package config

import (
	"net/url"
	"os"
	"path/filepath"
	"strconv"
	"strings"

	"github.com/joho/godotenv"
)

// Config is populated entirely from environment variables (optionally set via .env — see Load).
type Config struct {
	AppEnv     string
	AdminToken string
	AuthAPIURL string
	DatabaseDSN string

	// 进程与对外访问（管理后台「系统状态」展示）
	HTTPListenAddr     string
	PublicAPIBaseURL   string

	// Redis（可选，用于缓存时配置；未启用则不连接）
	RedisEnabled  bool
	RedisAddr     string
	RedisPassword string
	RedisDB       int
	RedisEnv      string

	RabbitMQEnabled bool
	RabbitMQURL     string
	RabbitMQEnv     string
}

// App environment: affects defaults when DATABASE_DSN / RABBITMQ_ENV are omitted.
// APP_ENV=production → prod DB default, RABBITMQ_ENV default prod
// Otherwise → development defaults (test DB, rabbit dev).
const (
	EnvDevelopment = "development"
	EnvProduction  = "production"
)

// Built-in DSN fallbacks when DATABASE_DSN is empty.
const (
	TestDSN = "mengyastore-test:mengyastore-test@tcp(10.1.1.100:3306)/mengyastore-test?charset=utf8mb4&parseTime=True&loc=Local"
	ProdDSN = "mengyastore:mengyastore@tcp(192.168.1.100:3306)/mengyastore?charset=utf8mb4&parseTime=True&loc=Local"

	DefaultRabbitMQHost    = "10.1.1.233"
	DefaultRabbitMQPort    = "5672"
	DefaultRabbitVHost     = "mengyastore-dev"
	DefaultRabbitMQUser    = "admin"
	ProdRabbitMQHost       = "192.168.1.100"
	DefaultRabbitVHostProd = "mengyastore-prod"

	// Redis：与 MySQL 同网段；未设置 REDIS_ADDR / REDIS_PASSWORD 时按 APP_ENV 填入
	TestRedisAddr = "10.1.1.100:6379"
	ProdRedisAddr = "192.168.1.100:6379"
	// 内网默认口令（可用环境变量 REDIS_PASSWORD 覆盖）
	DefaultRedisPassword = "tyh@19900420"
)

// Load reads optional .env file(s) then builds Config from the process environment.
//
// Dotenv resolution order:
//  1. File named by ENV_FILE (if set)
//  2. .env in current working directory
//
// Variables (all optional unless noted):
//
//	APP_ENV               — development | production (default: development)
//	ADMIN_TOKEN           — admin API token (default: changeme)
//	AUTH_API_URL          — SproutGate base URL
//	DATABASE_DSN          — MySQL DSN; if empty, uses TestDSN or ProdDSN from APP_ENV
//	RABBITMQ_ENABLED      — true/false
//	RABBITMQ_URL          — full amqp URL
//	RABBITMQ_ENV          — dev | prod (default from APP_ENV)
//	RABBITMQ_PASSWORD     — if RABBITMQ_URL empty but RABBITMQ_ENABLED, builds URL with host/vhost defaults
//
//	HTTP_LISTEN_ADDR      — 进程监听，默认 :8080
//	PUBLIC_API_BASE_URL   — 对外 API 基地址（反向代理场景）
//
//	REDIS_ENABLED         — 默认 true；显式 false/0/off 则关闭
//	REDIS_ADDR            — 默认 development→TestRedisAddr，production→ProdRedisAddr
//	REDIS_PASSWORD        — 默认 DefaultRedisPassword（建议生产用环境变量覆盖）
//	REDIS_DB              — 逻辑库编号，默认 1
//	REDIS_ENV             — dev|prod（展示用 Key 前缀环境）
func Load() (*Config, error) {
	loadDotenv()

	appEnv := normalizeAppEnv(os.Getenv("APP_ENV"))

	cfg := &Config{
		AppEnv:      appEnv,
		AdminToken:  strings.TrimSpace(os.Getenv("ADMIN_TOKEN")),
		AuthAPIURL:  strings.TrimSpace(os.Getenv("AUTH_API_URL")),
		DatabaseDSN: strings.TrimSpace(os.Getenv("DATABASE_DSN")),
		RabbitMQURL: strings.TrimSpace(os.Getenv("RABBITMQ_URL")),
	}

	if cfg.AdminToken == "" {
		cfg.AdminToken = "changeme"
	}

	if cfg.DatabaseDSN == "" {
		if appEnv == EnvProduction {
			cfg.DatabaseDSN = ProdDSN
		} else {
			cfg.DatabaseDSN = TestDSN
		}
	}

	if v := os.Getenv("RABBITMQ_ENABLED"); v != "" {
		cfg.RabbitMQEnabled = v == "true" || v == "1"
	}

	cfg.RabbitMQEnv = strings.TrimSpace(os.Getenv("RABBITMQ_ENV"))
	if cfg.RabbitMQEnv == "" {
		if appEnv == EnvProduction {
			cfg.RabbitMQEnv = "prod"
		} else {
			cfg.RabbitMQEnv = "dev"
		}
	}

	if cfg.RabbitMQURL == "" && cfg.RabbitMQEnabled {
		cfg.RabbitMQURL = composeRabbitMQURL(cfg)
	}

	if v := os.Getenv("HTTP_LISTEN_ADDR"); v != "" {
		cfg.HTTPListenAddr = strings.TrimSpace(v)
	}
	if cfg.HTTPListenAddr == "" {
		cfg.HTTPListenAddr = ":8080"
	}
	cfg.PublicAPIBaseURL = strings.TrimSpace(os.Getenv("PUBLIC_API_BASE_URL"))

	cfg.RedisEnabled = redisEnabledFromEnv(os.Getenv("REDIS_ENABLED"))
	cfg.RedisAddr = strings.TrimSpace(os.Getenv("REDIS_ADDR"))
	cfg.RedisPassword = os.Getenv("REDIS_PASSWORD")
	if v := os.Getenv("REDIS_DB"); v != "" {
		if n, err := strconv.Atoi(v); err == nil {
			cfg.RedisDB = n
		}
	}
	cfg.RedisEnv = strings.TrimSpace(os.Getenv("REDIS_ENV"))
	if cfg.RedisEnv == "" {
		if appEnv == EnvProduction {
			cfg.RedisEnv = "prod"
		} else {
			cfg.RedisEnv = "dev"
		}
	}

	if cfg.RedisEnabled {
		if cfg.RedisAddr == "" {
			if appEnv == EnvProduction {
				cfg.RedisAddr = ProdRedisAddr
			} else {
				cfg.RedisAddr = TestRedisAddr
			}
		}
		if cfg.RedisPassword == "" {
			cfg.RedisPassword = DefaultRedisPassword
		}
		if cfg.RedisDB == 0 {
			cfg.RedisDB = 1
		}
	}

	return cfg, nil
}

// redisEnabledFromEnv defaults to true unless explicitly turned off.
func redisEnabledFromEnv(v string) bool {
	s := strings.ToLower(strings.TrimSpace(v))
	if s == "false" || s == "0" || s == "no" || s == "off" {
		return false
	}
	if s == "true" || s == "1" || s == "yes" || s == "on" {
		return true
	}
	return true
}

func loadDotenv() {
	if f := strings.TrimSpace(os.Getenv("ENV_FILE")); f != "" {
		_ = godotenv.Load(f)
		return
	}
	// Standard local file; ignore missing.
	_ = godotenv.Load(filepath.Clean(".env"))
}

func normalizeAppEnv(s string) string {
	switch strings.ToLower(strings.TrimSpace(s)) {
	case "production", "prod":
		return EnvProduction
	default:
		return EnvDevelopment
	}
}

func composeRabbitMQURL(cfg *Config) string {
	pass := os.Getenv("RABBITMQ_PASSWORD")
	if pass == "" {
		return ""
	}
	host := os.Getenv("RABBITMQ_HOST")
	port := os.Getenv("RABBITMQ_PORT")
	user := os.Getenv("RABBITMQ_USER")
	vhost := os.Getenv("RABBITMQ_VHOST")
	if host == "" {
		if cfg.RabbitMQEnv == "prod" {
			host = ProdRabbitMQHost
		} else {
			host = DefaultRabbitMQHost
		}
	}
	if port == "" {
		port = DefaultRabbitMQPort
	}
	if user == "" {
		user = DefaultRabbitMQUser
	}
	if vhost == "" {
		if cfg.RabbitMQEnv == "prod" {
			vhost = DefaultRabbitVHostProd
		} else {
			vhost = DefaultRabbitVHost
		}
	}
	var path string
	if vhost == "/" {
		path = "/%2F"
	} else {
		path = "/" + url.PathEscape(vhost)
	}
	u := url.URL{
		Scheme: "amqp",
		User:   url.UserPassword(user, pass),
		Host:   host + ":" + port,
		Path:   path,
	}
	return u.String()
}
