package config

import (
	"errors"
	"os"
	"strconv"
	"strings"
)

type Config struct {
	AppEnv                     string
	AppAddr                    string
	MySQLDSN                   string
	RedisAddr                  string
	RedisPassword              string
	RedisDB                    int
	JWTSecret                  string
	PaymentConfigEncryptionKey string
	FieldEncryptionKey         string
	FieldEncryptionLegacyKey   string
	ExternalUploadSecret       string
	ExternalUploadAllowedIPs   []string
	BootstrapAdminUsername     string
	BootstrapAdminPassword     string
	BootstrapAdminNickname     string
	Storage                    StorageConfig
	SMS                        SMSConfig
	Realname                   RealnameConfig
	Log                        LogConfig
	RateLimit                  RateLimitConfig
}

type StorageConfig struct {
	Endpoint        string
	Bucket          string
	AccessKeyID     string
	SecretAccessKey string
}

type SMSConfig struct {
	Provider                string
	AliyunAccessKeyID       string
	AliyunAccessKeySecret   string
	AliyunEndpoint          string
	AliyunSignName          string
	AliyunLoginTemplateCode string
}

type RealnameConfig struct {
	Provider           string
	CloudMarketURL     string
	CloudMarketAppCode string
}

type LogConfig struct {
	Level         string
	Dir           string
	EnableConsole bool
	EnableFile    bool
}

type RateLimitConfig struct {
	Enabled           bool
	RequestsPerMinute int
}

func Load() Config {
	return Config{
		AppEnv:                     getEnv("APP_ENV", "development"),
		AppAddr:                    getEnv("APP_ADDR", ":8080"),
		MySQLDSN:                   getEnv("MYSQL_DSN", "hfb:secret@tcp(127.0.0.1:3306)/hfb_sys?charset=utf8mb4&parseTime=True&loc=Local"),
		RedisAddr:                  getEnv("REDIS_ADDR", "127.0.0.1:6379"),
		RedisPassword:              getEnv("REDIS_PASSWORD", ""),
		RedisDB:                    getEnvInt("REDIS_DB", 0),
		JWTSecret:                  getEnv("JWT_SECRET", "change-me"),
		PaymentConfigEncryptionKey: getEnv("PAYMENT_CONFIG_ENCRYPTION_KEY", ""),
		FieldEncryptionKey:         getEnv("FIELD_ENCRYPTION_KEY", ""),
		// 旧密钥回退：生产环境必须显式设置（空 = 禁用回退，用于密钥轮换收敛）；
		// 非生产默认填历史硬编码密钥，兼容开发/测试库的存量密文。不能用 getEnv 的 fallback——
		// 那样生产删掉 env 会重新注入已泄露的硬编码密钥，破坏轮换闭环。
		FieldEncryptionLegacyKey: fieldEncryptionLegacyKey(getEnv("APP_ENV", "development")),
		ExternalUploadSecret:     getEnv("EXTERNAL_UPLOAD_SECRET", ""),
		ExternalUploadAllowedIPs: getEnvList("EXTERNAL_UPLOAD_ALLOWED_IPS"),
		BootstrapAdminUsername:   getEnv("ADMIN_BOOTSTRAP_USERNAME", ""),
		BootstrapAdminPassword:   getEnv("ADMIN_BOOTSTRAP_PASSWORD", ""),
		BootstrapAdminNickname:   getEnv("ADMIN_BOOTSTRAP_NICKNAME", "超级管理员"),
		Storage: StorageConfig{
			Endpoint:        getEnv("STORAGE_ENDPOINT", "http://localhost:9000"),
			Bucket:          getEnv("STORAGE_BUCKET", "hfb-sys"),
			AccessKeyID:     getEnv("STORAGE_ACCESS_KEY_ID", "minioadmin"),
			SecretAccessKey: getEnv("STORAGE_SECRET_ACCESS_KEY", "minioadmin"),
		},
		SMS: SMSConfig{
			Provider:                getEnv("SMS_PROVIDER", "mock"),
			AliyunAccessKeyID:       getEnv("ALIYUN_ACCESS_KEY_ID", ""),
			AliyunAccessKeySecret:   getEnv("ALIYUN_ACCESS_KEY_SECRET", ""),
			AliyunEndpoint:          getEnv("ALIYUN_SMS_ENDPOINT", "dysmsapi.aliyuncs.com"),
			AliyunSignName:          getEnv("ALIYUN_SMS_SIGN_NAME", ""),
			AliyunLoginTemplateCode: getEnv("ALIYUN_SMS_LOGIN_TEMPLATE_CODE", ""),
		},
		Realname: RealnameConfig{
			Provider:           getEnv("REALNAME_PROVIDER", "mock"),
			CloudMarketURL:     getEnv("REALNAME_CLOUDMARKET_URL", "https://sinocheck2.market.alicloudapi.com/fortest/ttttt"),
			CloudMarketAppCode: getEnv("REALNAME_CLOUDMARKET_APPCODE", ""),
		},
		Log: LogConfig{
			Level:         getEnv("LOG_LEVEL", "info"),
			Dir:           getEnv("LOG_DIR", "logs"),
			EnableConsole: getEnvBool("LOG_ENABLE_CONSOLE", true),
			EnableFile:    getEnvBool("LOG_ENABLE_FILE", true),
		},
		RateLimit: RateLimitConfig{
			Enabled:           getEnvBool("RATE_LIMIT_ENABLED", true),
			RequestsPerMinute: getEnvInt("RATE_LIMIT_REQUESTS_PER_MINUTE", 300),
		},
	}
}

func (c Config) ValidateProductionSecurity() error {
	if !IsProductionEnv(c.AppEnv) {
		return nil
	}
	if strings.TrimSpace(c.JWTSecret) == "" || isPlaceholder(c.JWTSecret) || len([]byte(c.JWTSecret)) < 32 {
		return errors.New("JWT_SECRET must be a non-default random value of at least 32 bytes in production")
	}
	keyLen := len([]byte(c.PaymentConfigEncryptionKey))
	if isPlaceholder(c.PaymentConfigEncryptionKey) || (keyLen != 16 && keyLen != 24 && keyLen != 32) {
		return errors.New("PAYMENT_CONFIG_ENCRYPTION_KEY must be 16, 24, or 32 bytes in production")
	}
	fieldKeyLen := len([]byte(c.FieldEncryptionKey))
	if c.FieldEncryptionKey == "" || isPlaceholder(c.FieldEncryptionKey) || (fieldKeyLen != 16 && fieldKeyLen != 24 && fieldKeyLen != 32) {
		return errors.New("FIELD_ENCRYPTION_KEY must be 16, 24, or 32 bytes in production")
	}
	legacyKeyLen := len([]byte(c.FieldEncryptionLegacyKey))
	if c.FieldEncryptionLegacyKey != "" && (isPlaceholder(c.FieldEncryptionLegacyKey) || (legacyKeyLen != 16 && legacyKeyLen != 24 && legacyKeyLen != 32)) {
		return errors.New("FIELD_ENCRYPTION_LEGACY_KEY must be empty or 16, 24, or 32 bytes in production")
	}
	if c.FieldEncryptionKey == c.FieldEncryptionLegacyKey {
		return errors.New("FIELD_ENCRYPTION_KEY must differ from FIELD_ENCRYPTION_LEGACY_KEY in production (set a new primary key to rotate)")
	}
	if c.BootstrapAdminPassword != "" && isPlaceholder(c.BootstrapAdminPassword) {
		return errors.New("ADMIN_BOOTSTRAP_PASSWORD must not use the example placeholder in production")
	}
	return nil
}

func getEnv(key, fallback string) string {
	value := os.Getenv(key)
	if value == "" {
		return fallback
	}
	return value
}

// historicFieldEncryptionKey 是迁移前 pkg/crypto 的硬编码密钥，仅用于解密历史存量密文。
const historicFieldEncryptionKey = "hfb-sys-2024-secret-key-32bytes!"

// fieldEncryptionLegacyKey 解析 FIELD_ENCRYPTION_LEGACY_KEY：
//   - 生产环境：必须显式设置，空表示禁用回退（密钥轮换收敛后删除 env 即关闭旧密钥）。
//     不能用硬编码默认值，否则轮换闭环不成立。
//   - 非生产环境：未设置时回退到历史硬编码密钥，兼容开发/测试库的存量密文（零配置）。
func fieldEncryptionLegacyKey(appEnv string) string {
	if IsProductionEnv(appEnv) {
		// 生产显式空 = 禁用；未设置也视为禁用。
		return os.Getenv("FIELD_ENCRYPTION_LEGACY_KEY")
	}
	if v := os.Getenv("FIELD_ENCRYPTION_LEGACY_KEY"); v != "" {
		return v
	}
	return historicFieldEncryptionKey
}

func getEnvInt(key string, fallback int) int {
	value := os.Getenv(key)
	if value == "" {
		return fallback
	}
	parsed, err := strconv.Atoi(value)
	if err != nil {
		return fallback
	}
	return parsed
}

func getEnvBool(key string, fallback bool) bool {
	value := os.Getenv(key)
	if value == "" {
		return fallback
	}
	parsed, err := strconv.ParseBool(value)
	if err != nil {
		return fallback
	}
	return parsed
}

func getEnvList(key string) []string {
	raw := os.Getenv(key)
	if raw == "" {
		return nil
	}
	parts := strings.Split(raw, ",")
	values := make([]string, 0, len(parts))
	for _, part := range parts {
		value := strings.TrimSpace(part)
		if value != "" {
			values = append(values, value)
		}
	}
	return values
}

func isPlaceholder(value string) bool {
	normalized := strings.ToLower(strings.TrimSpace(value))
	return normalized == "change-me" || strings.HasPrefix(normalized, "change-") || strings.Contains(normalized, "change-to-")
}

// IsProductionEnv 判断 AppEnv 是否为生产环境（与 ValidateProductionSecurity 同口径）。
func IsProductionEnv(appEnv string) bool {
	return strings.ToLower(strings.TrimSpace(appEnv)) == "production"
}
