use crate::common::Rect;
use crate::entity::GameEntity;
use crate::framework::context::Context;
use crate::framework::error::GameResult;
use crate::game::frame::Frame;
use crate::game::shared_game_state::SharedGameState;
use crate::input::touch_controls::TouchControlType;
use crate::game::player::Player;
use crate::game::scripting::tsc::text_script::ScriptMode;

pub struct StageSelect {
    pub current_teleport_slot: u8,
    prev_teleport_slot: u8,
    stage_select_text_y_pos: usize,
    tick: usize,
}

impl StageSelect {
    pub fn new() -> StageSelect {
        StageSelect {
            current_teleport_slot: 0,
            prev_teleport_slot: 0,
            stage_select_text_y_pos: 54,
            tick: 0,
        }
    }

    pub fn reset(&mut self) {
        self.stage_select_text_y_pos = 54;
        self.tick = 0;
    }
}

impl GameEntity<(&mut Context, &Player, &Player)> for StageSelect {
    fn tick(&mut self, state: &mut SharedGameState, (ctx, player1, player2): (&mut Context, &Player, &Player)) -> GameResult {
        state.touch_controls.control_type = TouchControlType::None;

        let slot_count = state.teleporter_slots.iter()
            .filter(|&&(index, _event_num)| index != 0)
            .count();

        if slot_count <= self.current_teleport_slot as usize {
            self.current_teleport_slot = 0;
        }

        if self.stage_select_text_y_pos > 46 {
            self.stage_select_text_y_pos -= 1;
        }

        let left_pressed = player1.controller.trigger_left() || player2.controller.trigger_left();
        let right_pressed = player1.controller.trigger_right() || player2.controller.trigger_right();
        let mut ok_pressed = player1.controller.trigger_jump() || player1.controller.trigger_menu_ok()
            || player2.controller.trigger_jump() || player2.controller.trigger_menu_ok();
        let mut cancel_pressed = player1.controller.trigger_shoot() || player2.controller.trigger_shoot();

        if left_pressed {
            if self.current_teleport_slot == 0 {
                self.current_teleport_slot = slot_count.saturating_sub(1) as u8;
            } else {
                self.current_teleport_slot -= 1;
            }
        } else if right_pressed {
            if self.current_teleport_slot == slot_count.saturating_sub(1) as u8 {
                self.current_teleport_slot = 0;
            } else {
                self.current_teleport_slot += 1;
            }
        }

        if self.prev_teleport_slot != self.current_teleport_slot {
            self.prev_teleport_slot = self.current_teleport_slot;
            state.sound_manager.play_sfx(1);
            if let Some(&(index, _event_num)) = state.teleporter_slots.get(self.current_teleport_slot as usize) {
                state.textscript_vm.start_script(1000 + index);
            } else {
                state.textscript_vm.start_script(1000);
            }
        }

        if state.settings.touch_controls {
            let slot_offset = ((state.canvas_size.0 - 40.0 * slot_count as f32) / 2.0).floor();
            let mut slot_rect;

            for i in 0..slot_count {
                slot_rect = Rect::new_size(slot_offset as isize + i as isize * 40 - 2, 64 - 8, 36, 32);

                if state.touch_controls.consume_click_in(slot_rect) {
                    if self.current_teleport_slot as usize == i {
                        ok_pressed = true;
                    } else {
                        state.sound_manager.play_sfx(1);
                        self.current_teleport_slot = i as u8;
                    }

                    break;
                }
            }

            let (_, off_top, off_right, _) = crate::framework::graphics::screen_insets_scaled(ctx, state.scale);
            slot_rect = Rect::new_size(state.canvas_size.0 as isize - 34 - off_right as isize, 8 + off_top as isize, 26, 26);

            if state.touch_controls.consume_click_in(slot_rect) {
                state.sound_manager.play_sfx(5);
                cancel_pressed = true;
            }
        }

        if ok_pressed || cancel_pressed {
            self.reset();
            state.textscript_vm.set_mode(ScriptMode::Map);
            state.control_flags.set_tick_world(true);
            state.control_flags.set_control_enabled(true);
            state.control_flags.set_interactions_disabled(false);

            if ok_pressed {
                if let Some(&(_index, event_num)) = state.teleporter_slots.get(self.current_teleport_slot as usize) {
                    state.textscript_vm.start_script(event_num);
                }
            }
        }

        self.tick += 1;

        Ok(())
    }

    fn draw(&self, state: &mut SharedGameState, ctx: &mut Context, _frame: &Frame) -> GameResult {
        let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "StageImage")?;

        let slot_count = state.teleporter_slots.iter()
            .filter(|&&(index, _event_num)| index != 0)
            .count();
        let slot_offset = ((state.canvas_size.0 - 40.0 * slot_count as f32) / 2.0).floor();
        let mut slot_rect = Rect::new(0, 0, 0, 0);

        for i in 0..slot_count {
            let index = state.teleporter_slots[i].0;

            slot_rect.left = 32 * (index as u16 % 8);
            slot_rect.top = 16 * (index as u16 / 8);
            slot_rect.right = slot_rect.left + 32;
            slot_rect.bottom = slot_rect.top + 16;

            batch.add_rect(slot_offset + i as f32 * 40.0, 64.0, &slot_rect);
        }

        batch.draw(ctx)?;

        let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "TextBox")?;

        batch.add_rect((state.canvas_size.0 / 2.0) - 32.0, self.stage_select_text_y_pos as f32, &state.constants.textscript.stage_select_text);
        if slot_count > 0 {
            batch.add_rect(slot_offset + self.current_teleport_slot as f32 * 40.0, 64.0, &state.constants.textscript.cursor[self.tick / 2 % 2]);
        }

        batch.draw(ctx)?;

        if state.settings.touch_controls {
            let (_, off_top, off_right, _) = crate::framework::graphics::screen_insets_scaled(ctx, state.scale);

            let close_rect = Rect { left: 110, top: 110, right: 128, bottom: 128 };
            let batch = state.texture_set.get_or_load_batch(ctx, &state.constants, "builtin/touch")?;

            batch.add_rect(state.canvas_size.0 - off_right - 30.0, 12.0 + off_top, &close_rect);
            batch.draw(ctx)?;
        }

        Ok(())
    }
}
