package config

import (
	"fmt"
	"net"
	"os"
	"strconv"
	"time"

	mysqlDriver "github.com/go-sql-driver/mysql"
	"gopkg.in/yaml.v3"
)

type Config struct {
	Server        ServerConfig        `yaml:"server"`
	Database      DatabaseConfig      `yaml:"database"`
	Auth          AuthConfig          `yaml:"auth"`
	Pricing       PricingConfig       `yaml:"pricing"`
	Export        ExportConfig        `yaml:"export"`
	Alerts        AlertsConfig        `yaml:"alerts"`
	Notifications NotificationsConfig `yaml:"notifications"`
	Logging       LoggingConfig       `yaml:"logging"`
	Backup        BackupConfig        `yaml:"backup"`
}

type ServerConfig struct {
	Host         string        `yaml:"host"`
	Port         int           `yaml:"port"`
	Mode         string        `yaml:"mode"`
	ReadTimeout  time.Duration `yaml:"read_timeout"`
	WriteTimeout time.Duration `yaml:"write_timeout"`
}

type DatabaseConfig struct {
	Host            string        `yaml:"host"`
	Port            int           `yaml:"port"`
	Name            string        `yaml:"name"`
	User            string        `yaml:"user"`
	Password        string        `yaml:"password"`
	MaxOpenConns    int           `yaml:"max_open_conns"`
	MaxIdleConns    int           `yaml:"max_idle_conns"`
	ConnMaxLifetime time.Duration `yaml:"conn_max_lifetime"`
}

func (d *DatabaseConfig) DSN() string {
	cfg := mysqlDriver.NewConfig()
	cfg.User = d.User
	cfg.Passwd = d.Password
	cfg.Net = "tcp"
	cfg.Addr = net.JoinHostPort(d.Host, strconv.Itoa(d.Port))
	cfg.DBName = d.Name
	cfg.ParseTime = true
	cfg.Loc = time.Local
	cfg.Params = map[string]string{
		"charset": "utf8mb4",
	}
	return cfg.FormatDSN()
}

type AuthConfig struct {
	JWTSecret     string        `yaml:"jwt_secret"`
	TokenExpiry   time.Duration `yaml:"token_expiry"`
	RefreshExpiry time.Duration `yaml:"refresh_expiry"`
}

type PricingConfig struct {
	DefaultMethod       string `yaml:"default_method"`
	DefaultPeriodDays   int    `yaml:"default_period_days"`
	FreshnessGreenDays  int    `yaml:"freshness_green_days"`
	FreshnessYellowDays int    `yaml:"freshness_yellow_days"`
	FreshnessRedDays    int    `yaml:"freshness_red_days"`
	MinQuotesForMedian  int    `yaml:"min_quotes_for_median"`
	PopularityDecayDays int    `yaml:"popularity_decay_days"`
}

type ExportConfig struct {
	TempDir     string        `yaml:"temp_dir"`
	MaxFileAge  time.Duration `yaml:"max_file_age"`
	CompanyName string        `yaml:"company_name"`
}

type AlertsConfig struct {
	Enabled                  bool          `yaml:"enabled"`
	CheckInterval            time.Duration `yaml:"check_interval"`
	HighDemandThreshold      int           `yaml:"high_demand_threshold"`
	TrendingThresholdPercent int           `yaml:"trending_threshold_percent"`
}

type NotificationsConfig struct {
	EmailEnabled bool   `yaml:"email_enabled"`
	SMTPHost     string `yaml:"smtp_host"`
	SMTPPort     int    `yaml:"smtp_port"`
	SMTPUser     string `yaml:"smtp_user"`
	SMTPPassword string `yaml:"smtp_password"`
	FromAddress  string `yaml:"from_address"`
}

type LoggingConfig struct {
	Level    string `yaml:"level"`
	Format   string `yaml:"format"`
	Output   string `yaml:"output"`
	FilePath string `yaml:"file_path"`
}

type BackupConfig struct {
	Time string `yaml:"time"`
}

func Load(path string) (*Config, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("reading config file: %w", err)
	}

	var cfg Config
	if err := yaml.Unmarshal(data, &cfg); err != nil {
		return nil, fmt.Errorf("parsing config file: %w", err)
	}

	cfg.setDefaults()

	return &cfg, nil
}

func (c *Config) setDefaults() {
	if c.Server.Host == "" {
		c.Server.Host = "127.0.0.1"
	}
	if c.Server.Port == 0 {
		c.Server.Port = 8080
	}
	if c.Server.Mode == "" {
		c.Server.Mode = "release"
	}
	if c.Server.ReadTimeout == 0 {
		c.Server.ReadTimeout = 30 * time.Second
	}
	if c.Server.WriteTimeout == 0 {
		c.Server.WriteTimeout = 30 * time.Second
	}

	if c.Database.Port == 0 {
		c.Database.Port = 3306
	}
	if c.Database.MaxOpenConns == 0 {
		c.Database.MaxOpenConns = 25
	}
	if c.Database.MaxIdleConns == 0 {
		c.Database.MaxIdleConns = 5
	}
	if c.Database.ConnMaxLifetime == 0 {
		c.Database.ConnMaxLifetime = 5 * time.Minute
	}

	if c.Auth.TokenExpiry == 0 {
		c.Auth.TokenExpiry = 24 * time.Hour
	}
	if c.Auth.RefreshExpiry == 0 {
		c.Auth.RefreshExpiry = 7 * 24 * time.Hour
	}

	if c.Pricing.DefaultMethod == "" {
		c.Pricing.DefaultMethod = "weighted_median"
	}
	if c.Pricing.DefaultPeriodDays == 0 {
		c.Pricing.DefaultPeriodDays = 90
	}
	if c.Pricing.FreshnessGreenDays == 0 {
		c.Pricing.FreshnessGreenDays = 30
	}
	if c.Pricing.FreshnessYellowDays == 0 {
		c.Pricing.FreshnessYellowDays = 60
	}
	if c.Pricing.FreshnessRedDays == 0 {
		c.Pricing.FreshnessRedDays = 90
	}
	if c.Pricing.MinQuotesForMedian == 0 {
		c.Pricing.MinQuotesForMedian = 3
	}

	if c.Logging.Level == "" {
		c.Logging.Level = "info"
	}
	if c.Logging.Format == "" {
		c.Logging.Format = "json"
	}
	if c.Logging.Output == "" {
		c.Logging.Output = "stdout"
	}

	if c.Backup.Time == "" {
		c.Backup.Time = "00:00"
	}
}

func (c *Config) Address() string {
	return fmt.Sprintf("%s:%d", c.Server.Host, c.Server.Port)
}
