use crate::{
    config::{Config, IVerge},
    core::{handle, hotkey, sysopt, tray, CoreManager},
    log_err,
    module::lightweight,
};
use anyhow::Result;
use serde_yaml::Mapping;

/// Patch Clash configuration
pub async fn patch_clash(patch: Mapping) -> Result<()> {
    Config::clash().draft().patch_config(patch.clone());

    let res = {
        // 激活订阅
        if patch.get("secret").is_some() || patch.get("external-controller").is_some() {
            Config::generate().await?;
            CoreManager::global().restart_core().await?;
        } else {
            if patch.get("mode").is_some() {
                log_err!(tray::Tray::global().update_menu());
                log_err!(tray::Tray::global().update_icon(None));
            }
            Config::runtime().latest().patch_config(patch);
            CoreManager::global().update_config().await?;
        }
        handle::Handle::refresh_clash();
        <Result<()>>::Ok(())
    };
    match res {
        Ok(()) => {
            Config::clash().apply();
            Config::clash().data().save_config()?;
            Ok(())
        }
        Err(err) => {
            Config::clash().discard();
            Err(err)
        }
    }
}

// Define update flags as bitflags for better performance
#[derive(Clone, Copy)]
enum UpdateFlags {
    None = 0,
    RestartCore = 1 << 0,
    ClashConfig = 1 << 1,
    VergeConfig = 1 << 2,
    Launch = 1 << 3,
    SysProxy = 1 << 4,
    SystrayIcon = 1 << 5,
    Hotkey = 1 << 6,
    SystrayMenu = 1 << 7,
    SystrayTooltip = 1 << 8,
    SystrayClickBehavior = 1 << 9,
    LighteWeight = 1 << 10,
}

/// Patch Verge configuration
pub async fn patch_verge(patch: IVerge, not_save_file: bool) -> Result<()> {
    Config::verge().draft().patch_config(patch.clone());

    let tun_mode = patch.enable_tun_mode;
    let auto_launch = patch.enable_auto_launch;
    let system_proxy = patch.enable_system_proxy;
    let pac = patch.proxy_auto_config;
    let pac_content = patch.pac_file_content;
    let proxy_bypass = patch.system_proxy_bypass;
    let language = patch.language;
    let mixed_port = patch.verge_mixed_port;
    #[cfg(target_os = "macos")]
    let tray_icon = patch.tray_icon;
    #[cfg(not(target_os = "macos"))]
    let tray_icon: Option<String> = None;
    let common_tray_icon = patch.common_tray_icon;
    let sysproxy_tray_icon = patch.sysproxy_tray_icon;
    let tun_tray_icon = patch.tun_tray_icon;
    #[cfg(not(target_os = "windows"))]
    let redir_enabled = patch.verge_redir_enabled;
    #[cfg(not(target_os = "windows"))]
    let redir_port = patch.verge_redir_port;
    #[cfg(target_os = "linux")]
    let tproxy_enabled = patch.verge_tproxy_enabled;
    #[cfg(target_os = "linux")]
    let tproxy_port = patch.verge_tproxy_port;
    let socks_enabled = patch.verge_socks_enabled;
    let socks_port = patch.verge_socks_port;
    let http_enabled = patch.verge_http_enabled;
    let http_port = patch.verge_port;
    let enable_tray_speed = patch.enable_tray_speed;
    let enable_global_hotkey = patch.enable_global_hotkey;
    let tray_event = patch.tray_event;
    let home_cards = patch.home_cards.clone();
    let enable_auto_light_weight = patch.enable_auto_light_weight_mode;
    let res: std::result::Result<(), anyhow::Error> = {
        // Initialize with no flags set
        let mut update_flags: i32 = UpdateFlags::None as i32;

        if tun_mode.is_some() {
            update_flags |= UpdateFlags::ClashConfig as i32;
            update_flags |= UpdateFlags::SystrayMenu as i32;
            update_flags |= UpdateFlags::SystrayTooltip as i32;
            update_flags |= UpdateFlags::SystrayIcon as i32;
        }
        if enable_global_hotkey.is_some() || home_cards.is_some() {
            update_flags |= UpdateFlags::VergeConfig as i32;
        }
        #[cfg(not(target_os = "windows"))]
        if redir_enabled.is_some() || redir_port.is_some() {
            update_flags |= UpdateFlags::RestartCore as i32;
        }
        #[cfg(target_os = "linux")]
        if tproxy_enabled.is_some() || tproxy_port.is_some() {
            update_flags |= UpdateFlags::RestartCore as i32;
        }
        if socks_enabled.is_some()
            || http_enabled.is_some()
            || socks_port.is_some()
            || http_port.is_some()
            || mixed_port.is_some()
        {
            update_flags |= UpdateFlags::RestartCore as i32;
        }
        if auto_launch.is_some() {
            update_flags |= UpdateFlags::Launch as i32;
        }

        if system_proxy.is_some() {
            update_flags |= UpdateFlags::SysProxy as i32;
            update_flags |= UpdateFlags::SystrayMenu as i32;
            update_flags |= UpdateFlags::SystrayTooltip as i32;
            update_flags |= UpdateFlags::SystrayIcon as i32;
        }

        if proxy_bypass.is_some() || pac_content.is_some() || pac.is_some() {
            update_flags |= UpdateFlags::SysProxy as i32;
        }

        if language.is_some() {
            update_flags |= UpdateFlags::SystrayMenu as i32;
        }
        if common_tray_icon.is_some()
            || sysproxy_tray_icon.is_some()
            || tun_tray_icon.is_some()
            || tray_icon.is_some()
            || enable_tray_speed.is_some()
        {
            update_flags |= UpdateFlags::SystrayIcon as i32;
        }

        if patch.hotkeys.is_some() {
            update_flags |= UpdateFlags::Hotkey as i32;
            update_flags |= UpdateFlags::SystrayMenu as i32;
        }

        if tray_event.is_some() {
            update_flags |= UpdateFlags::SystrayClickBehavior as i32;
        }

        if enable_auto_light_weight.is_some() {
            update_flags |= UpdateFlags::LighteWeight as i32;
        }

        // Process updates based on flags
        if (update_flags & (UpdateFlags::RestartCore as i32)) != 0 {
            Config::generate().await?;
            CoreManager::global().restart_core().await?;
        }
        if (update_flags & (UpdateFlags::ClashConfig as i32)) != 0 {
            CoreManager::global().update_config().await?;
            handle::Handle::refresh_clash();
        }
        if (update_flags & (UpdateFlags::VergeConfig as i32)) != 0 {
            Config::verge().draft().enable_global_hotkey = enable_global_hotkey;
            handle::Handle::refresh_verge();
        }
        if (update_flags & (UpdateFlags::Launch as i32)) != 0 {
            sysopt::Sysopt::global().update_launch()?;
        }
        if (update_flags & (UpdateFlags::SysProxy as i32)) != 0 {
            sysopt::Sysopt::global().update_sysproxy().await?;
        }
        if (update_flags & (UpdateFlags::Hotkey as i32)) != 0 {
            hotkey::Hotkey::global().update(patch.hotkeys.unwrap())?;
        }
        if (update_flags & (UpdateFlags::SystrayMenu as i32)) != 0 {
            tray::Tray::global().update_menu()?;
        }
        if (update_flags & (UpdateFlags::SystrayIcon as i32)) != 0 {
            tray::Tray::global().update_icon(None)?;
        }
        if (update_flags & (UpdateFlags::SystrayTooltip as i32)) != 0 {
            tray::Tray::global().update_tooltip()?;
        }
        if (update_flags & (UpdateFlags::SystrayClickBehavior as i32)) != 0 {
            tray::Tray::global().update_click_behavior()?;
        }
        if (update_flags & (UpdateFlags::LighteWeight as i32)) != 0 {
            if enable_auto_light_weight.unwrap() {
                lightweight::enable_auto_light_weight_mode();
            } else {
                lightweight::disable_auto_light_weight_mode();
            }
        }

        <Result<()>>::Ok(())
    };
    match res {
        Ok(()) => {
            Config::verge().apply();
            if !not_save_file {
                Config::verge().data().save_file()?;
            }

            Ok(())
        }
        Err(err) => {
            Config::verge().discard();
            Err(err)
        }
    }
}
