package config

import (
	"flag"
	"os"
	"path/filepath"
	"runtime"
	"strings"
)

const ConfigDirName = ".sproutclaw"

type Config struct {
	Port     int
	AgentDir string
	RepoRoot string // SproutClaw 仓库根目录（CLI 子进程的工作目录）
	DataDir  string // sproutclaw-web 自己的数据目录（SQLite 等）
	PiCmd    string // SproutClaw CLI 启动命令（完整路径）
	PiArgs   []string

	// 派生路径（从 AgentDir 推导）
	SessionsDir      string
	SystemPromptFile string
	ModelsConfigFile string
	McpConfigFile    string
	McpCacheFile     string
	SettingsFile     string
	SkillsDir        string
	SkillsDisabledDir string
	ExtensionsDir    string
	PromptsDir       string
	FrontendDist     string // ../frontend/dist 相对于可执行文件
}

func New() *Config {
	port := flag.Int("port", 19133, "HTTP port")
	agentDir := flag.String("agent-dir", "", "SproutClaw agent directory (e.g. /path/to/.sproutclaw/agent)")
	repoRoot := flag.String("repo-root", "", "SproutClaw repo root (CLI cwd); defaults to two levels above agent-dir")
	dataDir := flag.String("data-dir", "", "sproutclaw-web data dir for SQLite (defaults to ./data)")
	sproutclawCmd := flag.String("sproutclaw-cmd", "", "SproutClaw CLI command (alias for --pi-cmd)")
	piCmd := flag.String("pi-cmd", "", "SproutClaw CLI command (may include args, e.g. \"node /path/tsx.mjs /path/cli.ts\")")
	frontendDist := flag.String("frontend-dist", "", "path to frontend/dist (defaults to ../frontend/dist relative to binary)")
	flag.Parse()

	if *agentDir == "" {
		*agentDir = resolveDefaultAgentDir()
	}
	if abs, err := filepath.Abs(*agentDir); err == nil {
		*agentDir = abs
	}

	cfg := &Config{
		Port:     *port,
		AgentDir: *agentDir,
		RepoRoot: *repoRoot,
		DataDir:  *dataDir,
	}
	if cfg.RepoRoot == "" {
		cfg.RepoRoot = inferRepoRoot(*agentDir)
	}
	if abs, err := filepath.Abs(cfg.RepoRoot); err == nil {
		cfg.RepoRoot = abs
	}
	// dataDir defaults to ./data relative to cwd (run-backend.bat cd's into backend/)
	if cfg.DataDir == "" {
		cwd, _ := os.Getwd()
		cfg.DataDir = filepath.Join(cwd, "data")
	}
	if abs, err := filepath.Abs(cfg.DataDir); err == nil {
		cfg.DataDir = abs
	}
	// --pi-cmd / --sproutclaw-cmd may include arguments separated by spaces, e.g.
	//   "node /path/to/tsx/dist/cli.mjs /path/to/cli.ts"
	// Split into executable + args so exec.Command receives them correctly.
	cmdLine := strings.TrimSpace(*sproutclawCmd)
	if cmdLine == "" {
		cmdLine = strings.TrimSpace(*piCmd)
	}
	if parts := strings.Fields(cmdLine); len(parts) > 0 {
		cfg.PiCmd = parts[0]
		cfg.PiArgs = parts[1:]
	}
	cfg.derivePaths()

	// Override frontend dist if explicitly specified
	if *frontendDist != "" {
		cfg.FrontendDist = *frontendDist
	}
	return cfg
}

func (c *Config) derivePaths() {
	a := c.AgentDir
	c.SessionsDir = filepath.Join(a, "sessions")
	c.SystemPromptFile = filepath.Join(a, "AGENTS.md")
	c.ModelsConfigFile = filepath.Join(a, "models.json")
	c.McpConfigFile = filepath.Join(a, "mcp.json")
	c.McpCacheFile = filepath.Join(a, "mcp-cache.json")
	c.SettingsFile = filepath.Join(a, "settings.json")
	c.SkillsDir = filepath.Join(a, "skills")
	c.SkillsDisabledDir = filepath.Join(a, "skills-disabled")
	c.ExtensionsDir = filepath.Join(a, "extensions")
	c.PromptsDir = filepath.Join(a, "prompts")

	// frontend/dist 相对于二进制所在目录的上级
	exe, err := os.Executable()
	if err != nil {
		exe, _ = os.Getwd()
	}
	exeDir := filepath.Dir(exe)
	c.FrontendDist = filepath.Join(exeDir, "..", "frontend", "dist")
}

func Platform() string {
	return runtime.GOOS
}

func Arch() string {
	return runtime.GOARCH
}

func resolveDefaultAgentDir() string {
	if env := strings.TrimSpace(os.Getenv("SPROUTCLAW_AGENT_DIR")); env != "" {
		return env
	}
	cwd, _ := os.Getwd()
	candidates := []string{
		filepath.Join(cwd, ConfigDirName, "agent"),
		filepath.Join(cwd, "..", "sproutclaw", ConfigDirName, "agent"),
		filepath.Join(cwd, "..", "sproutclaw", ".pi", "agent"),
	}
	for _, candidate := range candidates {
		if st, err := os.Stat(candidate); err == nil && st.IsDir() {
			return candidate
		}
	}
	return filepath.Join(cwd, ConfigDirName, "agent")
}

func inferRepoRoot(agentDir string) string {
	agentDir = filepath.Clean(agentDir)
	if filepath.Base(agentDir) == "agent" {
		configDir := filepath.Base(filepath.Dir(agentDir))
		if configDir == ConfigDirName || configDir == ".pi" {
			return filepath.Dir(filepath.Dir(agentDir))
		}
	}
	return filepath.Dir(filepath.Dir(agentDir))
}
