use crate::utils::cxx_string_to_string;
use cxx::CxxString;
use serde::{Deserialize, Serialize};
use std::fmt::Display;
use std::path::Path;
use std::{fs, io};
use toml::Value;

#[cxx::bridge]
mod ffi {
    extern "Rust" {
        type Config;

        /// 载入配置文件
        fn load_or_create(path: &CxxString) -> Result<Box<Config>>;
        /// 保存配置文件
        fn save_config(cfg: &Box<Config>, path: &CxxString) -> Result<()>;

        /// 做不做每日任务
        fn is_daily_missions(cfg: &Box<Config>) -> bool;
        fn set_daily_missions(cfg: &mut Box<Config>, value: bool);

        /// 做不做群岛
        fn is_archipelago(cfg: &Box<Config>) -> bool;
        fn set_archipelago(cfg: &mut Box<Config>, value: bool);

        /// 做不做深渊
        fn is_spiral_abyss(cfg: &Box<Config>) -> bool;
        fn set_spiral_abyss(cfg: &mut Box<Config>, value: bool);

        /// 做不做妖气
        fn is_demonic_energy(cfg: &Box<Config>) -> bool;
        fn set_demonic_energy(cfg: &mut Box<Config>, value: bool);

        /// 森林
        fn is_forest(cfg: &Box<Config>) -> bool;
        fn set_forest(cfg: &mut Box<Config>, value: bool);

        /// 分解
        fn is_decompose(cfg: &Box<Config>) -> bool;
        fn set_decompose(cfg: &mut Box<Config>, value: bool);

        /// 倍攻
        fn is_attack_power(cfg: &Box<Config>) -> bool;
        fn set_attack_power(cfg: &mut Box<Config>, value: bool);

        /// 装备变换
        fn is_equip_transform(cfg: &Box<Config>) -> bool;
        fn set_equip_transform(cfg: &mut Box<Config>, value: bool);

        /// 从配置文件中读取一个配置项
        fn get_config_value(
            path: &CxxString,
            path_name: &CxxString,
            key: &CxxString,
            default_value: &CxxString,
        ) -> String;

        /// 设置配置文件中的一个配置项
        fn set_config_value(
            path: &CxxString,
            path_name: &CxxString,
            key: &CxxString,
            value: &CxxString,
        ) -> bool;
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(default)]
pub struct Config {
    /// 做不做每日任务
    is_daily_missions: u8,
    /// 做不做群岛
    is_archipelago: u8,
    /// 做不做深渊
    is_spiral_abyss: u8,
    /// 做不做妖气
    is_demonic_energy: u8,
    /// 森林
    is_forest: u8,
    /// 分解
    is_decompose: u8,
    /// 倍攻
    is_attack_power: u8,
    /// 装备变换
    is_equip_transform: u8,
}

impl Default for Config {
    fn default() -> Self {
        Self {
            is_daily_missions: 1,
            is_archipelago: 1,
            is_spiral_abyss: 1,
            is_demonic_energy: 1,
            is_forest: 0,
            is_decompose: 1,
            is_attack_power: 0,
            is_equip_transform: 1,
        }
    }
}

impl Config {
    /// 生成带“文档注释”的 toml 文本（toml/serde 不会自动输出 Rust 的 /// 注释，所以这里手动拼）
    pub fn to_toml_with_comments(&self) -> String {
        // 你也可以加一个总注释、版本号等
        format!(
            r#"# 自动生成的配置文件

# 做不做每日任务
is_daily_missions = {is_daily_missions}

# 做不做群岛
is_archipelago = {is_archipelago}

# 做不做深渊
is_spiral_abyss = {is_spiral_abyss}

# 做不做妖气
is_demonic_energy = {is_demonic_energy}

# 森林
is_forest = {is_forest}

# 分解
is_decompose = {is_decompose}

# 倍攻
is_attack_power = {is_attack_power}

# 装备变换
is_equip_transform = {is_equip_transform}
"#,
            is_daily_missions = self.is_daily_missions,
            is_archipelago = self.is_archipelago,
            is_spiral_abyss = self.is_spiral_abyss,
            is_demonic_energy = self.is_demonic_energy,
            is_forest = self.is_forest,
            is_decompose = self.is_decompose,
            is_attack_power = self.is_attack_power,
            is_equip_transform = self.is_equip_transform,
        )
    }

    pub fn save_with_comments(&self, path: impl AsRef<Path>) -> io::Result<()> {
        let path = path.as_ref();
        if let Some(parent) = path.parent() {
            fs::create_dir_all(parent)?;
        }
        fs::write(path, self.to_toml_with_comments())?;
        Ok(())
    }

    /// 读取配置：不存在则创建（写入默认值+注释），存在则从文件构造实例。
    ///
    /// - toml 缺字段：会自动用 Default 补齐（因为 #[serde(default)]）
    /// - 可选：如果你想“读取后把缺的字段补齐回写”，这里也做了回写
    pub fn load_or_create(path: impl AsRef<Path>) -> Result<Self, Box<dyn std::error::Error>> {
        let path = path.as_ref();

        if !path.exists() {
            let cfg = Self::default();
            cfg.save_with_comments(path)?;
            return Ok(cfg);
        }

        let text = fs::read_to_string(path)?;
        let cfg: Self = toml::from_str(&text)?;

        // 可选：自动回写补全（比如用户旧版配置少字段时，补齐并带注释写回去）
        // 如果你不想覆盖用户文件，把下面两行删掉即可。
        cfg.save_with_comments(path)?;
        /*let cfg = Config {
            is_daily_missions: true,
            is_archipelago: true,
            is_spiral_abyss: false,
            is_demonic_energy: true,
            is_forest: true,
            is_decompose: true,
        };*/

        Ok(cfg)
    }
}

pub(crate) fn load_or_create(path: &CxxString) -> Result<Box<Config>, Box<dyn std::error::Error>> {
    let path = cxx_string_to_string(path);
    let config = Config::load_or_create(&path)?;
    Ok(Box::new(config))
}

pub(crate) fn save_config(
    this: &Box<Config>,
    path: &CxxString,
) -> Result<(), Box<dyn std::error::Error>> {
    let path = cxx_string_to_string(path);
    this.save_with_comments(path)?;
    Ok(())
}

pub(crate) fn is_daily_missions(this: &Box<Config>) -> bool {
    this.is_daily_missions != 0
}

pub(crate) fn set_daily_missions(this: &mut Box<Config>, flag: bool) {
    this.is_daily_missions = flag as u8;
}

pub(crate) fn is_archipelago(this: &Box<Config>) -> bool {
    this.is_archipelago != 0
}

pub(crate) fn set_archipelago(this: &mut Box<Config>, flag: bool) {
    this.is_archipelago = flag as u8;
}

pub(crate) fn is_spiral_abyss(this: &Box<Config>) -> bool {
    this.is_spiral_abyss != 0
}

pub(crate) fn set_spiral_abyss(this: &mut Box<Config>, flag: bool) {
    this.is_spiral_abyss = flag as u8;
}

pub(crate) fn is_demonic_energy(this: &Box<Config>) -> bool {
    this.is_demonic_energy != 0
}

pub(crate) fn set_demonic_energy(this: &mut Box<Config>, flag: bool) {
    this.is_demonic_energy = flag as u8;
}

pub(crate) fn is_forest(this: &Box<Config>) -> bool {
    this.is_forest != 0
}

pub(crate) fn set_forest(this: &mut Box<Config>, flag: bool) {
    this.is_forest = flag as u8;
}

pub(crate) fn is_decompose(this: &Box<Config>) -> bool {
    this.is_decompose != 0
}

pub(crate) fn set_decompose(this: &mut Box<Config>, flag: bool) {
    this.is_decompose = flag as u8;
}

fn is_attack_power(cfg: &Box<Config>) -> bool {
    cfg.is_attack_power != 0
}
fn set_attack_power(cfg: &mut Box<Config>, value: bool) {
    cfg.is_attack_power = value as u8;
}

fn is_equip_transform(cfg: &Box<Config>) -> bool {
    cfg.is_equip_transform != 0
}
fn set_equip_transform(cfg: &mut Box<Config>, value: bool) {
    cfg.is_equip_transform = value as u8;
}

pub(crate) fn set_config_value(
    path: &CxxString,
    path_name: &CxxString,
    key: &CxxString,
    value: &CxxString,
) -> bool {
    let path_str = cxx_string_to_string(path);
    let path_name_str = cxx_string_to_string(path_name);
    let key_str = cxx_string_to_string(key);
    let value_str = cxx_string_to_string(value);

    // 创建父目录（如果不存在）
    let path = Path::new(&path_str);
    if let Some(parent) = path.parent() {
        if let Err(_) = fs::create_dir_all(parent) {
            return false;
        }
    }

    // 读取现有内容或创建新的 TOML 值
    let mut value: Value = if path.exists() {
        match fs::read_to_string(&path_str) {
            Ok(content) => {
                toml::from_str(&content).unwrap_or_else(|_| Value::Table(toml::map::Map::new()))
            }
            Err(_) => Value::Table(toml::map::Map::new()),
        }
    } else {
        Value::Table(toml::map::Map::new())
    };

    // 确保根值是一个表
    let root_table = match value.as_table_mut() {
        Some(t) => t,
        None => return false,
    };

    // 获取或创建 path_name 对应的表
    let path_table = root_table
        .entry(&path_name_str)
        .or_insert(Value::Table(toml::map::Map::new()))
        .as_table_mut();

    let path_table = match path_table {
        Some(t) => t,
        None => return false,
    };

    // 设置键值对
    path_table.insert(key_str, Value::String(value_str));

    // 序列化并写入文件
    let toml_string = match toml::to_string_pretty(&value) {
        Ok(s) => s,
        Err(_) => return false,
    };

    match fs::write(&path_str, toml_string) {
        Ok(_) => true,
        Err(_) => false,
    }
}

/// 从配置文件中读取一个配置项
pub(crate) fn get_config_value(
    path: &CxxString,
    path_name: &CxxString,
    key: &CxxString,
    default_value: &CxxString,
) -> String {
    let path_str = cxx_string_to_string(path);
    let path_name_str = cxx_string_to_string(path_name);
    let key_str = cxx_string_to_string(key);
    let default_str = cxx_string_to_string(default_value);

    // 读取文件内容
    let content = match fs::read_to_string(&path_str) {
        Ok(c) => c,
        Err(_) => return default_str,
    };

    // 解析 TOML
    let value: Value = match toml::from_str(&content) {
        Ok(v) => v,
        Err(_) => return default_str,
    };

    // 导航到 path_name 下的 table
    let table = match value.get(&path_name_str) {
        Some(Value::Table(t)) => t,
        _ => return default_str,
    };

    // 获取 key 对应的值
    let result = match table.get(&key_str) {
        Some(v) => match v.as_str() {
            Some(s) => s.to_string(),
            None => v.to_string(),
        },
        None => return default_str,
    };

    result
}
