package config

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

type Config struct {
	HTTPPort               int
	WorkerHTTPPort         int
	MongoHost              string
	MongoPort              int
	MongoUsername          string
	MongoPassword          string
	MongoAuthSource        string
	BusinessMongoDatabase  string
	SchedulerMongoDatabase string
	RedisAddr              string
	RedisUsername          string
	RedisPassword          string
}

func Load() Config {
	loadEnvFiles()

	return Config{
		HTTPPort:               getenvInt("HTTP_PORT", 10090),
		WorkerHTTPPort:         getenvInt("WORKER_HTTP_PORT", 10091),
		MongoHost:              getenv("MONGO_HOST", "127.0.0.1"),
		MongoPort:              getenvInt("MONGO_PORT", 27017),
		MongoUsername:          getenv("MONGO_USERNAME", ""),
		MongoPassword:          getenv("MONGO_PASSWORD", ""),
		MongoAuthSource:        getenv("MONGO_AUTHSOURCE", "admin"),
		BusinessMongoDatabase:  getenv("MONGO_DATABASE", "openim_v3"),
		SchedulerMongoDatabase: getenv("SCHEDULER_MONGO_DATABASE", "scheduler_center"),
		RedisAddr:              getenv("REDIS_ADDR", ""),
		RedisUsername:          getenv("REDIS_USERNAME", ""),
		RedisPassword:          getenv("REDIS_PASSWORD", ""),
	}
}

func loadEnvFiles() {
	loadEnvFile(".env")

	if envName := currentEnvName(); envName != "" {
		loadEnvFile(".env." + envName)
	}

	loadEnvFile(".env.local")
}

func currentEnvName() string {
	for _, key := range []string{"APP_ENV", "GO_ENV", "ENV"} {
		if value := strings.TrimSpace(os.Getenv(key)); value != "" {
			return value
		}
	}

	return ""
}

func loadEnvFile(name string) {
	file, err := os.Open(filepath.Clean(name))
	if err != nil {
		return
	}
	defer file.Close()

	scanner := bufio.NewScanner(file)
	for scanner.Scan() {
		line := strings.TrimSpace(scanner.Text())
		if line == "" || strings.HasPrefix(line, "#") {
			continue
		}

		key, value, ok := strings.Cut(line, "=")
		if !ok {
			continue
		}

		key = strings.TrimSpace(key)
		value = strings.TrimSpace(value)
		if key == "" {
			continue
		}

		if _, exists := os.LookupEnv(key); exists {
			continue
		}

		_ = os.Setenv(key, value)
	}
}

func (c Config) MongoURI() string {
	return fmt.Sprintf(
		"mongodb://%s:%s@%s:%d/?authSource=%s",
		c.MongoUsername,
		c.MongoPassword,
		c.MongoHost,
		c.MongoPort,
		c.MongoAuthSource,
	)
}

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

func getenvInt(key string, fallback int) int {
	raw := getenv(key, "")
	if raw == "" {
		return fallback
	}

	value, err := strconv.Atoi(raw)
	if err != nil {
		return fallback
	}

	return value
}
