use bevy::ecs::error::Result;
use bevy::input::keyboard::{Key, KeyboardInput};
use bevy::prelude::*;

use crate::consts::{BACKGROUND_COLOR, GAME_AREA, TITLE, TITLE_COLOR, Y_OFFSET};
use crate::gameplay::{Board, Cell, CellSize, CurrentCell, Gameplay};
use crate::resources::{AppState, Chronometer, MonospaceFont, Mute, TitleFont, SFX};

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, Component)]
pub struct GameOver;

impl GameOver {

    pub fn load(
        mut commands: Commands,
        board_query: Query<&Board>,
        remove_query: Query<Entity, With<Gameplay>>,
        chronometer: Res<Chronometer>,
        title_font: Res<TitleFont>,
        monospace_font: Res<MonospaceFont>,
        cell_size: Res<CellSize>,
        sfx: Res<SFX>,
        mute: Res<Mute>,
    ) -> Result<()> {
        let board = board_query.single()?.clone();
        let cell_size = *cell_size.clone();
        let seconds = chronometer.as_secs();
        for id in &remove_query {
            commands.entity(id).despawn();
        }
        commands.remove_resource::<CellSize>();
        commands.remove_resource::<CurrentCell>();

        commands.spawn((
            Self,
            Text::new(TITLE),
            TextFont {
                font: title_font.clone_weak(),
                font_size: 48.0,
                ..default()
            },
            TextShadow::default(),
            TextColor(TITLE_COLOR),
            TextLayout::new_with_justify(JustifyText::Center),
            Node {
                position_type: PositionType::Absolute,
                top: Val::ZERO,
                width: Val::Percent(100.0),
                ..default()
            },
        ));

        let minutes = seconds / 60;
        let seconds = seconds % 60;
        commands.spawn((
            Self,
            Text::new(format!("{:02}:{:02}", minutes, seconds)),
            TextColor(TITLE_COLOR),
            TextFont {
                font: monospace_font.clone_weak(),
                font_size: 32.0,
                ..default()
            },
            Node {
                position_type: PositionType::Absolute,
                top: Val::Px(4.0),
                right: Val:: Px(4.0),
                ..default()
            },
        ));

        let (width, height) = board.size.clone();
        for iy in 0..height {
            for ix in 0..width {
                let cell = match board.get(ix, iy) {
                    Cell::Yes |
                    Cell::LockedYes => Cell::Yes,
                    _ => Cell::No,
                };
                let color = match cell {
                    Cell::Yes |
                    Cell::LockedYes => cell.into(),
                    _ => BACKGROUND_COLOR,
                };

                commands
                    .spawn((
                        Self,
                        BackgroundColor(color),
                        Node {
                            position_type: PositionType::Absolute,
                            top: Val::Px(Y_OFFSET + cell_size.y * iy as f32),
                            left: Val::Px(cell_size.x * ix as f32),
                            width: Val::Px(cell_size.x),
                            height: Val::Px(cell_size.y),
                            ..default()
                        }
                    ))
                ;
                commands
                    .spawn((
                        Self,
                        BackgroundColor(color),
                        Node {
                            position_type: PositionType::Absolute,
                            bottom: Val::Px(GAME_AREA.y / 2.0 - 4.0 * iy as f32),
                            right: Val::Px(GAME_AREA.x / 4.0 - 4.0 * ix as f32),
                            width: Val::Px(4.0),
                            height: Val::Px(4.0),
                            ..default()
                        }
                    ))
                ;
            }
        }

        if !mute.0 {
            commands.spawn((
                Self,
                AudioPlayer::new(sfx.clapping.clone_weak()),
                PlaybackSettings::DESPAWN,
            ));
        }

        Ok(())
    }

    pub fn key_events(
        mut keyboard: EventReader<KeyboardInput>,
        mut next_state: ResMut<NextState<AppState>>,
    ) {
        for (input, _) in keyboard.par_read() {
            if input.state.is_pressed() && !input.repeat {
                if input.logical_key == Key::Escape {
                    next_state.set(AppState::Title);
                    return;
                }
            }
        }
    }

    pub fn unload(
        mut commands: Commands,
        query: Query<Entity, With<Self>>,
    ) {
        for id in &query {
            commands.entity(id).despawn();
        }
    }
}
