package provider

import (
	"fmt"
	"net/url"
	"strings"
)

type APIConfig struct {
	APIType         string
	BaseURL         string
	EditableBaseURL bool
	DiscoverModels  bool
	DefaultAuthMode string
	AuthModes       []string
	Models          []Model
}

const (
	AuthModeBearer  = "bearer"
	AuthModeXAPIKey = "x-api-key"
)

type Model struct {
	ID   string
	Name string
}

type Meta struct {
	Key            string
	DisplayName    string
	DisplayNameKey string
	Sort           uint
	DefaultAPIType string
	APIConfigs     []APIConfig
	EnvKey         string
	Models         []Model
}

var catalog = map[string]Meta{
	"custom": {
		Key: "custom", DisplayName: "Custom", Sort: 10, DefaultAPIType: "openai-completions", EnvKey: "CUSTOM_API_KEY",
		APIConfigs: editableAPIConfigs(true, "openai-completions", "openai-responses", "anthropic-messages", "openai-images"),
	},
	"ollama": {
		Key: "ollama", DisplayName: "Ollama", Sort: 15, DefaultAPIType: "openai-responses",
		APIConfigs: editableAPIConfigs(false, "openai-responses", "openai-completions"),
	},
	"vllm": {
		Key: "vllm", DisplayName: "vLLM", Sort: 20, DefaultAPIType: "openai-completions", EnvKey: "VLLM_API_KEY",
		APIConfigs: editableAPIConfigs(false, "openai-completions", "openai-responses", "anthropic-messages", "openai-images"),
	},
	"deepseek": {
		Key: "deepseek", DisplayName: "DeepSeek", Sort: 25, DefaultAPIType: "openai-completions", EnvKey: "DEEPSEEK_API_KEY",
		APIConfigs: []APIConfig{
			{APIType: "openai-completions", BaseURL: "https://api.deepseek.com"},
			anthropicAPIConfig("https://api.deepseek.com/anthropic", AuthModeXAPIKey),
		},
		Models: []Model{{ID: "deepseek-v4-flash", Name: "deepseek-v4-flash"}, {ID: "deepseek-v4-pro", Name: "deepseek-v4-pro"}},
	},
	"bailian-coding-plan": {
		Key: "bailian-coding-plan", DisplayNameKey: "AIProviderBailianCodingPlan", Sort: 30, DefaultAPIType: "openai-completions", EnvKey: "QWEN_API_KEY",
		APIConfigs: []APIConfig{
			{APIType: "openai-completions", BaseURL: "https://coding.dashscope.aliyuncs.com/v1"},
			anthropicAPIConfig("https://coding.dashscope.aliyuncs.com/apps/anthropic", AuthModeBearer),
		},
		Models: []Model{
			{ID: "qwen3-coder-plus", Name: "Qwen3-Coder-Plus"},
			{ID: "qwen3-max-2026-01-23", Name: "Qwen3-Max-2026-01-23"},
			{ID: "qwen3-coder-next", Name: "Qwen3-Coder-Next"},
			{ID: "glm-4.7", Name: "GLM-4.7"},
			{ID: "kimi-k2.5", Name: "Kimi K2.5"},
			{ID: "qwen3.5-plus", Name: "Qwen3.5-Plus"},
			{ID: "glm-5", Name: "GLM-5"},
			{ID: "MiniMax-M2.5", Name: "MiniMax M2.5"},
			{ID: "qwen3.6-plus", Name: "Qwen3.6-Plus"},
			{ID: "qwen3.7-plus", Name: "Qwen3.7-Plus"},
		},
	},
	"ark-coding-plan": {
		Key: "ark-coding-plan", DisplayNameKey: "AIProviderArkCodingPlan", Sort: 35, DefaultAPIType: "openai-completions", EnvKey: "ARK_API_KEY",
		APIConfigs: []APIConfig{
			{APIType: "openai-completions", BaseURL: "https://ark.cn-beijing.volces.com/api/coding/v3"},
			anthropicAPIConfig("https://ark.cn-beijing.volces.com/api/coding", AuthModeBearer),
		},
		Models: []Model{
			{ID: "ark-code-latest", Name: "Ark Coding Plan"}, {ID: "doubao-seed-code", Name: "Doubao Seed Code"},
			{ID: "glm-4.7", Name: "GLM 4.7 Coding"}, {ID: "kimi-k2-thinking", Name: "Kimi K2 Thinking"},
			{ID: "kimi-k2.5", Name: "Kimi K2.5 Coding"}, {ID: "doubao-seed-code-preview-251028", Name: "Doubao Seed Code Preview"},
		},
	},
	"zai": {
		Key: "zai", DisplayName: "Z.ai", Sort: 40, DefaultAPIType: "openai-completions", EnvKey: "ZAI_API_KEY",
		APIConfigs: []APIConfig{
			{APIType: "openai-completions", BaseURL: "https://open.bigmodel.cn/api/paas/v4", EditableBaseURL: true},
			{APIType: "openai-images", BaseURL: "https://open.bigmodel.cn/api/paas/v4", EditableBaseURL: true},
		},
		Models: []Model{{ID: "glm-5", Name: "GLM-5"}, {ID: "glm-4.7", Name: "GLM-4.7"}, {ID: "glm-4.7-flash", Name: "GLM-4.7-Flash"}, {ID: "glm-4.7-flashx", Name: "GLM-4.7-FlashX"}},
	},
	"minimax": {
		Key: "minimax", DisplayName: "MiniMax (CN)", Sort: 45, DefaultAPIType: "anthropic-messages", EnvKey: "MINIMAX_API_KEY",
		APIConfigs: []APIConfig{
			anthropicAPIConfig("https://api.minimaxi.com/anthropic", AuthModeXAPIKey, AuthModeBearer),
			{APIType: "openai-completions", BaseURL: "https://api.minimaxi.com/v1"},
			{APIType: "minimax-images", BaseURL: "https://api.minimaxi.com"},
		},
		Models: []Model{{ID: "MiniMax-M3", Name: "MiniMax M3"}, {ID: "MiniMax-M2.7", Name: "MiniMax M2.7"}, {ID: "MiniMax-M2.7-highspeed", Name: "MiniMax M2.7 highspeed"}},
	},
	"xiaomi": {
		Key: "xiaomi", DisplayName: "Xiaomi", Sort: 46, DefaultAPIType: "openai-completions", EnvKey: "XIAOMI_API_KEY",
		APIConfigs: []APIConfig{
			{APIType: "openai-completions", BaseURL: "https://api.xiaomimimo.com/v1"},
			{APIType: "openai-responses", BaseURL: "https://api.xiaomimimo.com/v1"},
			anthropicAPIConfig("https://api.xiaomimimo.com/anthropic", AuthModeBearer),
		},
		Models: []Model{{ID: "mimo-v2.5", Name: "Xiaomi MiMo V2.5"}, {ID: "mimo-v2.5-pro", Name: "Xiaomi MiMo V2.5 Pro"}},
	},
	"kimi": {
		Key: "kimi", DisplayName: "Kimi (CN)", Sort: 50, DefaultAPIType: "openai-completions", EnvKey: "KIMI_API_KEY",
		APIConfigs: []APIConfig{{APIType: "openai-completions", BaseURL: "https://api.moonshot.cn/v1"}},
		Models:     []Model{{ID: "kimi-k2.5", Name: "Kimi K2.5"}, {ID: "kimi-k2-0905-preview", Name: "Kimi K2 0905 Preview"}, {ID: "kimi-k2-thinking", Name: "Kimi K2 Thinking"}},
	},
	"kimi-coding": {
		Key: "kimi-coding", DisplayName: "Kimi Coding", Sort: 51, DefaultAPIType: "anthropic-messages", EnvKey: "KIMI_API_KEY",
		APIConfigs: []APIConfig{anthropicAPIConfig("https://api.kimi.com/coding/", AuthModeXAPIKey)},
		Models:     []Model{{ID: "kimi-code", Name: "Kimi Code"}, {ID: "k2p5", Name: "Kimi K2.5"}},
	},
	"openai": {
		Key: "openai", DisplayName: "OpenAI", Sort: 55, DefaultAPIType: "openai-responses", EnvKey: "OPENAI_API_KEY",
		APIConfigs: []APIConfig{
			{APIType: "openai-responses", BaseURL: "https://api.openai.com/v1"},
			{APIType: "openai-completions", BaseURL: "https://api.openai.com/v1"},
			{APIType: "openai-images", BaseURL: "https://api.openai.com/v1"},
		},
		Models: []Model{{ID: "gpt-5.4", Name: "gpt-5.4"}, {ID: "gpt-5.4-pro", Name: "gpt-5.4-pro"}, {ID: "gpt-5.4-mini", Name: "gpt-5.4-mini"}, {ID: "gpt-5.4-nano", Name: "gpt-5.4-nano"}},
	},
	"openrouter": {
		Key: "openrouter", DisplayName: "OpenRouter", Sort: 56, DefaultAPIType: "openai-completions", EnvKey: "OPENROUTER_API_KEY",
		APIConfigs: []APIConfig{
			{APIType: "openai-completions", BaseURL: "https://openrouter.ai/api/v1"},
			{APIType: "openrouter-images", BaseURL: "https://openrouter.ai"},
		},
		Models: []Model{{ID: "openrouter/free", Name: "openrouter/free"}, {ID: "openrouter/auto", Name: "openrouter/auto"}},
	},
	"anthropic": {
		Key: "anthropic", DisplayName: "Anthropic", Sort: 60, DefaultAPIType: "anthropic-messages", EnvKey: "ANTHROPIC_API_KEY",
		APIConfigs: []APIConfig{anthropicAPIConfig("https://api.anthropic.com", AuthModeXAPIKey)},
		Models:     []Model{{ID: "claude-sonnet-4-6", Name: "Claude Sonnet 4.6"}, {ID: "claude-opus-4-6", Name: "Claude Opus 4.6"}, {ID: "claude-opus-4-5", Name: "Claude Opus 4.5"}, {ID: "claude-sonnet-4-5", Name: "Claude Sonnet 4.5"}, {ID: "claude-haiku-4-5", Name: "Claude Haiku 4.5"}},
	},
	"gemini": {
		Key: "gemini", DisplayName: "Gemini", Sort: 65, DefaultAPIType: "gemini-generate-content", EnvKey: "GEMINI_API_KEY",
		APIConfigs: []APIConfig{{APIType: "gemini-generate-content", BaseURL: "https://generativelanguage.googleapis.com"}},
		Models:     []Model{{ID: "gemini-3-flash-preview", Name: "Gemini 3 Flash Preview"}, {ID: "gemini-flash-latest", Name: "Gemini Flash Latest"}, {ID: "gemini-3-pro-preview", Name: "Gemini 3 Pro Preview"}},
	},
	"moonshot": {
		Key: "moonshot", DisplayName: "Moonshot (Global)", Sort: 70, DefaultAPIType: "openai-completions", EnvKey: "MOONSHOT_API_KEY",
		APIConfigs: []APIConfig{{APIType: "openai-completions", BaseURL: "https://api.moonshot.ai/v1"}},
		Models:     []Model{{ID: "kimi-k2.5", Name: "Kimi K2.5"}, {ID: "kimi-k2-0905-preview", Name: "Kimi K2 0905 Preview"}, {ID: "kimi-k2-thinking", Name: "Kimi K2 Thinking"}},
	},
	"bailian": {
		Key: "bailian", DisplayNameKey: "AIProviderBailian", Sort: 31, DefaultAPIType: "openai-completions", EnvKey: "DASHSCOPE_API_KEY",
		APIConfigs: []APIConfig{
			{
				APIType: "openai-completions", BaseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
				DiscoverModels: true,
				Models:         []Model{{ID: "qwen3.7-plus", Name: "qwen3.7-plus"}, {ID: "qwen3.6-plus", Name: "qwen3.6-plus"}, {ID: "qwen3.6-flash", Name: "qwen3.6-flash"}},
			},
			{
				APIType: "openai-responses", BaseURL: "https://dashscope.aliyuncs.com/compatible-mode/v1",
				DiscoverModels: true,
				Models:         []Model{{ID: "qwen3.7-plus", Name: "qwen3.7-plus"}, {ID: "qwen3.6-plus", Name: "qwen3.6-plus"}, {ID: "qwen3.6-flash", Name: "qwen3.6-flash"}},
			},
			{
				APIType: "anthropic-messages", BaseURL: "https://dashscope.aliyuncs.com/apps/anthropic",
				DefaultAuthMode: AuthModeBearer,
				AuthModes:       []string{AuthModeBearer},
				Models:          []Model{{ID: "qwen3.7-plus", Name: "qwen3.7-plus"}, {ID: "qwen3.6-plus", Name: "qwen3.6-plus"}, {ID: "qwen3.6-flash", Name: "qwen3.6-flash"}},
			},
			{
				APIType: "dashscope-images", BaseURL: "https://dashscope.aliyuncs.com",
				Models: []Model{
					{ID: "qwen-image-2.0-pro", Name: "qwen-image-2.0-pro"},
					{ID: "qwen-image-2.0", Name: "qwen-image-2.0"},
					{ID: "wan2.7-image-pro", Name: "wan2.7-image-pro"},
					{ID: "wan2.7-image", Name: "wan2.7-image"},
				},
			},
		},
	},
	"ark": {
		Key: "ark", DisplayNameKey: "AIProviderArk", Sort: 36, DefaultAPIType: "openai-completions", EnvKey: "ARK_API_KEY",
		APIConfigs: []APIConfig{
			{
				APIType: "openai-completions", BaseURL: "https://ark.cn-beijing.volces.com/api/v3",
				DiscoverModels: true,
				Models:         []Model{{ID: "doubao-seed-2-0-pro-260215", Name: "doubao-seed-2-0-pro-260215"}, {ID: "doubao-seed-2-0-lite-260215", Name: "doubao-seed-2-0-lite-260215"}},
			},
			{
				APIType: "openai-responses", BaseURL: "https://ark.cn-beijing.volces.com/api/v3",
				DiscoverModels: true,
				Models:         []Model{{ID: "doubao-seed-2-0-pro-260215", Name: "doubao-seed-2-0-pro-260215"}, {ID: "doubao-seed-2-0-lite-260215", Name: "doubao-seed-2-0-lite-260215"}},
			},
			{
				APIType: "openai-images", BaseURL: "https://ark.cn-beijing.volces.com/api/v3",
				Models: []Model{
					{ID: "doubao-seedream-5-0-260128", Name: "doubao-seedream-5-0-260128"},
					{ID: "doubao-seedream-5-0-lite-260128", Name: "doubao-seedream-5-0-lite-260128"},
					{ID: "doubao-seedream-4-5-251128", Name: "doubao-seedream-4-5-251128"},
				},
			},
		},
	},
}

func editableAPIConfigs(discoverModels bool, apiTypes ...string) []APIConfig {
	configs := make([]APIConfig, 0, len(apiTypes))
	for _, apiType := range apiTypes {
		if apiType == "anthropic-messages" {
			config := anthropicAPIConfig("", AuthModeXAPIKey, AuthModeBearer)
			config.EditableBaseURL = true
			configs = append(configs, config)
			continue
		}
		configs = append(configs, APIConfig{
			APIType:         apiType,
			EditableBaseURL: true,
			DiscoverModels:  discoverModels && (apiType == "openai-completions" || apiType == "openai-responses"),
		})
	}
	return configs
}

func anthropicAPIConfig(baseURL, defaultAuthMode string, additionalAuthModes ...string) APIConfig {
	authModes := []string{defaultAuthMode}
	for _, authMode := range additionalAuthModes {
		if authMode != defaultAuthMode {
			authModes = append(authModes, authMode)
		}
	}
	return APIConfig{
		APIType:         "anthropic-messages",
		BaseURL:         baseURL,
		DefaultAuthMode: defaultAuthMode,
		AuthModes:       authModes,
	}
}

func Get(key string) (Meta, bool) {
	meta, ok := catalog[key]
	if !ok {
		return Meta{}, false
	}
	return cloneMeta(meta), true
}

func All() map[string]Meta {
	result := make(map[string]Meta, len(catalog))
	for key, meta := range catalog {
		result[key] = cloneMeta(meta)
	}
	return result
}

func FindAPIConfig(key, apiType string) (APIConfig, bool) {
	meta, ok := catalog[key]
	if !ok {
		return APIConfig{}, false
	}
	target := strings.TrimSpace(apiType)
	if target == "" {
		target = meta.DefaultAPIType
	}
	for _, config := range meta.APIConfigs {
		if config.APIType == target {
			config.AuthModes = append([]string(nil), config.AuthModes...)
			config.Models = append([]Model(nil), config.Models...)
			return config, true
		}
	}
	return APIConfig{}, false
}

func DefaultModels(key, apiType string) []Model {
	meta, ok := catalog[key]
	if !ok {
		return nil
	}
	target := strings.TrimSpace(apiType)
	if target == "" {
		target = meta.DefaultAPIType
	}
	for _, config := range meta.APIConfigs {
		if config.APIType != target {
			continue
		}
		if len(config.Models) > 0 {
			return append([]Model(nil), config.Models...)
		}
		if IsImageAPIType(config.APIType) {
			return nil
		}
		break
	}
	return append([]Model(nil), meta.Models...)
}

func ResolveAuthMode(provider, apiType, requested string) (string, error) {
	config, ok := FindAPIConfig(provider, apiType)
	if !ok {
		return "", fmt.Errorf("provider %s does not support api type %s", provider, apiType)
	}
	if config.APIType != "anthropic-messages" {
		return "", nil
	}
	authMode := strings.TrimSpace(requested)
	if authMode == "" {
		authMode = config.DefaultAuthMode
	}
	for _, allowed := range config.AuthModes {
		if authMode == allowed {
			return authMode, nil
		}
	}
	return "", fmt.Errorf("provider %s does not support auth mode %s", provider, authMode)
}

func DefaultBaseURL(key string) (string, bool) {
	config, ok := FindAPIConfig(key, "")
	if !ok || strings.TrimSpace(config.BaseURL) == "" {
		return "", false
	}
	return config.BaseURL, true
}

func DefaultAPIType(key string) string {
	meta, ok := catalog[key]
	if !ok || strings.TrimSpace(meta.DefaultAPIType) == "" {
		return "openai-completions"
	}
	return meta.DefaultAPIType
}

func ResolveBaseURL(key, apiType, requested string) (string, error) {
	config, ok := FindAPIConfig(key, apiType)
	if !ok {
		return "", fmt.Errorf("provider %s does not support api type %s", key, apiType)
	}
	if !config.EditableBaseURL {
		return strings.TrimRight(config.BaseURL, "/"), nil
	}
	baseURL := strings.TrimSpace(requested)
	if baseURL == "" {
		baseURL = config.BaseURL
	}
	if baseURL == "" {
		return "", fmt.Errorf("base url is required")
	}
	parsed, err := url.Parse(baseURL)
	if err != nil || parsed.Scheme == "" || parsed.Host == "" {
		return "", fmt.Errorf("invalid base url")
	}
	if key == "custom" && IsImageAPIType(config.APIType) {
		return baseURL, nil
	}
	parsed.Path = normalizeEndpointPath(config.APIType, parsed.Path)
	parsed.RawQuery = ""
	parsed.Fragment = ""
	return strings.TrimRight(parsed.String(), "/"), nil
}

func normalizeEndpointPath(apiType, value string) string {
	if IsImageAPIType(apiType) {
		return strings.TrimRight(value, "/")
	}
	path := strings.TrimRight(value, "/")
	suffixes := []string{}
	switch apiType {
	case "openai-completions":
		suffixes = []string{"/chat/completions"}
	case "openai-responses":
		suffixes = []string{"/responses"}
	case "anthropic-messages":
		suffixes = []string{"/v1/messages", "/messages"}
	}
	for _, suffix := range suffixes {
		if strings.HasSuffix(strings.ToLower(path), suffix) {
			return path[:len(path)-len(suffix)]
		}
	}
	return path
}

func IsImageAPIType(apiType string) bool {
	switch apiType {
	case "openai-images", "dashscope-images", "minimax-images", "openrouter-images":
		return true
	default:
		return false
	}
}

func EnvKey(key string) string {
	meta, ok := catalog[key]
	if !ok {
		return ""
	}
	return meta.EnvKey
}

func DisplayName(key string) string {
	meta, ok := catalog[key]
	if !ok || strings.TrimSpace(meta.DisplayName) == "" {
		return key
	}
	return meta.DisplayName
}

func DisplayNameKey(key string) string {
	meta, ok := catalog[key]
	if !ok {
		return ""
	}
	return meta.DisplayNameKey
}

func NormalizeModelID(provider, modelID string) string {
	target := strings.TrimLeft(strings.TrimSpace(modelID), "/")
	for _, prefix := range legacyModelPrefixes[provider] {
		legacyPrefix := prefix + "/"
		if !strings.HasPrefix(target, legacyPrefix) {
			continue
		}
		candidate := strings.TrimSpace(strings.TrimPrefix(target, legacyPrefix))
		if candidate != "" {
			return candidate
		}
	}
	return target
}

var legacyModelPrefixes = map[string][]string{
	"custom":              {"custom"},
	"vllm":                {"custom"},
	"ollama":              {"ollama"},
	"deepseek":            {"deepseek"},
	"bailian-coding-plan": {"bailian-coding-plan"},
	"ark-coding-plan":     {"ark-coding-plan"},
	"zai":                 {"zai"},
	"minimax":             {"minimax"},
	"xiaomi":              {"xiaomi"},
	"kimi":                {"kimi", "moonshot"},
	"kimi-coding":         {"kimi-coding"},
	"openai":              {"openai"},
	"anthropic":           {"anthropic"},
	"gemini":              {"google", "gemini"},
	"moonshot":            {"moonshot"},
}

func cloneMeta(meta Meta) Meta {
	clone := meta
	clone.APIConfigs = make([]APIConfig, len(meta.APIConfigs))
	for index, config := range meta.APIConfigs {
		clone.APIConfigs[index] = config
		clone.APIConfigs[index].AuthModes = append([]string(nil), config.AuthModes...)
		clone.APIConfigs[index].Models = append([]Model(nil), config.Models...)
	}
	clone.Models = append([]Model(nil), meta.Models...)
	return clone
}
