use cfg::Cfg;
use context::Context;
use font::FontSize;
use host_screen::HostScreen;
use login_screen::LoginScreen;
use macroquad::{
    prelude::*,
    ui::{Skin, root_ui},
};
use player_screen::PlayerScreen;
use screen::Screen;

use crate::util::get_ws_url;

mod cfg;
mod context;
mod font;
mod host_screen;
mod login_screen;
mod model;
mod player_screen;
mod screen;
mod ui_scaling;
mod util;

pub enum State {
    Init,
    Login(LoginScreen),
    PlayerScreen(PlayerScreen),
    HostScreen(HostScreen),
}

impl State {
    pub fn transition_state(&self, transition: StateTransition) -> Self {
        info!("Applying transition: {:?}", transition);
        match transition {
            StateTransition::Init | StateTransition::LeaveGame => {
                Self::Login(LoginScreen::default())
            }
            StateTransition::JoinAsPlayer => Self::PlayerScreen(PlayerScreen::default()),
            StateTransition::JoinAsHost => Self::HostScreen(HostScreen::default()),
        }
    }

    pub fn handle_frame(&mut self, ctx: &mut Context) {
        match self {
            Self::Init => {}
            Self::Login(login_screen) => login_screen.handle_frame(ctx),
            Self::PlayerScreen(player_screen) => player_screen.handle_frame(ctx),
            State::HostScreen(host_screen) => host_screen.handle_frame(ctx),
        }
    }

    pub fn handle_messages(&mut self, ctx: &mut Context) -> Option<StateTransition> {
        match self {
            Self::Init => Some(StateTransition::Init),
            State::Login(login_screen) => login_screen.handle_messages(ctx),
            State::PlayerScreen(player_screen) => player_screen.handle_messages(ctx),
            State::HostScreen(host_screen) => host_screen.handle_messages(ctx),
        }
    }
}

#[derive(Debug)]
pub enum StateTransition {
    Init,
    JoinAsPlayer,
    JoinAsHost,
    LeaveGame,
}

pub fn default_skin() -> Skin {
    let label_style = root_ui()
        .style_builder()
        .font_size(FontSize::Large.size())
        .text_color(WHITE)
        .build();
    let editbox_style = root_ui()
        .style_builder()
        .font_size(FontSize::Large.size())
        .color(BROWN)
        .color_selected(BROWN)
        .color_clicked(BROWN)
        .text_color(WHITE)
        .build();
    let window_style = root_ui().style_builder().color(DARKBROWN).build();
    let button_style = root_ui()
        .style_builder()
        .font_size(FontSize::Large.size())
        .color(GOLD)
        .text_color(BLACK)
        .color_hovered(YELLOW)
        .build();

    Skin {
        label_style,
        editbox_style,
        button_style,
        window_style,
        ..root_ui().default_skin()
    }
}

#[macroquad::main("Play of the Game")]
async fn main() {
    let cfg = Cfg::load_from_cookies().unwrap();

    let mut context = Context::new(&get_ws_url(), cfg);

    let mut state = State::Init;
    state.transition_state(StateTransition::Init);

    loop {
        let skin = default_skin();
        root_ui().push_skin(&skin);

        if let Some(transition) = state.handle_messages(&mut context) {
            state = state.transition_state(transition);
        }

        state.handle_frame(&mut context);

        root_ui().pop_skin();
        next_frame().await
    }
}
