// Package config 读取并校验 API 服务运行所需的环境变量。
package config

import (
	"fmt"
	"net/url"
	"os"
	"strconv"
	"strings"

	"github.com/joho/godotenv"
)

// Config 汇总数据库、缓存、认证、腾讯云 COS 和本地媒体处理配置。
type Config struct {
	AppEnv                 string
	Debug                  bool
	ServerAddress          string
	DatabaseURL            string
	RedisAddress           string
	RedisPassword          string
	RedisDB                int
	AsynqRedisDB           int
	CORSOrigins            []string
	StaticDirectory        string
	JWTSecretKey           string
	JWTAccessMinutes       int
	JWTRefreshHours        int
	BootstrapAdminUsername string
	BootstrapAdminPassword string
	Argon2Time             uint32
	Argon2Memory           uint32
	Argon2Parallelism      uint8
	Argon2HashLength       uint32
	Argon2SaltLength       uint32
	EncryptionKeyVersion   string
	EncryptionKey          string
	COSSecretID            string
	COSSecretKey           string
	COSBucket              string
	COSRegion              string
	COSEndpoint            string
	COSPublicBaseURL       string
	COSMaxImageSizeMB      int
	COSMaxVideoSizeMB      int
	COSMaxAudioSizeMB      int
	AIWorkerConcurrency    int
	AIPollIntervalSeconds  int
	AIHTTPMaxConnections   int
	FFmpegPath             string
	FFprobePath            string
	PythonPath             string
	ASRScriptPath          string
}

// Load 从本地环境文件和进程环境读取配置，并校验数值范围。
func Load() (Config, error) {
	_ = godotenv.Load()

	databasePort, err := envInt("DATABASE_PORT", 25432)
	if err != nil {
		return Config{}, err
	}
	redisPort, err := envInt("REDIS_PORT", 26379)
	if err != nil {
		return Config{}, err
	}
	redisDB, err := envInt("REDIS_DB", 0)
	if err != nil {
		return Config{}, err
	}
	asynqRedisDB, err := envInt("ASYNQ_REDIS_DB", 1)
	if err != nil {
		return Config{}, err
	}
	jwtAccessMinutes, err := envInt("JWT_ACCESS_TOKEN_EXPIRE_MINUTES", 60)
	if err != nil {
		return Config{}, err
	}
	jwtRefreshHours, err := envInt("JWT_REFRESH_TOKEN_EXPIRE_HOURS", 168)
	if err != nil {
		return Config{}, err
	}
	argon2Time, err := envInt("ARGON2_TIME_COST", 2)
	if err != nil {
		return Config{}, err
	}
	argon2Memory, err := envInt("ARGON2_MEMORY_COST", 19456)
	if err != nil {
		return Config{}, err
	}
	argon2Parallelism, err := envInt("ARGON2_PARALLELISM", 1)
	if err != nil {
		return Config{}, err
	}
	argon2HashLength, err := envInt("ARGON2_HASH_LENGTH", 32)
	if err != nil {
		return Config{}, err
	}
	argon2SaltLength, err := envInt("ARGON2_SALT_LENGTH", 16)
	if err != nil {
		return Config{}, err
	}
	cosMaxImageSizeMB, err := envInt("COS_MAX_IMAGE_SIZE_MB", 20)
	if err != nil {
		return Config{}, err
	}
	cosMaxVideoSizeMB, err := envInt("COS_MAX_VIDEO_SIZE_MB", 100)
	if err != nil {
		return Config{}, err
	}
	cosMaxAudioSizeMB, err := envInt("COS_MAX_AUDIO_SIZE_MB", 30)
	if err != nil {
		return Config{}, err
	}
	aiWorkerConcurrency, err := envInt("AI_WORKER_CONCURRENCY", 100)
	if err != nil {
		return Config{}, err
	}
	aiPollIntervalSeconds, err := envInt("AI_POLL_INTERVAL_SECONDS", 10)
	if err != nil {
		return Config{}, err
	}
	aiHTTPMaxConnections, err := envInt("AI_HTTP_MAX_CONNECTIONS", 200)
	if err != nil {
		return Config{}, err
	}
	if cosMaxImageSizeMB < 1 || cosMaxVideoSizeMB < 1 || cosMaxAudioSizeMB < 1 {
		return Config{}, fmt.Errorf("COS 文件大小限制必须为正整数")
	}
	if aiWorkerConcurrency < 1 || aiWorkerConcurrency > 1000 {
		return Config{}, fmt.Errorf("AI_WORKER_CONCURRENCY 必须在 1 至 1000 之间")
	}
	if aiPollIntervalSeconds < 2 || aiPollIntervalSeconds > 300 {
		return Config{}, fmt.Errorf("AI_POLL_INTERVAL_SECONDS 必须在 2 至 300 之间")
	}
	if aiHTTPMaxConnections < 10 || aiHTTPMaxConnections > 5000 {
		return Config{}, fmt.Errorf("AI_HTTP_MAX_CONNECTIONS 必须在 10 至 5000 之间")
	}
	debug, err := strconv.ParseBool(env("DEBUG", "true"))
	if err != nil {
		return Config{}, fmt.Errorf("DEBUG 必须是布尔值: %w", err)
	}

	databaseURL := strings.TrimSpace(os.Getenv("DATABASE_URL"))
	if databaseURL == "" {
		databaseURL = buildDatabaseURL(databasePort)
	} else if parsed, parseErr := url.Parse(databaseURL); parseErr == nil {
		query := parsed.Query()
		if query.Get("TimeZone") == "" {
			query.Set("TimeZone", "Asia/Shanghai")
		}
		parsed.RawQuery = query.Encode()
		databaseURL = parsed.String()
	}

	return Config{
		AppEnv:                 env("APP_ENV", "development"),
		Debug:                  debug,
		ServerAddress:          env("SERVER_ADDRESS", ":8900"),
		DatabaseURL:            databaseURL,
		RedisAddress:           fmt.Sprintf("%s:%d", env("REDIS_HOST", "127.0.0.1"), redisPort),
		RedisPassword:          os.Getenv("REDIS_PASSWORD"),
		RedisDB:                redisDB,
		AsynqRedisDB:           asynqRedisDB,
		CORSOrigins:            splitCSV(env("CORS_ORIGINS", "http://localhost:5500,http://localhost:5501")),
		StaticDirectory:        env("STATIC_DIRECTORY", "static"),
		JWTSecretKey:           env("JWT_SECRET_KEY", "replace-with-a-strong-random-secret"),
		JWTAccessMinutes:       jwtAccessMinutes,
		JWTRefreshHours:        jwtRefreshHours,
		BootstrapAdminUsername: env("ADMIN_BOOTSTRAP_USERNAME", "admin"),
		BootstrapAdminPassword: os.Getenv("ADMIN_BOOTSTRAP_PASSWORD"),
		Argon2Time:             uint32(argon2Time),
		Argon2Memory:           uint32(argon2Memory),
		Argon2Parallelism:      uint8(argon2Parallelism),
		Argon2HashLength:       uint32(argon2HashLength),
		Argon2SaltLength:       uint32(argon2SaltLength),
		EncryptionKeyVersion:   env("CONFIG_ENCRYPTION_KEY_VERSION", "v1"),
		EncryptionKey:          os.Getenv("CONFIG_ENCRYPTION_KEY"),
		COSSecretID:            os.Getenv("COS_SECRET_ID"),
		COSSecretKey:           os.Getenv("COS_SECRET_KEY"),
		COSBucket:              os.Getenv("COS_BUCKET"),
		COSRegion:              env("COS_REGION", "ap-chengdu"),
		COSEndpoint:            os.Getenv("COS_ENDPOINT"),
		COSPublicBaseURL:       strings.TrimRight(os.Getenv("COS_PUBLIC_BASE_URL"), "/"),
		COSMaxImageSizeMB:      cosMaxImageSizeMB,
		COSMaxVideoSizeMB:      cosMaxVideoSizeMB,
		COSMaxAudioSizeMB:      cosMaxAudioSizeMB,
		AIWorkerConcurrency:    aiWorkerConcurrency,
		AIPollIntervalSeconds:  aiPollIntervalSeconds,
		AIHTTPMaxConnections:   aiHTTPMaxConnections,
		FFmpegPath:             env("FFMPEG_PATH", "ffmpeg"),
		FFprobePath:            env("FFPROBE_PATH", "ffprobe"),
		PythonPath:             env("PYTHON_PATH", "python3"),
		ASRScriptPath:          env("ASR_SCRIPT_PATH", "workers/transcribe.py"),
	}, nil
}

func buildDatabaseURL(port int) string {
	credentials := url.UserPassword(
		env("DATABASE_USER", "postgres"),
		env("DATABASE_PASSWORD", "juchuang_dev"),
	).String()
	return fmt.Sprintf(
		"postgres://%s@%s:%d/%s?sslmode=disable&TimeZone=Asia/Shanghai",
		credentials,
		env("DATABASE_HOST", "127.0.0.1"),
		port,
		url.PathEscape(env("DATABASE_NAME", "juchuang_factory")),
	)
}

func env(key, fallback string) string {
	if value := strings.TrimSpace(os.Getenv(key)); value != "" {
		return value
	}
	return fallback
}

func envInt(key string, fallback int) (int, error) {
	value := strings.TrimSpace(os.Getenv(key))
	if value == "" {
		return fallback, nil
	}
	parsed, err := strconv.Atoi(value)
	if err != nil {
		return 0, fmt.Errorf("%s 必须是整数: %w", key, err)
	}
	return parsed, nil
}

func splitCSV(value string) []string {
	items := strings.Split(value, ",")
	result := make([]string, 0, len(items))
	for _, item := range items {
		if item = strings.TrimSpace(item); item != "" {
			result = append(result, item)
		}
	}
	return result
}
