package config

import (
	"fmt"
	"os"
	"path/filepath"
	"sunhpc/pkg/logger"
	"sunhpc/pkg/utils"
	"sync"

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

// ==============================================================
// 全局变量
// ==============================================================
var (
	GlobalConfig *Config
	configOnce   sync.Once    // 确保配置只加载一次
	configMutex  sync.RWMutex // 读写锁保护 GlobalConfig
)

// ==============================================================
// 目录常量 (可在 main.go 中通过 flag 覆盖默认值)
// ==============================================================
var (
	BaseDir string = utils.DefaultBaseDir
	TmplDir string = utils.DefaultTmplDir
	LogDir  string = utils.DefaultLogDir
)

// ==============================================================
// 配置结构体
// ==============================================================
type Config struct {
	Log      logger.LogConfig `mapstructure:"log" yaml:"log"`
	Database DatabaseConfig   `mapstructure:"database" yaml:"database"`
}

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

type CLIParamsType struct {
	Verbose bool   // -v/--verbose
	NoColor bool   // --no-color
	Config  string // -c/--config
}

var CLIParams CLIParamsType // 命令行参数

// InitConfigs 初始化所有配置目录等数据
func InitConfigs() 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)
		}
	}

	// 检查配置文件是否存在，不存在则创建默认配置
	configPath := filepath.Join(BaseDir, "sunhpc.yaml")
	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		if err := createDefaultConfig(configPath); err != nil {
			return fmt.Errorf("创建默认配置文件失败: %w", err)
		}
	}
	return nil
}

func createDefaultConfig(configPath string) error {
	defaultConfig := &Config{
		Database: DatabaseConfig{
			Path: utils.DefaultDBPath,
			Name: utils.DefaultDBName,
			Args: utils.DefaultDBArgs,
		},
		Log: logger.LogConfig{
			Level:     "info",
			Format:    "text",
			Output:    "stdout",
			Verbose:   false,
			LogFile:   utils.DefaultLogFile,
			ShowColor: true,
		},
	}

	// 确保数据库目录存在
	if err := os.MkdirAll(defaultConfig.Database.Path, 0755); err != nil {
		return fmt.Errorf("创建数据库目录失败: %w", err)
	}

	// 序列号并写入
	data, err := yaml.Marshal(defaultConfig)
	if err != nil {
		return fmt.Errorf("序列化配置失败: %w", err)
	}
	return os.WriteFile(configPath, data, 0644)
}

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

	// 双重检查
	if GlobalConfig != nil {
		// 如果已经加载过，直接返回
		return GlobalConfig, nil
	}

	// 配置文件路径
	if CLIParams.Config != "" {
		viper.SetConfigFile(CLIParams.Config)
	} else {
		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", utils.DefaultLogFile)
	viper.SetDefault("database.name", utils.DefaultDBName)
	viper.SetDefault("database.path", utils.DefaultDBPath)

	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)
	}

	// 计算派生配置 (如数据库 DSN)
	dbPath := viper.GetString("database.path")
	dbName := viper.GetString("database.name")
	dbArgs := viper.GetString("database.args")
	fullPath := filepath.Join(dbPath, dbName)
	dsn := fmt.Sprintf("%s?%s", fullPath, dbArgs)
	viper.Set("database.dsn", dsn)

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

	GlobalConfig = &cfg

	return GlobalConfig, nil
}

// ==============================================================
// SaveConfig - 保存全局配置到文件、运行时配置
// ==============================================================
func SaveConfig() error {
	configMutex.RLock()
	defer configMutex.RUnlock()

	if GlobalConfig == nil {
		return fmt.Errorf("全局配置为空")
	}

	configPath := filepath.Join(BaseDir, "config.yaml")
	data, err := yaml.Marshal(GlobalConfig)
	if err != nil {
		return err
	}
	return os.WriteFile(configPath, data, 0644)
}

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