use crate::app_config::AppType;
use serde_json::json;

use super::{ClaudeApiFormat, CodexWireApi, FormMode, GeminiAuthType, ProviderAddFormState};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ProviderTemplateId {
    Custom,
    ClaudeOfficial,
    OpenAiOfficial,
    GoogleOAuth,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct ProviderTemplateDef {
    id: ProviderTemplateId,
    label: &'static str,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(super) struct SponsorProviderPreset {
    id: &'static str,
    provider_name: &'static str,
    chip_label: &'static str,
    website_url: &'static str,
    register_url: &'static str,
    promo_code: &'static str,
    partner_promotion_key: &'static str,
    claude_base_url: &'static str,
    codex_base_url: &'static str,
    gemini_base_url: &'static str,
}

#[cfg(test)]
impl SponsorProviderPreset {
    pub(super) fn id(&self) -> &'static str {
        self.id
    }

    pub(super) fn register_url(&self) -> &'static str {
        self.register_url
    }
}

static SPONSOR_PROVIDER_PRESETS: [SponsorProviderPreset; 4] = [
    SponsorProviderPreset {
        id: "packycode",
        provider_name: "PackyCode",
        chip_label: "* PackyCode",
        website_url: "https://www.packyapi.com",
        register_url: "https://www.packyapi.com/register?aff=cc-switch-cli",
        promo_code: "cc-switch-cli",
        partner_promotion_key: "packycode",
        claude_base_url: "https://www.packyapi.com",
        codex_base_url: "https://www.packyapi.com/v1",
        gemini_base_url: "https://www.packyapi.com",
    },
    SponsorProviderPreset {
        id: "aicodemirror",
        provider_name: "AICodeMirror",
        chip_label: "* AICodeMirror",
        website_url: "https://www.aicodemirror.com",
        register_url: "https://www.aicodemirror.com/register?invitecode=77V9EA",
        promo_code: "",
        partner_promotion_key: "aicodemirror",
        claude_base_url: "https://api.aicodemirror.com/api/claudecode",
        codex_base_url: "https://api.aicodemirror.com/api/codex/backend-api/codex",
        gemini_base_url: "https://api.aicodemirror.com/api/gemini",
    },
    SponsorProviderPreset {
        id: "rightcode",
        provider_name: "RightCode",
        chip_label: "* RightCode",
        website_url: "https://right.codes",
        register_url: "https://www.right.codes/register?aff=ccswitch-cli",
        promo_code: "",
        partner_promotion_key: "rightcode",
        claude_base_url: "https://www.right.codes/claude",
        codex_base_url: "https://right.codes/codex/v1",
        gemini_base_url: "https://www.right.codes",
    },
    SponsorProviderPreset {
        id: "dds",
        provider_name: "DDS",
        chip_label: "* DDS",
        website_url: "https://www.ddshub.cc",
        register_url: "https://ddshub.short.gy/ccscli",
        promo_code: "",
        partner_promotion_key: "dds",
        claude_base_url: "https://www.ddshub.cc",
        codex_base_url: "https://www.ddshub.cc",
        gemini_base_url: "",
    },
];

static SPONSOR_PROVIDER_PRESETS_CLAUDE: [SponsorProviderPreset; 4] = [
    SPONSOR_PROVIDER_PRESETS[0],
    SPONSOR_PROVIDER_PRESETS[1],
    SPONSOR_PROVIDER_PRESETS[2],
    SPONSOR_PROVIDER_PRESETS[3],
];

static SPONSOR_PROVIDER_PRESETS_CODEX: [SponsorProviderPreset; 4] = [
    SPONSOR_PROVIDER_PRESETS[0],
    SPONSOR_PROVIDER_PRESETS[1],
    SPONSOR_PROVIDER_PRESETS[2],
    SPONSOR_PROVIDER_PRESETS[3],
];

static SPONSOR_PROVIDER_PRESETS_GEMINI: [SponsorProviderPreset; 3] = [
    SPONSOR_PROVIDER_PRESETS[0],
    SPONSOR_PROVIDER_PRESETS[1],
    SPONSOR_PROVIDER_PRESETS[2],
];

static SPONSOR_PROVIDER_PRESETS_OPENCODE: [SponsorProviderPreset; 1] =
    [SPONSOR_PROVIDER_PRESETS[1]];

static SPONSOR_PROVIDER_PRESETS_OPENCLAW: [SponsorProviderPreset; 1] =
    [SPONSOR_PROVIDER_PRESETS[1]];

static PROVIDER_TEMPLATE_DEFS_CLAUDE: [ProviderTemplateDef; 2] = [
    ProviderTemplateDef {
        id: ProviderTemplateId::Custom,
        label: "Custom",
    },
    ProviderTemplateDef {
        id: ProviderTemplateId::ClaudeOfficial,
        label: "Claude Official",
    },
];

static PROVIDER_TEMPLATE_DEFS_CODEX: [ProviderTemplateDef; 2] = [
    ProviderTemplateDef {
        id: ProviderTemplateId::Custom,
        label: "Custom",
    },
    ProviderTemplateDef {
        id: ProviderTemplateId::OpenAiOfficial,
        label: "OpenAI Official",
    },
];

static PROVIDER_TEMPLATE_DEFS_GEMINI: [ProviderTemplateDef; 2] = [
    ProviderTemplateDef {
        id: ProviderTemplateId::Custom,
        label: "Custom",
    },
    ProviderTemplateDef {
        id: ProviderTemplateId::GoogleOAuth,
        label: "Google OAuth",
    },
];

static PROVIDER_TEMPLATE_DEFS_OPENCODE: [ProviderTemplateDef; 1] = [ProviderTemplateDef {
    id: ProviderTemplateId::Custom,
    label: "Custom",
}];

static PROVIDER_TEMPLATE_DEFS_HERMES: [ProviderTemplateDef; 1] = [ProviderTemplateDef {
    id: ProviderTemplateId::Custom,
    label: "Custom",
}];

static PROVIDER_TEMPLATE_DEFS_OPENCLAW: [ProviderTemplateDef; 1] = [ProviderTemplateDef {
    id: ProviderTemplateId::Custom,
    label: "Custom",
}];

pub(super) fn provider_builtin_template_defs(app_type: &AppType) -> &'static [ProviderTemplateDef] {
    match app_type {
        AppType::Claude => &PROVIDER_TEMPLATE_DEFS_CLAUDE,
        AppType::Codex => &PROVIDER_TEMPLATE_DEFS_CODEX,
        AppType::Gemini => &PROVIDER_TEMPLATE_DEFS_GEMINI,
        AppType::OpenCode => &PROVIDER_TEMPLATE_DEFS_OPENCODE,
        AppType::Hermes => &PROVIDER_TEMPLATE_DEFS_HERMES,
        AppType::OpenClaw => &PROVIDER_TEMPLATE_DEFS_OPENCLAW,
    }
}

pub(super) fn provider_sponsor_presets(app_type: &AppType) -> &'static [SponsorProviderPreset] {
    match app_type {
        AppType::Claude => &SPONSOR_PROVIDER_PRESETS_CLAUDE,
        AppType::Codex => &SPONSOR_PROVIDER_PRESETS_CODEX,
        AppType::Gemini => &SPONSOR_PROVIDER_PRESETS_GEMINI,
        AppType::OpenCode => &SPONSOR_PROVIDER_PRESETS_OPENCODE,
        AppType::Hermes => &[],
        AppType::OpenClaw => &SPONSOR_PROVIDER_PRESETS_OPENCLAW,
    }
}

impl ProviderAddFormState {
    pub fn template_count(&self) -> usize {
        provider_builtin_template_defs(&self.app_type).len()
            + provider_sponsor_presets(&self.app_type).len()
    }

    pub fn template_labels(&self) -> Vec<&'static str> {
        let mut labels = provider_builtin_template_defs(&self.app_type)
            .iter()
            .map(|def| def.label)
            .collect::<Vec<_>>();
        labels.extend(
            provider_sponsor_presets(&self.app_type)
                .iter()
                .map(|preset| preset.chip_label),
        );
        labels
    }

    pub fn apply_template(&mut self, idx: usize, existing_ids: &[String]) {
        let builtin_defs = provider_builtin_template_defs(&self.app_type);
        let sponsor_presets = provider_sponsor_presets(&self.app_type);
        let total_templates = builtin_defs.len() + sponsor_presets.len();
        let idx = idx.min(total_templates.saturating_sub(1));
        self.template_idx = idx;
        self.id_is_manual = false;

        if idx >= builtin_defs.len() {
            let sponsor_idx = idx.saturating_sub(builtin_defs.len());
            if let Some(preset) = sponsor_presets.get(sponsor_idx) {
                self.apply_sponsor_preset(preset);
            }
        } else {
            let template_id = builtin_defs
                .get(idx)
                .map(|def| def.id)
                .unwrap_or(ProviderTemplateId::Custom);

            if template_id == ProviderTemplateId::Custom {
                if matches!(self.mode, FormMode::Add) {
                    let defaults = Self::new(self.app_type.clone());
                    let previous_include_common_config = self.include_common_config;
                    let previous_include_common_config_touched = self.include_common_config_touched;
                    self.extra = defaults.extra;
                    self.id = defaults.id;
                    self.id_is_manual = defaults.id_is_manual;
                    self.name = defaults.name;
                    self.website_url = defaults.website_url;
                    self.notes = defaults.notes;
                    self.include_common_config = previous_include_common_config;
                    self.include_common_config_touched = previous_include_common_config_touched;
                    self.json_scroll = defaults.json_scroll;
                    self.codex_preview_section = defaults.codex_preview_section;
                    self.codex_auth_scroll = defaults.codex_auth_scroll;
                    self.codex_config_scroll = defaults.codex_config_scroll;
                    self.claude_model_config_touched = defaults.claude_model_config_touched;
                    self.claude_api_key = defaults.claude_api_key;
                    self.claude_base_url = defaults.claude_base_url;
                    self.claude_api_format = defaults.claude_api_format;
                    self.claude_model = defaults.claude_model;
                    self.claude_reasoning_model = defaults.claude_reasoning_model;
                    self.claude_haiku_model = defaults.claude_haiku_model;
                    self.claude_sonnet_model = defaults.claude_sonnet_model;
                    self.claude_opus_model = defaults.claude_opus_model;
                    self.codex_base_url = defaults.codex_base_url;
                    self.codex_model = defaults.codex_model;
                    self.codex_wire_api = defaults.codex_wire_api;
                    self.codex_requires_openai_auth = defaults.codex_requires_openai_auth;
                    self.codex_env_key = defaults.codex_env_key;
                    self.codex_api_key = defaults.codex_api_key;
                    self.gemini_auth_type = defaults.gemini_auth_type;
                    self.gemini_api_key = defaults.gemini_api_key;
                    self.gemini_base_url = defaults.gemini_base_url;
                    self.gemini_model = defaults.gemini_model;
                    self.openclaw_user_agent = defaults.openclaw_user_agent;
                    self.openclaw_models = defaults.openclaw_models;
                    self.hermes_api_mode = defaults.hermes_api_mode;
                    self.hermes_api_key = defaults.hermes_api_key;
                    self.hermes_base_url = defaults.hermes_base_url;
                    self.hermes_models = defaults.hermes_models;
                    self.hermes_rate_limit_delay = defaults.hermes_rate_limit_delay;
                    self.opencode_npm_package = defaults.opencode_npm_package;
                    self.opencode_api_key = defaults.opencode_api_key;
                    self.opencode_base_url = defaults.opencode_base_url;
                    self.opencode_model_id = defaults.opencode_model_id;
                    self.opencode_model_name = defaults.opencode_model_name;
                    self.opencode_model_context_limit = defaults.opencode_model_context_limit;
                    self.opencode_model_output_limit = defaults.opencode_model_output_limit;
                    self.opencode_model_original_id = defaults.opencode_model_original_id;
                }
                return;
            }

            self.extra = json!({});
            self.notes.set("");
            match template_id {
                ProviderTemplateId::Custom => {}
                ProviderTemplateId::ClaudeOfficial => {
                    self.extra = json!({
                        "category": "official",
                    });
                    self.name.set("Claude Official");
                    self.website_url
                        .set("https://www.anthropic.com/claude-code");
                    self.claude_api_key.set("");
                    self.claude_base_url.set("");
                    self.claude_api_format = ClaudeApiFormat::Anthropic;
                    self.claude_model.set("");
                    self.claude_reasoning_model.set("");
                    self.claude_haiku_model.set("");
                    self.claude_sonnet_model.set("");
                    self.claude_opus_model.set("");
                    self.claude_model_config_touched = false;
                }
                ProviderTemplateId::OpenAiOfficial => {
                    self.extra = json!({
                        "category": "official",
                        "meta": {
                            "codexOfficial": true,
                        }
                    });
                    self.name.set("OpenAI Official");
                    self.website_url.set("https://chatgpt.com/codex");
                    self.codex_api_key.set("");
                    self.codex_base_url.set("");
                    self.codex_model.set("");
                    self.codex_wire_api = CodexWireApi::Responses;
                    self.codex_requires_openai_auth = true;
                    self.codex_env_key.set("");
                }
                ProviderTemplateId::GoogleOAuth => {
                    self.extra = json!({
                        "category": "official",
                        "meta": {
                            "partnerPromotionKey": "google-official",
                        }
                    });
                    self.name.set("Google OAuth");
                    self.website_url.set("https://ai.google.dev");
                    self.gemini_auth_type = GeminiAuthType::OAuth;
                }
            };
        }

        if !self.id_is_manual && !self.name.is_blank() {
            let id = crate::cli::commands::provider_input::generate_provider_id(
                self.name.value.trim(),
                existing_ids,
            );
            self.id.set(id);
        }
    }

    fn apply_sponsor_preset(&mut self, preset: &SponsorProviderPreset) {
        self.extra = json!({
            "meta": {
                "isPartner": true,
                "partnerPromotionKey": preset.partner_promotion_key,
            }
        });
        self.name.set(preset.provider_name);
        self.website_url.set(preset.website_url);
        self.notes.set("");

        match self.app_type {
            AppType::Claude => {
                self.claude_base_url.set(preset.claude_base_url);
            }
            AppType::Codex => {
                self.codex_base_url.set(preset.codex_base_url);
                self.codex_model.set("gpt-5.4");
                self.codex_wire_api = CodexWireApi::Responses;
                self.codex_requires_openai_auth = true;
            }
            AppType::Gemini => {
                self.gemini_auth_type = GeminiAuthType::ApiKey;
                self.gemini_base_url.set(preset.gemini_base_url);
            }
            AppType::OpenCode => {
                if preset.id == "aicodemirror" {
                    self.extra["settingsConfig"] = json!({
                        "npm": "@ai-sdk/anthropic",
                        "options": {
                            "baseURL": preset.claude_base_url,
                        },
                        "models": {
                            "claude-opus-4.6": {
                                "name": "Claude Opus 4.6",
                            },
                            "claude-sonnet-4.6": {
                                "name": "Claude Sonnet 4.6",
                            },
                        },
                    });
                    self.opencode_npm_package.set("@ai-sdk/anthropic");
                    self.opencode_api_key.set("");
                    self.opencode_base_url.set(preset.claude_base_url);
                    self.opencode_model_id.set("claude-opus-4.6");
                    self.opencode_model_name.set("Claude Opus 4.6");
                    self.opencode_model_context_limit.set("");
                    self.opencode_model_output_limit.set("");
                    self.opencode_model_original_id = Some("claude-opus-4.6".to_string());
                }
            }
            AppType::Hermes => {}
            AppType::OpenClaw => {
                if preset.id == "aicodemirror" {
                    self.opencode_api_key.set("");
                    self.opencode_base_url.set(preset.claude_base_url);
                    self.opencode_npm_package.set("anthropic-messages");
                    self.openclaw_user_agent = false;
                    self.openclaw_models = vec![
                        json!({
                            "id": "claude-opus-4-6",
                            "name": "Claude Opus 4.6",
                            "contextWindow": 200000,
                            "cost": {
                                "input": 5,
                                "output": 25,
                            },
                        }),
                        json!({
                            "id": "claude-sonnet-4-6",
                            "name": "Claude Sonnet 4.6",
                            "contextWindow": 200000,
                            "cost": {
                                "input": 3,
                                "output": 15,
                            },
                        }),
                    ];
                    self.opencode_model_id.set("claude-opus-4-6");
                    self.opencode_model_name.set("Claude Opus 4.6");
                    self.opencode_model_context_limit.set("200000");
                    self.opencode_model_original_id = Some("claude-opus-4-6".to_string());
                }
            }
        }
    }
}
