use crate::common::Direction;
use crate::framework::error::GameResult;
use crate::game::npc::NPC;
use crate::game::shared_game_state::SharedGameState;
use crate::game::stage::{BackgroundType, Stage};
use crate::util::rng::RNG;

impl NPC {
    pub(crate) fn tick_n001_experience(&mut self, state: &mut SharedGameState, stage: &mut Stage) -> GameResult {
        if stage.data.background_type == BackgroundType::Scrolling || stage.data.background_type == BackgroundType::OutsideWind {
            if self.action_num == 0 {
                self.action_num = 1;

                self.vel_x = self.rng.range(-0x80..0x80) as i32;
                self.vel_y = self.rng.range(-0x7f..0x100) as i32;
            }

            self.vel_x -= 0x8;

            if self.x < 0xa000 {
                self.cond.set_alive(false);
                return Ok(());
            }

            if self.vel_x < -0x600 {
                self.vel_x = -0x600;
            }

            if self.flags.hit_left_wall() {
                self.vel_x = 0x100;
            }

            if self.flags.hit_top_wall() {
                self.vel_y = 0x40;
            }

            if self.flags.hit_bottom_wall() {
                self.vel_y = -0x40;
            }
        } else {
            if self.action_num == 0 {
                self.action_num = 1;
                self.anim_num = self.rng.range(0..4) as u16;

                self.vel_x = self.rng.range(-0x200..0x200) as i32;
                self.vel_y = self.rng.range(-0x400..0) as i32;

                self.direction = if self.rng.range(0..1) != 0 { Direction::Left } else { Direction::Right };
            }

            self.vel_y += if self.flags.in_water() { 0x15 } else { 0x2a };

            if self.flags.hit_left_wall() && self.vel_x < 0 {
                self.vel_x = -self.vel_x;
            }

            if self.flags.hit_right_wall() && self.vel_x > 0 {
                self.vel_x = -self.vel_x;
            }

            if self.flags.hit_top_wall() && self.vel_y < 0 {
                self.vel_y = -self.vel_y;
            }

            if self.flags.hit_bottom_wall() {
                state.sound_manager.play_sfx(45);

                self.vel_y = -0x280;
                self.vel_x = 2 * self.vel_x / 3;
            }

            if self.flags.hit_left_wall() || self.flags.hit_right_wall() || self.flags.hit_bottom_wall() {
                state.sound_manager.play_sfx(45);
                self.action_counter2 += 1;

                if self.action_counter2 > 2 {
                    self.vel_y -= 0x200;
                }
            } else {
                self.action_counter2 = 0;
            }

            self.vel_x = self.vel_x.clamp(-0x5ff, 0x5ff);
            self.vel_y = self.vel_y.clamp(-0x5ff, 0x5ff);
        }

        self.x += self.vel_x;
        self.y += self.vel_y;

        self.anim_counter += 1;

        if self.direction == Direction::Left {
            if self.anim_counter > 2 {
                self.anim_counter = 0;

                self.anim_num += 1;
                if self.anim_num > 5 {
                    self.anim_num = 0;
                }
            }
        } else if self.anim_counter > 2 {
            self.anim_counter = 0;

            if self.anim_num > 0 {
                self.anim_num -= 1;
            } else {
                self.anim_num = 5;
            }
        }

        self.anim_rect = state.constants.npc.n001_experience[self.anim_num as usize];

        if self.action_num != 0 {
            if self.exp >= 20 {
                self.anim_rect.top += 32;
                self.anim_rect.bottom += 32;
            } else if self.exp >= 5 {
                self.anim_rect.top += 16;
                self.anim_rect.bottom += 16;
            }

            self.action_num = 1;
        }

        self.action_counter += 1;
        if self.action_counter > 500 && self.anim_num == 5 && self.anim_counter == 2 {
            self.cond.set_alive(false);
            return Ok(());
        }

        if self.action_counter > 400 && (self.action_counter & 0x02) != 0 {
            self.anim_rect.left = 0;
            self.anim_rect.top = 0;
            self.anim_rect.right = 0;
            self.anim_rect.bottom = 0;
        }

        Ok(())
    }

    pub(crate) fn tick_n086_missile_pickup(&mut self, state: &mut SharedGameState, stage: &mut Stage) -> GameResult {
        if self.direction == Direction::Left {
            self.anim_counter += 1;
            if self.anim_counter > 2 {
                self.anim_counter = 0;
                self.anim_num += 1;
                if self.anim_num > 1 {
                    self.anim_num = 0;
                }
            }

            self.action_counter2 += 1;
        }

        if stage.data.background_type == BackgroundType::Scrolling || stage.data.background_type == BackgroundType::OutsideWind {
            if self.action_num == 0 {
                self.action_num = 1;
                self.vel_x = self.rng.range(0x7f..0x100) as i32;
                self.vel_y = self.rng.range(-0x20..0x20) as i32;
            }

            self.vel_x -= 0x08;
            if self.x < 0xa000 {
                self.cond.set_alive(false)
            }

            if self.flags.hit_left_wall() {
                self.vel_x = 0x100;
            }

            if self.flags.hit_top_wall() {
                self.vel_y = 0x40;
            }

            if self.flags.hit_bottom_wall() {
                self.vel_y = -0x40;
            }

            self.x += self.vel_x;
            self.y += self.vel_y;
        }

        match self.exp {
            1 => {
                self.anim_rect = state.constants.npc.n086_missile_pickup[self.anim_num as usize];
            }
            3 => {
                self.anim_rect = state.constants.npc.n086_missile_pickup[2 + self.anim_num as usize];
            }
            _ => (),
        }

        if self.action_counter2 > 550 {
            self.cond.set_alive(false);
        }

        if self.action_counter2 > 500 && self.action_counter2 & 0x02 != 0 {
            self.anim_rect.right = self.anim_rect.left;
            self.anim_rect.bottom = self.anim_rect.top;
        }

        if self.action_counter2 > 547 {
            self.anim_rect = state.constants.npc.n086_missile_pickup[4];
        }

        Ok(())
    }

    pub(crate) fn tick_n087_heart_pickup(&mut self, state: &mut SharedGameState, stage: &mut Stage) -> GameResult {
        if self.direction == Direction::Left {
            self.anim_counter += 1;
            if self.anim_counter > 2 {
                self.anim_counter = 0;
                self.anim_num += 1;
                if self.anim_num > 1 {
                    self.anim_num = 0;
                }
            }

            self.action_counter2 += 1;
        }

        if stage.data.background_type == BackgroundType::Scrolling || stage.data.background_type == BackgroundType::OutsideWind {
            if self.action_num == 0 {
                self.action_num = 1;
                self.vel_x = self.rng.range(0x7f..0x100) as i32;
                self.vel_y = self.rng.range(-0x20..0x20) as i32;
            }

            self.vel_x -= 0x08;
            if self.x < 0xa000 {
                self.cond.set_alive(false)
            }

            if self.flags.hit_left_wall() {
                self.vel_x = 0x100;
            }

            if self.flags.hit_top_wall() {
                self.vel_y = 0x40;
            }

            if self.flags.hit_bottom_wall() {
                self.vel_y = -0x40;
            }

            self.x += self.vel_x;
            self.y += self.vel_y;
        }

        match self.exp {
            2 => {
                self.anim_rect = state.constants.npc.n087_heart_pickup[self.anim_num as usize];
            }
            6 => {
                self.anim_rect = state.constants.npc.n087_heart_pickup[2 + self.anim_num as usize];
            }
            _ => (),
        }

        if self.action_counter2 > 550 {
            self.cond.set_alive(false);
        }

        if self.action_counter2 > 500 && self.action_counter2 & 0x02 != 0 {
            self.anim_rect.right = self.anim_rect.left;
            self.anim_rect.bottom = self.anim_rect.top;
        }

        if self.action_counter2 > 547 {
            self.anim_rect = state.constants.npc.n087_heart_pickup[4];
        }

        Ok(())
    }
}
