use std::collections::HashMap;

use macroquad::{
    prelude::*,
    ui::{Skin, Ui, hash, root_ui, widgets::Window},
};
use serde::{Deserialize, Serialize};

use crate::{
    font::FontSize, model::player::Player, screen::Screen, ui_scaling::window_width,
    util::refresh_page,
};

#[allow(dead_code)]
#[derive(Serialize)]
#[serde(tag = "type")]
enum HostClientMessages {
    ResetAllBuzers,
    ResetPlayerBuzzer { user_id: u64 },
    UpdateScore { user_id: u64, diff: i32 },
    EndGame,
}

#[derive(Deserialize)]
#[serde(tag = "type")]
enum HostServerMessages {
    Ack,
    UpdatePlayerStates { players: HashMap<String, Player> },
    ExitGame,
}

#[derive(Default)]
pub struct HostScreen {
    players: HashMap<String, Player>,
}

impl HostScreen {
    fn draw_user(&self, ctx: &mut crate::context::Context, user_id: &str, ui: &mut Ui, width: f32) {
        let player = &self.players[user_id];
        let size = Vec2::new(width, screen_height() * 0.05);

        let first_buzzed_in_player = self.get_first_buzzed_in_player();

        let is_first = if let Some(first_player) = first_buzzed_in_player {
            first_player == user_id
        } else {
            false
        };

        ui.group(hash!(user_id), size, |ui| {
            let player_txt = player.name.clone();
            let player_txt_size = FontSize::Medium.measure(&player_txt);

            let score_txt = format!("Score: {}", player.score);
            ui.label(Vec2::new(0.0, 0.0), &player_txt);
            ui.label(
                Vec2::new(0.0, player_txt_size.height + size.y * 0.025),
                &score_txt,
            );

            if is_first {
                ui.label(Vec2::new(size.x * 0.45, 0.0), "BUZZED IN");
            }

            if ui.button(Vec2::new(size.x * 0.70, 0.0), "+") {
                let msg = HostClientMessages::UpdateScore {
                    user_id: user_id.parse().unwrap(),
                    diff: 1,
                };
                ctx.send_msg(&msg);
            }
            if ui.button(Vec2::new(size.x * 0.80, 0.0), "-") {
                let msg = HostClientMessages::UpdateScore {
                    user_id: user_id.parse().unwrap(),
                    diff: -1,
                };
                ctx.send_msg(&msg);
            }
            if ui.button(Vec2::new(size.x * 0.90, 0.0), "C") {
                let msg = HostClientMessages::ResetPlayerBuzzer {
                    user_id: user_id.parse().unwrap(),
                };
                ctx.send_msg(&msg);
            }
        });
    }

    fn menu_skin() -> Skin {
        let label_style = root_ui()
            .style_builder()
            .font_size(FontSize::Medium.size())
            .text_color(WHITE)
            .build();

        Skin {
            label_style,
            ..root_ui().default_skin()
        }
    }

    fn get_first_buzzed_in_player(&self) -> Option<String> {
        self.players
            .iter()
            .filter_map(|(id, player)| player.buzz_in_time.map(|buzz_in| (id, buzz_in)))
            .min_by(|(_, buzz_in), (_, other_buzz_in)| buzz_in.total_cmp(other_buzz_in))
            .map(|(id, _)| id)
            .cloned()
    }
}

impl Screen for HostScreen {
    fn handle_frame(&mut self, ctx: &mut crate::context::Context) {
        clear_background(BEIGE);

        let width = window_width();

        let menu_skin = &Self::menu_skin();
        root_ui().push_skin(menu_skin);

        let window_position =
            Vec2::new(screen_width() * 0.5 - (width * 0.5), screen_height() * 0.1);
        let window_size = Vec2::new(width, screen_height() * 0.70);

        Window::new(hash!("HostWindow"), window_position, window_size)
            .movable(false)
            .ui(&mut root_ui(), |ui| {
                let mut players: Vec<String> = self.players.keys().cloned().collect();
                players.sort();

                for user_id in &players {
                    self.draw_user(ctx, user_id, ui, width);
                }

                ui.group(
                    hash!("Host Control"),
                    Vec2::new(width, window_size.y * 0.25),
                    |ui| {
                        if ui.button(Vec2::new(width * 0.05, 0.0), "Clear All") {
                            let msg = HostClientMessages::ResetAllBuzers;
                            ctx.send_msg(&msg);
                        }

                        if ui.button(Vec2::new(width * 0.55, 0.0), "End Game") {
                            let msg = HostClientMessages::EndGame;
                            ctx.send_msg(&msg);
                        }
                    },
                );
            });

        root_ui().pop_skin();
    }

    fn handle_messages(
        &mut self,
        ctx: &mut crate::context::Context,
    ) -> Option<crate::StateTransition> {
        if let Some(msg) = ctx.recv_msg() {
            match msg {
                HostServerMessages::Ack => {
                    // pass
                }
                HostServerMessages::UpdatePlayerStates { players } => {
                    info!("Got new player state: {:?}", players);
                    self.players = players;
                }
                HostServerMessages::ExitGame => {
                    info!("Exiting Game");
                    refresh_page();
                }
            };
        }

        None
    }
}
