package config

import (
	"fmt"
	"os"
	"path/filepath"

	"github.com/spf13/viper"
	"go.yaml.in/yaml/v3"
)

type Config struct {
	Database DatabaseConfig `yaml:"database"`
	Log      LogConfig      `yaml:"log"`
}

type DatabaseConfig struct {
	DSN  string `yaml:"dsn"`  // 数据库连接字符串
	Path string `yaml:"path"` // SQLite: 目录路径
	Name string `yaml:"name"` // SQLite: 文件名
}

type LogConfig struct {
	Level     string `yaml:"level"`
	Format    string `yaml:"format"`
	Output    string `yaml:"output"`
	Verbose   bool   `yaml:"verbose"`
	LogFile   string `yaml:"log_file"`
	ShowColor bool   `yaml:"show_color"`
}

// --------------------------------- 全局单例配置(核心) ---------------------------------
var (
	// GlobalConfig 全局配置单例实例
	GlobalConfig *Config
	// 命令行参数配置(全局、由root命令绑定)
	CLIParams = struct {
		Verbose bool   // -v/--verbose
		NoColor bool   // --no-color
		Config  string // -c/--config
	}{}
	BaseDir       string = "/etc/sunhpc"
	LogDir        string = "/var/log/sunhpc"
	TmplDir       string = BaseDir + "/tmpl.d"
	appName       string = "sunhpc"
	defaultDBPath string = "/var/lib/sunhpc"
	defaultDBName string = "sunhpc.db"
)

// ----------------------------------- 配置加载(只加载一次) -----------------------------------
func LoadConfig() (*Config, error) {
	// 如果已经加载过，直接返回
	if GlobalConfig != nil {
		return GlobalConfig, nil
	}

	viper.SetConfigName("sunhpc")
	viper.SetConfigType("yaml")
	viper.AddConfigPath(BaseDir)
	viper.AddConfigPath(".")
	viper.AddConfigPath(filepath.Join(os.Getenv("HOME"), "."))

	// Step 1: 设置默认值(最低优先级)
	viper.SetDefault("log.level", "info")
	viper.SetDefault("log.format", "text")
	viper.SetDefault("log.output", "stdout")
	viper.SetDefault("log.verbose", false)
	viper.SetDefault("log.log_file", filepath.Join(LogDir, "sunhpc.log"))
	viper.SetDefault("database.name", "sunhpc.db")
	viper.SetDefault("database.path", "/var/lib/sunhpc")

	if err := viper.ReadInConfig(); err != nil {
		// 配置文件不存在时，使用默认值
		if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
			return nil, err
		}
	}

	// 合并命令行参数(最高优先级)
	if CLIParams.Verbose {
		viper.Set("log.verbose", true)
		viper.Set("log.level", "debug")
	}

	// 合并noColor参数
	if CLIParams.NoColor {
		viper.Set("log.show_color", false)
	}

	fullPath := filepath.Join(
		viper.GetString("database.path"), viper.GetString("database.name"))
	dsn := fmt.Sprintf(
		"%s?_foreign_keys=on&_journal_mode=WAL&_timeout=5000", fullPath)
	viper.Set("database.dsn", dsn)

	// 解码到结构体
	var cfg Config
	if err := viper.Unmarshal(&cfg); err != nil {
		return nil, err
	}

	GlobalConfig = &cfg

	return GlobalConfig, nil
}

// InitDirs 创建所有必需目录
func InitDirs() error {
	dirs := []string{
		BaseDir,
		TmplDir,
		LogDir,
	}
	for _, d := range dirs {
		if err := os.MkdirAll(d, 0755); err != nil {
			return fmt.Errorf("创建目录 %s 失败: %w", d, err)
		}
	}
	return nil
}

func (c *Config) WriteDefaultConfig(path string) error {
	// 确保目录存在
	dir := filepath.Dir(path)
	if err := os.MkdirAll(dir, 0755); err != nil {
		return fmt.Errorf("创建目录失败: %w", err)
	}

	// 生成默认配置
	cfg := DefaultConfig(path)

	// 序列化为 YAML
	data, err := yaml.Marshal(cfg)
	if err != nil {
		return fmt.Errorf("序列化配置失败: %w", err)
	}

	// 写入文件（0644 权限）
	return os.WriteFile(path, data, 0644)
}

func DefaultConfig(path string) *Config {
	return &Config{
		Database: DatabaseConfig{
			DSN: fmt.Sprintf("%s?_foreign_keys=on&_journal_mode=WAL&_timeout=5000",
				filepath.Join(filepath.Dir(path), defaultDBName)),
			Path: filepath.Dir(path),
			Name: defaultDBName,
		},
		Log: LogConfig{
			Level:   "info",
			Format:  "text",
			Output:  "stdout",
			LogFile: filepath.Join(filepath.Dir(path), "sunhpc.log"),
			Verbose: false,
		},
	}
}

// ResetConfig 重置全局配置为默认值
func ResetConfig() {
	GlobalConfig = nil
	viper.Reset()
	CLIParams = struct {
		Verbose bool   // -v/--verbose
		NoColor bool   // --no-color
		Config  string // -c/--config
	}{}
}
