package agent

import (
	"encoding/json"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

// 支持的接口类型。
const (
	ProviderOpenAI    = "openai"
	ProviderAnthropic = "anthropic"
)

// 协作 worker 管理模式。
const (
	// CoopModeDocker 通过 Docker 容器管理 worker（需本机/远程 Docker daemon）。
	CoopModeDocker = "docker"
	// CoopModeLocal 通过本地子进程管理 worker（无需 Docker，托管沙箱等场景）。
	CoopModeLocal = "local"
)

// LLM 配置环境变量名。环境变量优先级最高，覆盖 api-config.json 用户配置与内置默认值。
// 适用于托管沙箱等场景：平台注入环境变量，Agent 启动即生效，无需通过 Web 设置页配置。
const (
	EnvLLMAPIKey   = "LLM_API_KEY"
	EnvLLMBaseURL  = "LLM_BASE_URL"
	EnvLLMModel    = "LLM_MODEL"
	EnvLLMProvider = "LLM_PROVIDER"
	EnvLLMEngine   = "LLM_ENGINE"
	EnvCoopMode    = "COOP_MODE"
)

// APIConfig 是用户可配置的 LLM API 连接信息。
type APIConfig struct {
	// APIKey 是模型服务商 API Key。
	APIKey string `json:"api_key,omitempty"`
	// BaseURL 是模型接口地址。
	BaseURL string `json:"base_url,omitempty"`
	// Model 是模型名称。
	Model string `json:"model,omitempty"`
	// Provider 是接口类型：openai（OpenAI 兼容）或 anthropic（Anthropic Messages API）。
	Provider string `json:"provider,omitempty"`
	// Engine 是默认协作引擎：pi（默认）/ pigo / claude。
	// 仅影响 run_coop 未显式指定 engine 时的默认值，见 tools_coop.go。
	Engine string `json:"engine,omitempty"`
	// CoopMode 是协作 worker 管理模式：local（默认，本地子进程）/ docker（Docker 容器）。
	// local 模式无需 Docker，适用于托管沙箱等无 Docker 环境；docker 模式需本机/远程 Docker daemon。
	CoopMode string `json:"coop_mode,omitempty"`
}

// APIConfigStore 持久化用户的 LLM API 配置，未配置的字段回退到默认值（环境变量）。
type APIConfigStore struct {
	mu       sync.RWMutex
	path     string
	config   APIConfig
	defaults APIConfig
}

func NewAPIConfigStore(dataDir string, defaults APIConfig) (*APIConfigStore, error) {
	store := &APIConfigStore{
		path:     filepath.Join(dataDir, "api-config.json"),
		defaults: defaults,
	}
	store.load()
	return store, nil
}

func (s *APIConfigStore) load() {
	data, err := os.ReadFile(s.path)
	if err != nil {
		return
	}
	if len(data) == 0 {
		return
	}
	var config APIConfig
	if err := json.Unmarshal(data, &config); err != nil {
		return
	}
	s.config = config
}

func (s *APIConfigStore) persist() error {
	data, err := json.MarshalIndent(s.config, "", "  ")
	if err != nil {
		return err
	}
	tmp := s.path + ".tmp"
	if err := os.WriteFile(tmp, data, 0o600); err != nil {
		return err
	}
	return os.Rename(tmp, s.path)
}

// APIKey 返回生效的 API Key。
// 优先级：环境变量 LLM_API_KEY > api-config.json > 内置默认值。
func (s *APIConfigStore) APIKey() string {
	if v := strings.TrimSpace(os.Getenv(EnvLLMAPIKey)); v != "" {
		return v
	}
	s.mu.RLock()
	defer s.mu.RUnlock()
	if s.config.APIKey != "" {
		return s.config.APIKey
	}
	return s.defaults.APIKey
}

// BaseURL 返回生效的接口地址。
// 优先级：环境变量 LLM_BASE_URL > api-config.json > 内置默认值。
func (s *APIConfigStore) BaseURL() string {
	if v := strings.TrimSpace(os.Getenv(EnvLLMBaseURL)); v != "" {
		return v
	}
	s.mu.RLock()
	defer s.mu.RUnlock()
	if s.config.BaseURL != "" {
		return s.config.BaseURL
	}
	return s.defaults.BaseURL
}

// Model 返回生效的模型名称。
// 优先级：环境变量 LLM_MODEL > api-config.json > 内置默认值。
func (s *APIConfigStore) Model() string {
	if v := strings.TrimSpace(os.Getenv(EnvLLMModel)); v != "" {
		return v
	}
	s.mu.RLock()
	defer s.mu.RUnlock()
	if s.config.Model != "" {
		return s.config.Model
	}
	return s.defaults.Model
}

// IsAPIKeyConfigured 报告是否已配置 API Key（含环境变量、用户配置与内置默认值）。
// LLM 客户端实际会按 APIKey() 的优先级（环境变量 > api-config.json > 默认值）取用，
// 因此只要最终能拿到非空 Key 就视为已配置，避免误判导致无法对话。
func (s *APIConfigStore) IsAPIKeyConfigured() bool {
	if v := strings.TrimSpace(os.Getenv(EnvLLMAPIKey)); v != "" {
		return true
	}
	s.mu.RLock()
	defer s.mu.RUnlock()
	return s.config.APIKey != "" || s.defaults.APIKey != ""
}

// Provider 返回生效的接口类型。
// 优先级：环境变量 LLM_PROVIDER > api-config.json > 内置默认值 > openai。
func (s *APIConfigStore) Provider() string {
	if v := strings.TrimSpace(os.Getenv(EnvLLMProvider)); v != "" {
		if v == ProviderOpenAI || v == ProviderAnthropic {
			return v
		}
	}
	s.mu.RLock()
	defer s.mu.RUnlock()
	if s.config.Provider != "" {
		return s.config.Provider
	}
	if s.defaults.Provider != "" {
		return s.defaults.Provider
	}
	return ProviderOpenAI
}

// Engine 返回生效的默认协作引擎：pi（默认）/ pigo / claude。
// 优先级：环境变量 LLM_ENGINE > api-config.json > 内置默认值 > pi。
// 仅在 run_coop 未显式指定 engine 时使用。
func (s *APIConfigStore) Engine() string {
	if v := strings.TrimSpace(os.Getenv(EnvLLMEngine)); v != "" {
		switch v {
		case "pi", "pigo", "claude":
			return v
		}
	}
	s.mu.RLock()
	defer s.mu.RUnlock()
	switch s.config.Engine {
	case "pi", "pigo", "claude":
		return s.config.Engine
	}
	if s.defaults.Engine != "" {
		return s.defaults.Engine
	}
	return "pi"
}

// CoopMode 返回生效的协作 worker 管理模式：local（默认）/ docker。
// 优先级：环境变量 COOP_MODE > api-config.json > 内置默认值 > local。
// local 模式通过本地子进程运行 worker（无需 Docker），docker 模式通过 Docker 容器运行。
func (s *APIConfigStore) CoopMode() string {
	if v := strings.TrimSpace(os.Getenv(EnvCoopMode)); v != "" {
		switch v {
		case CoopModeDocker, CoopModeLocal:
			return v
		}
	}
	s.mu.RLock()
	defer s.mu.RUnlock()
	switch s.config.CoopMode {
	case CoopModeDocker, CoopModeLocal:
		return s.config.CoopMode
	}
	if s.defaults.CoopMode != "" {
		return s.defaults.CoopMode
	}
	return CoopModeLocal
}

// Update 更新用户配置。每个参数为 nil 表示不修改该字段；
// 非 nil（含空字符串）表示设置或清除该字段（空串=清除，回退默认）。
func (s *APIConfigStore) Update(apiKey, baseURL, model, provider, engine, coopMode *string) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if apiKey != nil {
		s.config.APIKey = *apiKey
	}
	if baseURL != nil {
		s.config.BaseURL = *baseURL
	}
	if model != nil {
		s.config.Model = *model
	}
	if provider != nil {
		value := strings.TrimSpace(*provider)
		if value != ProviderOpenAI && value != ProviderAnthropic {
			value = ""
		}
		s.config.Provider = value
	}
	if engine != nil {
		value := strings.TrimSpace(*engine)
		switch value {
		case "pi", "pigo", "claude":
			// 合法值
		default:
			value = ""
		}
		s.config.Engine = value
	}
	if coopMode != nil {
		value := strings.TrimSpace(*coopMode)
		switch value {
		case CoopModeDocker, CoopModeLocal:
			// 合法值
		default:
			value = ""
		}
		s.config.CoopMode = value
	}
	return s.persist()
}
