use js_sys;
use wasm_bindgen::prelude::*;

// 瓶子状态枚举
#[wasm_bindgen]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BottleState {
    Empty,
    Some,
    Full,
    Close,
}

// 游戏状态枚举
#[wasm_bindgen]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum GameState {
    GameInit,
    GamePlay,
    GameWin,
    GameLost,
    GameOver,
    GamePause,
}

// 游戏事件枚举
#[wasm_bindgen]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DaoShuiGameEvent {
    GameWin,
    GameLost,
    GameOver,
    Move,
}

// 瓶子结构体
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub struct Bottle {
    bodys: Vec<u32>,
    index: u32,
    state: BottleState,
}

#[wasm_bindgen]
impl Bottle {
    #[wasm_bindgen(constructor)]
    pub fn new(index: u32) -> Bottle {
        Bottle {
            bodys: Vec::new(),
            index,
            state: BottleState::Empty,
        }
    }

    pub fn get_bodys(&self) -> Vec<u32> {
        self.bodys.clone()
    }

    pub fn set_bodys(&mut self, bodys: Vec<u32>) {
        self.bodys = bodys;
    }

    pub fn get_index(&self) -> u32 {
        self.index
    }

    pub fn set_state(&mut self, state: BottleState) {
        self.state = state;
    }

    pub fn get_state(&self) -> BottleState {
        self.state
    }
}

// 游戏事件项结构体
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub struct GameEventItem {
    #[allow(dead_code)]
    game_time: f64,
    #[allow(dead_code)]
    from_indexs: Vec<u32>,
    #[allow(dead_code)]
    to_indexs: Vec<u32>,
    #[allow(dead_code)]
    game_event: DaoShuiGameEvent,
    #[allow(dead_code)]
    event_values: Vec<u32>,
    #[allow(dead_code)]
    duration: f64,
}

#[wasm_bindgen]
impl GameEventItem {
    #[wasm_bindgen(constructor)]
    pub fn new(
        game_time: f64,
        from_indexs: Vec<u32>,
        to_indexs: Vec<u32>,
        game_event: DaoShuiGameEvent,
        event_values: Vec<u32>,
        duration: f64,
    ) -> GameEventItem {
        GameEventItem {
            game_time,
            from_indexs,
            to_indexs,
            game_event,
            event_values,
            duration,
        }
    }
}

// 倒水游戏盒子结构体
#[wasm_bindgen]
pub struct DaoShuiGameBox {
    bottles: Vec<Bottle>,
    cur_index: i32,
    target_index: i32,
    max_body_length: u32,
    max_round: u32,
    cur_round: u32,
    max_more_round: u32,
    cur_more_round: u32,
    game_time: f64,
    game_state: GameState,
    lost_count: u32,
    tmp_pre_cur_bottle_state: BottleState,
    tmp_pre_target_bottle_state: BottleState,
    tests: Vec<u32>,
}

#[wasm_bindgen]
impl DaoShuiGameBox {
    // 创建一个新的游戏盒子实例（无参构造函数）
    #[wasm_bindgen(constructor)]
    pub fn new() -> DaoShuiGameBox {
        DaoShuiGameBox {
            bottles: Vec::new(),
            cur_index: -1,
            target_index: -1,
            max_body_length: 0,
            max_round: 0,
            cur_round: 0,
            max_more_round: 0,
            cur_more_round: 0,
            game_time: 0.0,
            game_state: GameState::GameInit,
            lost_count: 0,
            tmp_pre_cur_bottle_state: BottleState::Empty,
            tmp_pre_target_bottle_state: BottleState::Empty,
            tests: Vec::new(),
        }
    }

    // 设置游戏配置数据
    pub fn set_config_data(&mut self, data: JsValue) {
        // 解析瓶子数组
        if let Some(bottles_value) =
            js_sys::Reflect::get(&data, &JsValue::from_str("bottles_bodys")).ok()
        {
            self.bottles = Vec::new();
            let bottles_array = js_sys::Array::from(&bottles_value);
            for i in 0..bottles_array.length() {
                let bottle_bodys = bottles_array.get(i);
                if !bottle_bodys.is_undefined() && !bottle_bodys.is_null() {
                    let mut bottle = Bottle::new(i as u32);

                    // 解析 bodys 数组

                    let mut bodys = Vec::new();
                    let bodys_array = js_sys::Array::from(&bottle_bodys);
                    for j in 0..bodys_array.length() {
                        let body_value = bodys_array.get(j);
                        if !body_value.is_undefined() && !body_value.is_null() {
                            if let Some(body) = body_value.as_f64() {
                                bodys.push(body as u32);
                            }
                        }
                    }
                    bottle.set_bodys(bodys.clone());

                    // 根据 bodys 数组长度设置瓶子状态
                    let state_enum = if bodys.is_empty() {
                        BottleState::Empty
                    } else if bodys.len() >= 3 {
                        BottleState::Full
                    } else {
                        BottleState::Some
                    };
                    bottle.set_state(state_enum);

                    self.bottles.push(bottle);
                }
            }
        }

        // 解析其他配置数据
        if let Some(max_body_length_value) =
            js_sys::Reflect::get(&data, &JsValue::from_str("max_body_length")).ok()
        {
            if let Some(max_body_length) = max_body_length_value.as_f64() {
                self.max_body_length = max_body_length as u32;
            }
        }

        if let Some(max_round_value) =
            js_sys::Reflect::get(&data, &JsValue::from_str("max_round")).ok()
        {
            if let Some(max_round) = max_round_value.as_f64() {
                self.max_round = max_round as u32;
            }
        }

        if let Some(max_more_round_value) =
            js_sys::Reflect::get(&data, &JsValue::from_str("max_more_round")).ok()
        {
            if let Some(max_more_round) = max_more_round_value.as_f64() {
                self.max_more_round = max_more_round as u32;
            }
        }

        // 解析其他属性
        if let Some(cur_index) = js_sys::Reflect::get(&data, &JsValue::from_str("curIndex")).ok() {
            if let Some(index) = cur_index.as_f64() {
                self.cur_index = index as i32;
            }
        }

        if let Some(target_index) =
            js_sys::Reflect::get(&data, &JsValue::from_str("targetIndex")).ok()
        {
            if let Some(index) = target_index.as_f64() {
                self.target_index = index as i32;
            }
        }

        if let Some(max_body_length) =
            js_sys::Reflect::get(&data, &JsValue::from_str("maxBodyLength")).ok()
        {
            if let Some(length) = max_body_length.as_f64() {
                self.max_body_length = length as u32;
            }
        }

        if let Some(max_round) = js_sys::Reflect::get(&data, &JsValue::from_str("maxRound")).ok() {
            if let Some(round) = max_round.as_f64() {
                self.max_round = round as u32;
            }
        }

        if let Some(cur_round) = js_sys::Reflect::get(&data, &JsValue::from_str("curRound")).ok() {
            if let Some(round) = cur_round.as_f64() {
                self.cur_round = round as u32;
            }
        }

        if let Some(max_more_round) =
            js_sys::Reflect::get(&data, &JsValue::from_str("maxMoreRound")).ok()
        {
            if let Some(round) = max_more_round.as_f64() {
                self.max_more_round = round as u32;
            }
        }

        if let Some(cur_more_round) =
            js_sys::Reflect::get(&data, &JsValue::from_str("curMoreRound")).ok()
        {
            if let Some(round) = cur_more_round.as_f64() {
                self.cur_more_round = round as u32;
            }
        }

        if let Some(game_time) = js_sys::Reflect::get(&data, &JsValue::from_str("gameTime")).ok() {
            if let Some(time) = game_time.as_f64() {
                self.game_time = time;
            }
        }

        if let Some(game_state) = js_sys::Reflect::get(&data, &JsValue::from_str("gameState")).ok()
        {
            if let Some(state) = game_state.as_f64() {
                let state_enum = match state as u32 {
                    0 => GameState::GameInit,
                    1 => GameState::GamePlay,
                    2 => GameState::GameWin,
                    3 => GameState::GameLost,
                    4 => GameState::GameOver,
                    5 => GameState::GamePause,
                    _ => GameState::GameInit,
                };
                self.game_state = state_enum;
            }
        }

        if let Some(lost_count) = js_sys::Reflect::get(&data, &JsValue::from_str("lostCount")).ok()
        {
            if let Some(count) = lost_count.as_f64() {
                self.lost_count = count as u32;
            }
        }
    }

    // 获取所有瓶子
    pub fn get_bottles(&self) -> JsValue {
        // 将 Vec<Bottle> 转换为 JavaScript 数组
        let js_array = js_sys::Array::new();
        for bottle in &self.bottles {
            js_array.push(&JsValue::from(bottle.clone()));
        }
        js_array.into()
    }

    // 获取特定瓶子的信息
    pub fn get_bottle_info(&self, index: u32) -> JsValue {
        if index < self.bottles.len() as u32 {
            let bottle = &self.bottles[index as usize];
            let obj = js_sys::Object::new();

            // 设置 bodys
            let bodys_array = js_sys::Array::new();
            for &body in &bottle.get_bodys() {
                bodys_array.push(&JsValue::from(body));
            }
            js_sys::Reflect::set(&obj, &JsValue::from_str("bodys"), &bodys_array).unwrap();

            // 设置 index
            js_sys::Reflect::set(&obj, &JsValue::from_str("index"), &JsValue::from(index)).unwrap();

            // 设置 state
            js_sys::Reflect::set(
                &obj,
                &JsValue::from_str("state"),
                &JsValue::from(bottle.get_state() as u32),
            )
            .unwrap();

            obj.into()
        } else {
            JsValue::null()
        }
    }

    // 获取游戏时间
    pub fn get_game_time(&self) -> f64 {
        self.game_time
    }

    // 开始游戏
    pub fn play(&mut self) {
        self.game_state = GameState::GamePlay;
    }

    // 返回游戏
    pub fn backplay(&mut self) {
        self.game_state = GameState::GamePlay;
    }

    // 暂停游戏
    pub fn stop(&mut self) {
        self.game_state = GameState::GamePause;
    }

    // 获取游戏状态
    pub fn get_game_state(&self) -> GameState {
        self.game_state
    }

    // 更新游戏状态
    pub fn update(&mut self, dt: f64) {
        if self.game_state == GameState::GamePlay {
            self.game_time += dt;
        }
    }

    // 触摸瓶子
    pub fn touch_bottle(&mut self, index: u32) -> i32 {
        if self.cur_index == -1 {
            self._set_cur_bottle(index)
        } else if self.cur_index == index as i32 {
            self.cur_index = -1;
            -1
        } else {
            self._set_target_bottle(index)
        }
    }

    // 设置当前选中的瓶子
    fn _set_cur_bottle(&mut self, index: u32) -> i32 {
        if self.bottles[index as usize].get_state() == BottleState::Close {
            self.cur_index = -1; // 已经盖上盖子
        } else {
            if self.bottles[index as usize].get_state() == BottleState::Empty {
                self.cur_index = -1; // 空瓶子
            } else {
                self.cur_index = index as i32;
            }
        }
        self.cur_index
    }

    // 获取当前选中的瓶子
    pub fn get_cur_bottle(&self) -> Option<Bottle> {
        if self.cur_index == -1 {
            None
        } else {
            Some(self.bottles[self.cur_index as usize].clone())
        }
    }

    // 获取目标瓶子
    pub fn get_target_bottle(&self) -> Option<Bottle> {
        if self.target_index == -1 {
            None
        } else {
            Some(self.bottles[self.target_index as usize].clone())
        }
    }

    // 移动液体
    pub fn move_body(&mut self) -> Vec<u32> {
        if self.cur_index == -1 || self.target_index == -1 {
            return Vec::new();
        }

        let move_bodys = self.get_move_bodys(self.cur_index as u32, self.target_index as u32);

        let game_event_item = GameEventItem::new(
            self.get_game_time(),
            vec![self.cur_index as u32],
            vec![self.target_index as u32],
            DaoShuiGameEvent::Move,
            move_bodys.clone(),
            1000.0,
        );

        self.save_game_event(game_event_item);

        if let Some(cur_bottle) = self.get_cur_bottle() {
            self.tmp_pre_cur_bottle_state = cur_bottle.get_state();
        }

        if let Some(target_bottle) = self.get_target_bottle() {
            self.tmp_pre_target_bottle_state = target_bottle.get_state();
        }

        self.cur_index = -1;
        self.target_index = -1;

        move_bodys
    }

    // 检查游戏胜利或失败
    pub fn check_game_win_or_lost(&mut self) {
        if self.tmp_pre_cur_bottle_state == BottleState::Empty
            && self.tmp_pre_target_bottle_state == BottleState::Close
        {
            if !self.check_win() {
                self.check_lost();
            }
        } else {
            self.check_lost();
        }
        self.cur_round += 1;
    }

    // 游戏复活
    pub fn game_revive(&mut self) {
        self.game_state = GameState::GamePlay;
        self.cur_more_round = self.max_more_round; // 加了回合
    }

    // 检查游戏是否胜利
    fn check_win(&mut self) -> bool {
        // 所有瓶子要么空，要么close
        let mut is_win = true;
        for i in 0..self.bottles.len() {
            let bottle = &self.bottles[i];
            if bottle.get_state() != BottleState::Empty && bottle.get_state() != BottleState::Close
            {
                is_win = false;
                break;
            }
        }

        if is_win {
            self.game_state = GameState::GameWin;
        }

        is_win
    }

    // 检查游戏是否失败
    fn check_lost(&mut self) {
        if self.cur_round >= (self.max_round + self.cur_more_round) {
            if self.lost_count == 0 {
                self.lost_count += 1;
                self.game_state = GameState::GameLost;
            } else {
                self.game_state = GameState::GameOver;
            }
        }
    }

    // 设置目标瓶子
    fn _set_target_bottle(&mut self, index: u32) -> i32 {
        if self.bottles[index as usize].get_state() == BottleState::Full
            || self.bottles[index as usize].get_state() == BottleState::Close
        {
            self.target_index = -1;
        } else {
            self.target_index = index as i32;
        }
        self.target_index
    }

    // 获取要移动的液体
    fn get_move_bodys(&mut self, from_index: u32, to_index: u32) -> Vec<u32> {
        // 确保 from_index 和 to_index 是有效的
        let from_idx = from_index as usize;
        let to_idx = to_index as usize;

        // 使用 Vec::split_at_mut 来获取两个可变引用
        let (first, second) = if from_idx < to_idx {
            let (first, rest) = self.bottles.split_at_mut(to_idx);
            (&mut first[from_idx], &mut rest[0])
        } else {
            let (first, rest) = self.bottles.split_at_mut(from_idx);
            (&mut rest[0], &mut first[to_idx])
        };

        let from_bottle = first;
        let to_bottle = second;

        let mut move_bodys = Vec::new();
        let mut del_from_i = -1;
        let mut del_len = 0;

        let from_bodys = from_bottle.get_bodys();
        let mut to_bodys = to_bottle.get_bodys();

        for (i, &body) in from_bodys.iter().enumerate().rev() {
            if to_bodys.len() < self.max_body_length as usize {
                if move_bodys.is_empty() || move_bodys[move_bodys.len() - 1] == body {
                    move_bodys.push(body);
                    del_from_i = i as i32;
                    to_bodys.push(body);
                    del_len += 1;
                } else {
                    break;
                }
            } else {
                break;
            }
        }

        // 更新 from_bottle 的 bodys
        if del_from_i != -1 {
            let mut new_from_bodys = from_bodys.clone();
            new_from_bodys.drain(del_from_i as usize..del_from_i as usize + del_len);
            from_bottle.set_bodys(new_from_bodys);
        }

        // 更新 to_bottle 的 bodys
        to_bottle.set_bodys(to_bodys);

        // 更新瓶子状态
        if from_bottle.get_bodys().is_empty() {
            from_bottle.set_state(BottleState::Empty);
        } else {
            from_bottle.set_state(BottleState::Some);
        }

        if to_bottle.get_bodys().len() == self.max_body_length as usize {
            to_bottle.set_state(BottleState::Full);

            // 检查是否已经同色
            let unique_bodys: std::collections::HashSet<_> =
                to_bottle.get_bodys().iter().cloned().collect();
            if unique_bodys.len() == 1 {
                to_bottle.set_state(BottleState::Close);
            }
        } else {
            to_bottle.set_state(BottleState::Some);
        }

        move_bodys
    }

    // 保存游戏事件
    fn save_game_event(&mut self, _game_event_item: GameEventItem) {
        // 这里可以保存游戏事件，目前实现为空
    }

    // 获取tests数组
    pub fn get_tests(&self) -> Vec<u32> {
        self.tests.clone()
    }

    // 设置tests数组
    pub fn set_tests(&mut self, tests: Vec<u32>) {
        self.tests = tests;
    }
}
