package agent

import (
	"bufio"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"
)

type Config struct {
	APIKey    string
	BaseURL   string
	Model     string
	Port      string
	Workspace string
	DataDir   string
	// AuthCode 是 Web/API/WS 访问授权码。为空（默认）表示不启用授权；
	// 非空（Docker 部署时通过环境变量 AGENT_AUTH_CODE 注入）表示启用：
	// 访问者必须输入正确授权码才能使用本实例。
	AuthCode           string
	MaxContextTokens   int
	KeepRecentMessages int
	MaxToolResultChars int
	MaxIterations      int
	ToolTimeout        time.Duration
	RequestTimeout     time.Duration
	StreamOutputTokens int
	CompactionTokens   int
	Temperature        float64
}

func LoadConfig() Config {
	loadDotEnv(".env")

	workspace := getenv("AGENT_WORKSPACE", "")
	if workspace == "" {
		workspace, _ = os.Getwd()
	}
	absWorkspace, err := filepath.Abs(workspace)
	if err != nil {
		absWorkspace = workspace
	}
	dataDir := getenv("AGENT_DATA_DIR", filepath.Join(absWorkspace, "data"))
	if !filepath.IsAbs(dataDir) {
		dataDir = filepath.Join(absWorkspace, dataDir)
	}

	cfg := Config{
		APIKey:    os.Getenv("SILICONFLOW_API_KEY"),
		BaseURL:   getenv("SILICONFLOW_BASE_URL", "https://api.siliconflow.cn/v1/chat/completions"),
		Model:     getenv("AGENT_MODEL", "Qwen/Qwen3-32B"),
		Port:      getenv("AGENT_PORT", "8080"),
		Workspace: absWorkspace,
		DataDir:   dataDir,
		// 全面放开限制以适配 DeepSeek（128K 上下文、大输出）跑复杂任务：
		// - MaxContextTokens 给到 1M，确保 compactionInputBudget 公式（window - Compaction - Stream - window/8）仍有充足余量
		// - StreamOutputTokens 提升到 65536：直接作为 max_tokens 传给 LLM（见 llm.go），是放开主 Agent 输出能力的关键
		// - CompactionTokens 提升到 16384：压缩摘要允许足够长度，避免历史信息丢失
		// - MaxToolResultChars 提升到 100000：复杂任务的脚本/日志能完整传回 LLM，不被截断
		// - KeepRecentMessages 提升到 50：压缩后保留更多历史，复杂多步任务上下文不丢
		// - ToolTimeout/RequestTimeout 提升到 600s：编译/长命令/深度推理有充足时间
		MaxContextTokens:   getenvInt("AGENT_MAX_CONTEXT_TOKENS", 1000000),
		KeepRecentMessages: getenvInt("AGENT_KEEP_RECENT_MESSAGES", 50),
		MaxToolResultChars: getenvInt("AGENT_MAX_TOOL_RESULT_CHARS", 100000),
		MaxIterations:      getenvInt("AGENT_MAX_ITERATIONS", 50),
		ToolTimeout:        time.Duration(getenvInt("AGENT_TOOL_TIMEOUT_SECONDS", 600)) * time.Second,
		RequestTimeout:     time.Duration(getenvInt("AGENT_REQUEST_TIMEOUT_SECONDS", 600)) * time.Second,
		StreamOutputTokens: getenvInt("AGENT_STREAM_OUTPUT_TOKENS", 65536),
		CompactionTokens:   getenvInt("AGENT_COMPACTION_TOKENS", 16384),
		Temperature:        getenvFloat("AGENT_TEMPERATURE", 0.3),
		// 授权码默认关闭：仅当 Docker 部署时显式注入 AGENT_AUTH_CODE 才启用访问授权。
		AuthCode: getenv("AGENT_AUTH_CODE", ""),
	}
	return cfg
}

func loadDotEnv(path string) {
	file, err := os.Open(path)
	if err != nil {
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}
		key, value, ok := strings.Cut(line, "=")
		if !ok {
			continue
		}
		key = strings.TrimSpace(key)
		value = strings.TrimSpace(value)
		value = strings.Trim(value, `"'`)
		if key == "" {
			continue
		}
		if _, exists := os.LookupEnv(key); !exists {
			_ = os.Setenv(key, value)
		}
	}
}

func getenv(key, fallback string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return fallback
}

func getenvInt(key string, fallback int) int {
	value := os.Getenv(key)
	if value == "" {
		return fallback
	}
	parsed, err := strconv.Atoi(value)
	if err != nil {
		return fallback
	}
	return parsed
}

func getenvFloat(key string, fallback float64) float64 {
	value := os.Getenv(key)
	if value == "" {
		return fallback
	}
	parsed, err := strconv.ParseFloat(value, 64)
	if err != nil {
		return fallback
	}
	return parsed
}
