package config

import (
	"context"
	"fmt"
	"os"
	"strconv"
	"time"

	"github.com/jackc/pgx/v5/pgxpool"
	"github.com/joho/godotenv"
)

// Config содержит конфигурацию приложения
type Config struct {
	// Database
	DatabaseURL string

	// Server
	ServerHost string
	ServerPort string
	AppEnv     string

	// JWT
	JWTSecret          string
	JWTAccessTokenTTL  time.Duration
	JWTRefreshTokenTTL time.Duration

	// CORS
	CORSAllowedOrigins []string
	CORSAllowedMethods []string
	CORSAllowedHeaders []string

	// Rate Limiting
	RateLimitRequestsPerMinute int
	RateLimitBurst             int

	// Matching Algorithm
	MatchingDefaultRadiusMeters int
	MatchingDefaultLimit        int
}

// Load загружает конфигурацию из переменных окружения
func Load() (*Config, error) {
	// Загружаем .env файл если он существует
	_ = godotenv.Load()

	cfg := &Config{
		DatabaseURL: getDatabaseURL(),
		ServerHost:  getEnv("APP_HOST", "0.0.0.0"),
		ServerPort:  getEnv("APP_PORT", "8080"),
		AppEnv:      getEnv("APP_ENV", "development"),

		JWTSecret:          getEnv("JWT_SECRET", "change_me_to_secure_random_string_min_32_chars"),
		JWTAccessTokenTTL:  parseDuration(getEnv("JWT_ACCESS_TOKEN_EXPIRY", "15m")),
		JWTRefreshTokenTTL: parseDuration(getEnv("JWT_REFRESH_TOKEN_EXPIRY", "168h")), // 7 days

		RateLimitRequestsPerMinute: getEnvInt("RATE_LIMIT_REQUESTS_PER_MINUTE", 60),
		RateLimitBurst:             getEnvInt("RATE_LIMIT_BURST", 10),

		MatchingDefaultRadiusMeters: getEnvInt("MATCHING_DEFAULT_RADIUS_METERS", 10000),
		MatchingDefaultLimit:        getEnvInt("MATCHING_DEFAULT_LIMIT", 20),
	}

	return cfg, nil
}

// NewDBPool создает новый пул соединений с БД
func NewDBPool(ctx context.Context, databaseURL string) (*pgxpool.Pool, error) {
	config, err := pgxpool.ParseConfig(databaseURL)
	if err != nil {
		return nil, fmt.Errorf("failed to parse database URL: %w", err)
	}

	// Настройка пула соединений
	config.MaxConns = 25
	config.MinConns = 5
	config.MaxConnLifetime = time.Hour
	config.MaxConnIdleTime = time.Minute * 30
	config.HealthCheckPeriod = time.Minute

	pool, err := pgxpool.NewWithConfig(ctx, config)
	if err != nil {
		return nil, fmt.Errorf("failed to create connection pool: %w", err)
	}

	// Проверка соединения
	if err := pool.Ping(ctx); err != nil {
		return nil, fmt.Errorf("failed to ping database: %w", err)
	}

	return pool, nil
}

// getDatabaseURL собирает DATABASE_URL из отдельных переменных или использует готовый
func getDatabaseURL() string {
	// Если задан DATABASE_URL, используем его
	if url := os.Getenv("DATABASE_URL"); url != "" {
		return url
	}

	// Иначе собираем из отдельных переменных
	user := getEnv("DB_USER", "volontery")
	password := getEnv("DB_PASSWORD", "volontery")
	host := getEnv("DB_HOST", "localhost")
	port := getEnv("DB_PORT", "5432")
	name := getEnv("DB_NAME", "volontery_db")
	sslmode := getEnv("DB_SSLMODE", "disable")

	return fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s",
		user, password, host, port, name, sslmode)
}

// getEnv получает переменную окружения или возвращает значение по умолчанию
func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}

// getEnvInt получает целочисленную переменную окружения
func getEnvInt(key string, defaultValue int) int {
	if value := os.Getenv(key); value != "" {
		if intVal, err := strconv.Atoi(value); err == nil {
			return intVal
		}
	}
	return defaultValue
}

// parseDuration парсит duration строку
func parseDuration(s string) time.Duration {
	d, err := time.ParseDuration(s)
	if err != nil {
		return 15 * time.Minute // default
	}
	return d
}
