package initcmd

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

	"sunhpc/internal/auth"
	"sunhpc/internal/db"
	"sunhpc/internal/log"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"
)

const (
	appName       string = "sunhpc"
	defaultDBPath string = "/var/lib/sunhpc"
	defaultDBName string = "sunhpc.db"
)

var (
	forceDB    bool
	dbPath     string
	dbName     string
	dbFullPath string
)

func initDBPathWithViper() error {
	/*
		从 Viper 配置文件获取数据库路径
		配置文件里的键要和 Viper.GetXXX 的键对应
		配置文件格式：
		db:
			path: "/tmp/sunhpc"  # 自定义数据库路径
			name: "my_sunhpc.db" # 自定义数据库名
	*/

	log.Infof("从 Viper 配置文件获取数据库路径...")

	// ========== 第一步：设置 Viper 配置文件规则（核心） ==========
	// 1. 设置Viper基础规则
	viper.SetConfigType("yaml")   // 配置文件类型
	viper.SetConfigName("config") // 配置文件名（不带后缀）
	viper.SetEnvPrefix(appName)   // 环境变量前缀：SUNHPC_
	viper.AutomaticEnv()          // 自动读取环境变量（可选，增强兼容性）

	// 2. 添加配置文件搜索目录（Viper 会按顺序查找，找到第一个就停止）
	// 优先级：当前目录 → 用户级目录 → 系统级目录

	// ① 当前目录（开发/测试常用）
	viper.AddConfigPath(".")

	// ② Linux/macOS 用户级目录（~/.config/sunhpc/）
	if homeDir, err := os.UserHomeDir(); err == nil {
		viper.AddConfigPath(filepath.Join(homeDir, ".config", appName))
	}
	// ③ Linux/macOS 系统级目录（/etc/sunhpc/）
	viper.AddConfigPath(filepath.Join("/etc", appName))

	// ========== 第二步：设置默认值（最低优先级） ==========
	viper.SetDefault("db.path", defaultDBPath)
	viper.SetDefault("db.name", defaultDBName)

	// ========== 第三步：绑定环境变量（优先级高于默认值，低于配置文件） ==========
	viper.BindEnv("db.path", "DB_PATH") // 绑定 SUNHPC_DB_PATH → db.path
	viper.BindEnv("db.name", "DB_NAME") // 绑定 SUNHPC_DB_NAME → db.name

	// ========== 第四步：读取配置文件（优先级高于环境变量，低于默认值） ==========
	if err := viper.ReadInConfig(); err != nil {
		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
			log.Info("未找到配置文件,将使用环境变量/默认值")
			return nil // 配置文件存在但格式错误，返回错误
		}
		log.Warnf("读取配置文件失败: %v", err)
		return fmt.Errorf("读取配置文件失败: %w", err)
	}

	log.Infof("成功加载配置文件: %s", viper.ConfigFileUsed())
	return nil
}

func initDBPath() error {

	// 1. 从 Viper 配置文件获取数据库路径(加载配置文件->环境变量->默认值)
	if err := initDBPathWithViper(); err != nil {
		return fmt.Errorf("Viper初始化数据库失败: %v", err)
	}

	// 2. 从Viper获取数据库路径
	dbPath = viper.GetString("db.path")
	dbName = viper.GetString("db.name")

	// 3. 拼接数据库路径
	dbFullPath = filepath.Join(dbPath, dbName)
	log.Infof("数据库完整路径: %s", dbFullPath)

	// 3. 检查数据库文件是否存在
	dir := filepath.Dir(dbFullPath)
	// 4. 检查数据库目录是否存在
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		log.Infof("数据库目录不存在,创建目录: %s", dir)

		if err := os.MkdirAll(dir, 0755); err != nil {
			return fmt.Errorf("创建数据库目录失败: %v", err)
		}
	}
	return nil
}

var databaseCmd = &cobra.Command{
	Use:   "database",
	Short: "初始化数据库",
	Long: `初始化SQLite数据库,创建所有表结构和默认数据。
    
示例:
  sunhpc init database        # 初始化数据库
  sunhpc init database --force # 强制重新初始化`,

	RunE: func(cmd *cobra.Command, args []string) error {
		if err := auth.RequireRoot(); err != nil {
			return err
		}

		log.Debug("初始化数据库...")

		if err := initDBPath(); err != nil {
			return fmt.Errorf("初始化数据库路径失败: %w", err)
		}

		log.Debugf("数据库目录存在: %s", dbPath)

		// 强制模式：用户确认
		if forceDB {
			log.Warn("⚠️  警告：强制重新初始化将清空数据库中的所有数据！")
			fmt.Printf("数据库路径: %s\n", dbFullPath)
			fmt.Print("确认要重新初始化数据库吗？这将删除所有现有数据。(Y/yes): ")

			reader := bufio.NewReader(os.Stdin)
			input, err := reader.ReadString('\n')
			if err != nil {
				return fmt.Errorf("读取用户输入失败: %v", err)
			}

			input = strings.TrimSpace(strings.ToLower(input))
			if input != "y" && input != "yes" {
				log.Info("操作已取消")
				return nil
			}

			log.Info("用户确认重新初始化数据库")
		}

		// 数据库存在且不是强制模式则跳过初始化
		if _, err := os.Stat(dbFullPath); err == nil && !forceDB {
			log.Infof("数据库文件已存在: %s", dbFullPath)
			return nil
		}

		// 初始化数据库（使用配置的路径）
		database, err := db.GetInstanceWithConfig(dbPath, dbName)
		if err != nil {
			return fmt.Errorf("初始化数据库失败: %v", err)
		}
		defer database.Close()

		// 如果是强制模式，设置强制重新初始化标志
		if forceDB {
			database.SetForceInit(true)
			log.Info("强制重新初始化数据库表...")

			// 关闭现有连接以触发重新连接
			if err := database.CloseConnection(); err != nil {
				return fmt.Errorf("关闭现有数据库连接失败: %v", err)
			}

			// 重新连接并初始化
			if err := database.Connect(); err != nil {
				return fmt.Errorf("强制重新初始化数据库失败: %v", err)
			}
		}

		log.Infof("数据库初始化成功: %s", dbFullPath)
		return nil
	},
}

func init() {
	databaseCmd.Flags().BoolVarP(&forceDB, "force", "f", false, "强制重新初始化，删除现有数据库")
	Cmd.AddCommand(databaseCmd)
}
