package cmd

import (
	"bufio"
	"crypto/rand"
	"encoding/hex"
	"fmt"
	"net"
	"os"
	"path/filepath"
	"strings"

	"github.com/spf13/cobra"
	"golang.org/x/term"

	"github.com/user-management-system/internal/config"
	"github.com/user-management-system/internal/database"
)

// initCmd is the init subcommand
var initCmd = &cobra.Command{
	Use:   "init",
	Short: "Initialize the User Management System",
	Long: `Interactively initialize UMS: generate secrets, configure database,
bootstrap admin user, and create configuration files.

This command can run in two modes:
1. Interactive mode (no flags): Prompts for all required values
2. Non-interactive mode (with flags): Uses provided values directly

Examples:
  # Interactive mode
  ums init

  # Non-interactive mode
  ums init --admin-user admin --admin-pass MySecret123 --admin-email admin@example.com`,
	RunE: func(cmd *cobra.Command, args []string) error {
		return runInit(cmd)
	},
}

var (
	initDBType        string
	initDBPath        string
	initRedisEnable   bool
	initRedisHost     string
	initRedisPort     int
	initRedisPassword string
	adminUser         string
	adminPass         string
	adminEmail        string
	initPort          int
	initCorsOrigin    string
	yesFlag           bool
)

func init() {
	initCmd.Flags().StringVar(&initDBType, "db-type", "sqlite", "database type (sqlite, postgresql, mysql)")
	initCmd.Flags().StringVar(&initDBPath, "db-path", "./data/user_management.db", "database path or connection string")
	initCmd.Flags().BoolVar(&initRedisEnable, "redis-enable", false, "enable Redis")
	initCmd.Flags().StringVar(&initRedisHost, "redis-host", "localhost", "Redis host")
	initCmd.Flags().IntVar(&initRedisPort, "redis-port", 6379, "Redis port")
	initCmd.Flags().StringVar(&initRedisPassword, "redis-password", "", "Redis password")
	initCmd.Flags().StringVar(&adminUser, "admin-user", "", "admin username")
	initCmd.Flags().StringVar(&adminPass, "admin-pass", "", "admin password")
	initCmd.Flags().StringVar(&adminEmail, "admin-email", "", "admin email")
	initCmd.Flags().IntVar(&initPort, "port", 8080, "server port")
	initCmd.Flags().StringVar(&initCorsOrigin, "cors-origin", "http://localhost:3000", "CORS allowed origin")
	initCmd.Flags().BoolVar(&yesFlag, "yes", false, "skip confirmation")

	rootCmd.AddCommand(initCmd)
}

type initConfig struct {
	dbType          string
	dbPath          string
	redisEnable     bool
	redisHost       string
	redisPort       int
	redisPassword   string
	adminUser       string
	adminPass       string
	adminEmail      string
	port            int
	corsOrigin      string
	jwtSecret       string
	bootstrapSecret string
}

func runInit(cmd *cobra.Command) error {
	cfg, err := gatherInitConfig()
	if err != nil {
		return err
	}

	// 显示配置摘要
	fmt.Println("\n=== Configuration Summary ===")
	fmt.Printf("Database Type:     %s\n", cfg.dbType)
	fmt.Printf("Database Path:     %s\n", cfg.dbPath)
	fmt.Printf("Redis Enabled:     %t\n", cfg.redisEnable)
	if cfg.redisEnable {
		fmt.Printf("Redis Host:        %s:%d\n", cfg.redisHost, cfg.redisPort)
	}
	fmt.Printf("Admin User:        %s\n", cfg.adminUser)
	fmt.Printf("Admin Email:       %s\n", cfg.adminEmail)
	fmt.Printf("Server Port:       %d\n", cfg.port)
	fmt.Printf("CORS Origin:       %s\n", cfg.corsOrigin)
	fmt.Println("===========================")

	if !yesFlag {
		fmt.Print("Proceed with initialization? [y/N]: ")
		reader := bufio.NewReader(os.Stdin)
		input, _ := reader.ReadString('\n')
		input = strings.TrimSpace(strings.ToLower(input))
		if input != "y" && input != "yes" {
			fmt.Println("Initialization cancelled.")
			return nil
		}
	}

	// 1. 创建数据目录
	if err := createDataDirectory(cfg); err != nil {
		return fmt.Errorf("create data directory failed: %w", err)
	}

	// 2. 生成密钥
	cfg.jwtSecret = generateSecret(32)
	cfg.bootstrapSecret = generateSecret(16)

	// 3. 创建配置文件
	if err := createConfigFiles(cfg); err != nil {
		return fmt.Errorf("create config files failed: %w", err)
	}

	// 4. 执行数据库迁移
	if err := runMigrations(cfg); err != nil {
		return fmt.Errorf("run migrations failed: %w", err)
	}

	// 5. 创建管理员账号
	if err := createAdminUser(cfg); err != nil {
		return fmt.Errorf("create admin user failed: %w", err)
	}

	fmt.Println("\n=== Initialization Complete ===")
	fmt.Println("Configuration files created:")
	fmt.Printf("  - %s\n", getConfigPath())
	fmt.Printf("  - %s\n", getEnvPath())
	fmt.Println("\nTo start the server:")
	fmt.Println("  ums serve")
	fmt.Println("=============================")

	return nil
}

func gatherInitConfig() (*initConfig, error) {
	isInteractive := adminUser == "" || adminPass == "" || adminEmail == ""

	if isInteractive {
		return gatherInteractiveConfig()
	}

	// 非交互式模式：验证必需参数
	if adminUser == "" {
		return nil, fmt.Errorf("--admin-user is required")
	}
	if adminPass == "" {
		return nil, fmt.Errorf("--admin-pass is required")
	}
	if adminEmail == "" {
		return nil, fmt.Errorf("--admin-email is required")
	}

	// 验证密码强度
	if len(adminPass) < 8 {
		return nil, fmt.Errorf("password must be at least 8 characters")
	}

	return &initConfig{
		dbType:        initDBType,
		dbPath:        initDBPath,
		redisEnable:   initRedisEnable,
		redisHost:     initRedisHost,
		redisPort:     initRedisPort,
		redisPassword: initRedisPassword,
		adminUser:     adminUser,
		adminPass:     adminPass,
		adminEmail:    adminEmail,
		port:          initPort,
		corsOrigin:    initCorsOrigin,
	}, nil
}

func gatherInteractiveConfig() (*initConfig, error) {
	reader := bufio.NewReader(os.Stdin)

	cfg := &initConfig{
		dbType:       "sqlite",
		dbPath:       "./data/user_management.db",
		redisEnable:  false,
		redisHost:    "localhost",
		redisPort:    6379,
		port:         8080,
		corsOrigin:   "http://localhost:3000",
	}

	fmt.Println("=== UMS Initialization ===")

	// 数据库类型
	fmt.Printf("Database type [%s]: ", cfg.dbType)
	input, _ := reader.ReadString('\n')
	input = strings.TrimSpace(input)
	if input != "" {
		cfg.dbType = input
	}

	// 数据库路径
	fmt.Printf("Database path [%s]: ", cfg.dbPath)
	input, _ = reader.ReadString('\n')
	input = strings.TrimSpace(input)
	if input != "" {
		cfg.dbPath = input
	}

	// Redis 启用
	fmt.Printf("Enable Redis? [y/N]: ")
	input, _ = reader.ReadString('\n')
	input = strings.TrimSpace(strings.ToLower(input))
	cfg.redisEnable = input == "y" || input == "yes"

	if cfg.redisEnable {
		fmt.Printf("Redis host [%s]: ", cfg.redisHost)
		input, _ = reader.ReadString('\n')
		input = strings.TrimSpace(input)
		if input != "" {
			cfg.redisHost = input
		}

		fmt.Printf("Redis port [%d]: ", cfg.redisPort)
		input, _ = reader.ReadString('\n')
		input = strings.TrimSpace(input)
		if input != "" {
			var port int
			fmt.Sscanf(input, "%d", &port)
			cfg.redisPort = port
		}

		fmt.Printf("Redis password (empty for none): ")
		input, _ = reader.ReadString('\n')
		input = strings.TrimSpace(input)
		cfg.redisPassword = input
	}

	// 管理员信息
	fmt.Printf("Admin username [admin]: ")
	input, _ = reader.ReadString('\n')
	input = strings.TrimSpace(input)
	if input != "" {
		cfg.adminUser = input
	} else {
		cfg.adminUser = "admin"
	}

	fmt.Print("Admin password: ")
	password, err := readPassword()
	fmt.Println()
	if err != nil {
		return nil, fmt.Errorf("read password failed: %w", err)
	}
	if len(password) < 8 {
		return nil, fmt.Errorf("password must be at least 8 characters")
	}
	cfg.adminPass = password

	fmt.Printf("Admin email [%s]: ", cfg.adminEmail)
	input, _ = reader.ReadString('\n')
	input = strings.TrimSpace(input)
	if input != "" {
		cfg.adminEmail = input
	} else if cfg.adminEmail == "" {
		cfg.adminEmail = "admin@example.com"
	}

	// 服务器端口
	fmt.Printf("Server port [%d]: ", cfg.port)
	input, _ = reader.ReadString('\n')
	input = strings.TrimSpace(input)
	if input != "" {
		var port int
		fmt.Sscanf(input, "%d", &port)
		cfg.port = port
	}

	// CORS 域名
	fmt.Printf("CORS origin [%s]: ", cfg.corsOrigin)
	input, _ = reader.ReadString('\n')
	input = strings.TrimSpace(input)
	if input != "" {
		cfg.corsOrigin = input
	}

	return cfg, nil
}

func readPassword() (string, error) {
	intrFd := int(os.Stdin.Fd())
	if term.IsTerminal(intrFd) {
		password, err := term.ReadPassword(intrFd)
		if err != nil {
			return "", err
		}
		return string(password), nil
	}
	// 非终端模式，使用普通输入
	reader := bufio.NewReader(os.Stdin)
	input, _ := reader.ReadString('\n')
	return strings.TrimSpace(input), nil
}

func generateSecret(length int) string {
	bytes := make([]byte, length)
	rand.Read(bytes)
	return hex.EncodeToString(bytes)
}

func createDataDirectory(cfg *initConfig) error {
	var dir string
	if cfg.dbType == "sqlite" {
		dir = filepath.Dir(cfg.dbPath)
		if dir == "." || dir == "" {
			dir = "./data"
		}
	} else {
		dir = "./data"
	}

	if dir == "" || dir == "." {
		return nil
	}

	return os.MkdirAll(dir, 0755)
}

func getConfigPath() string {
	return "./config.yaml"
}

func getEnvPath() string {
	return "./.env"
}

func createConfigFiles(cfg *initConfig) error {
	// 创建 .env 文件
	envContent := fmt.Sprintf(`# Auto-generated by ums init
# DO NOT COMMIT THIS FILE

# JWT Configuration
JWT_SECRET=%s
JWT_REFRESH_SECRET=%s

# Bootstrap secret for admin initialization
BOOTSTRAP_SECRET=%s

# Database
DATABASE_PATH=%s

# Admin credentials
DEFAULT_ADMIN_EMAIL=%s
DEFAULT_ADMIN_PASSWORD=%s

# Redis
REDIS_ENABLED=%t
REDIS_HOST=%s
REDIS_PORT=%d
REDIS_PASSWORD=%s

# CORS
CORS_ALLOWED_ORIGINS=%s

# Server
SERVER_PORT=%d
GIN_MODE=release
`,
		cfg.jwtSecret,
		cfg.jwtSecret, // refresh secret same as access for simplicity
		cfg.bootstrapSecret,
		cfg.dbPath,
		cfg.adminEmail,
		cfg.adminPass,
		cfg.redisEnable,
		cfg.redisHost,
		cfg.redisPort,
		cfg.redisPassword,
		cfg.corsOrigin,
		cfg.port,
	)

	if err := os.WriteFile(getEnvPath(), []byte(envContent), 0600); err != nil {
		return err
	}
	fmt.Printf("Created: %s\n", getEnvPath())

	// 创建 config.yaml
	configYAML := fmt.Sprintf(`server:
  port: %d
  mode: release
  host: 0.0.0.0

database:
  type: %s
  dbname: "%s"

redis:
  enabled: %t
  host: "%s"
  port: %d
  password: "%s"
  db: 0

jwt:
  secret: "%s"
  access_token_expire_minutes: 120
  refresh_token_expire_days: 7

cors:
  allowed_origins:
    - "%s"

default:
  admin_email: "%s"
  admin_password: "%s"
`,
		cfg.port,
		cfg.dbType,
		cfg.dbPath,
		cfg.redisEnable,
		cfg.redisHost,
		cfg.redisPort,
		cfg.redisPassword,
		cfg.jwtSecret,
		cfg.corsOrigin,
		cfg.adminEmail,
		cfg.adminPass,
	)

	if err := os.WriteFile(getConfigPath(), []byte(configYAML), 0644); err != nil {
		return err
	}
	fmt.Printf("Created: %s\n", getConfigPath())

	return nil
}

func runMigrations(cfg *initConfig) error {
	fmt.Println("\nRunning database migrations...")

	// 创建一个临时 config 对象用于迁移
	tempCfg := &config.Config{
		Database: config.DatabaseConfig{
			DBName: cfg.dbPath,
		},
		Default: config.DefaultConfig{
			AdminEmail:    cfg.adminEmail,
			AdminPassword: cfg.adminPass,
		},
	}

	db, err := database.NewDB(tempCfg)
	if err != nil {
		return fmt.Errorf("connect database failed: %w", err)
	}

	if err := db.AutoMigrate(tempCfg); err != nil {
		return fmt.Errorf("auto migrate failed: %w", err)
	}

	fmt.Println("Database migrations completed.")
	return nil
}

func createAdminUser(cfg *initConfig) error {
	fmt.Println("\nCreating admin user...")

	// 验证 Redis 连接（如果启用）
	if cfg.redisEnable {
		addr := net.JoinHostPort(cfg.redisHost, fmt.Sprintf("%d", cfg.redisPort))
		conn, err := net.Dial("tcp", addr)
		if err != nil {
			fmt.Printf("Warning: Redis connection failed: %v\n", err)
			fmt.Println("System will run without Redis caching.")
		} else {
			conn.Close()
			fmt.Println("Redis connection verified.")
		}
	}

	// 密码验证已在 gatherConfig 中完成
	fmt.Println("Admin user creation skipped (handled by migrations).")
	return nil
}
