package config

import (
	"encoding/json"
	"fmt"
	"os"
)

type ServerConfig struct {
	AppName               string     `json:"app_name"`
	ReadTimeoutSeconds    int        `json:"read_timeout_seconds"`
	WriteTimeoutSeconds   int        `json:"write_timeout_seconds"`
	IdleTimeoutSeconds    int        `json:"idle_timeout_seconds"`
	DisableStartupMessage bool       `json:"disable_startup_message"`
	Auth                  AuthConfig `json:"auth"`
	Mail                  MailConfig `json:"mail"`
	Db                    DbConfig   `json:"db_config"`
	RolesConfigPath       string     `json:"roles_config_path"`
}

type AuthConfig struct {
	Secret                    string `json:"secret"`
	Issuer                    string `json:"issuer"`
	AccessTokenExpiryMinutes  int    `json:"access_token_expiry_minutes"`
	RefreshTokenExpiryMinutes int    `json:"refresh_token_expiry_minutes"`
}

type MailConfig struct {
	Mode              string         `json:"mode"`
	From              string         `json:"from"`
	DebugDir          string         `json:"debug_dir"`
	TemplatesDir      string         `json:"templates_dir"`
	MailTemplatesDir  string         `json:"mail_templates_dir"`
	FrontendBaseURL   string         `json:"frontend_base_url"`
	ResetPasswordPath string         `json:"reset_password_path"`
	SMTP              SMTPMailConfig `json:"smtp"`
}

type SMTPMailConfig struct {
	Host     string `json:"host"`
	Port     int    `json:"port"`
	Username string `json:"username"`
	Password string `json:"password"`
}

type DbConfig struct {
	Driver string
	DSN    string
}

var Config *ServerConfig = nil

func GetConfig() (*ServerConfig, error) {
	if Config == nil {
		var err error
		Config, err = loadConfig()
		if err != nil {
			fmt.Printf("Failed to load config: %v\n", err)
			return nil, err
		}
	}
	return Config, nil
}

func envOrDefault(key, defaultValue string) string {
	if value, exists := os.LookupEnv(key); exists {
		return value
	}
	return defaultValue
}

func loadConfig() (*ServerConfig, error) {
	path := envOrDefault("CONFIG_PATH", "configs/config.json")

	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("read config: %w", err)
	}
	var cfg ServerConfig
	if err := json.Unmarshal(data, &cfg); err != nil {
		return nil, fmt.Errorf("parse config: %w", err)
	}
	if secret := os.Getenv("AUTH_SECRET"); secret != "" {
		cfg.Auth.Secret = secret
	}
	if cfg.Auth.Secret == "" {
		return nil, fmt.Errorf("auth.secret must be set")
	}
	if cfg.Auth.AccessTokenExpiryMinutes <= 0 {
		return nil, fmt.Errorf("auth.access_token_expiry_minutes must be greater than zero")
	}
	if cfg.Auth.RefreshTokenExpiryMinutes <= 0 {
		return nil, fmt.Errorf("auth.refresh_token_expiry_minutes must be greater than zero")
	}
	if cfg.Mail.Mode == "" {
		cfg.Mail.Mode = "file"
	}
	if cfg.Mail.MailTemplatesDir == "" {
		cfg.Mail.MailTemplatesDir = "templates/mailTemplates"
	}
	if cfg.Mail.ResetPasswordPath == "" {
		cfg.Mail.ResetPasswordPath = "/#reset-password"
	}
	if cfg.Mail.Mode != "smtp" && cfg.Mail.Mode != "file" {
		return nil, fmt.Errorf("mail.mode must be either smtp or file")
	}
	if cfg.Mail.From == "" {
		return nil, fmt.Errorf("mail.from must be set")
	}
	if cfg.Mail.Mode == "smtp" {
		if cfg.Mail.SMTP.Host == "" {
			return nil, fmt.Errorf("mail.smtp.host must be set when mail.mode=smtp")
		}
		if cfg.Mail.SMTP.Port <= 0 {
			return nil, fmt.Errorf("mail.smtp.port must be greater than zero when mail.mode=smtp")
		}
	} else if cfg.Mail.DebugDir == "" {
		cfg.Mail.DebugDir = "data/mail-debug"
	}

	cfg.Db = DbConfig{
		Driver: envOrDefault("DB_driver", "sqlite"),
		DSN:    envOrDefault("DB_dsn", "file:./data/data.db?_foreign_keys=on"),
	}

	return &cfg, nil
}
