package config

import (
	"fmt"
	"os"
	"strings" // Added for PreviewTLD validation

	"gopkg.in/yaml.v3"
)

// Config holds application configuration
type Config struct {
	Server       *Server                      `yaml:"server"`
	Database     *Database                    `yaml:"database"`
	Auth         *Auth                        `yaml:"auth"`
	Providers    map[string]map[string]string `yaml:"providers"`
	Debug        bool                         `yaml:"debug"`
	LocalPreview bool                         `yaml:"local_preview"` // For development/testing only - use false for production
	PreviewTLD   string                       `yaml:"preview_tld"`
	BuildkitHost string                       `yaml:"buildkit_host"`
	ReistryUrl   string                       `yaml:"registry_url"` // URL of the Docker registry
}

func (c *Config) UnmarshalYAML(unmarshal func(interface{}) error) error {
	type plain Config
	err := unmarshal((*plain)(c))
	if err != nil {
		return err
	}

	// Set default preview TLD if not specified
	if c.PreviewTLD == "" {
		c.PreviewTLD = "home.local"
	}

	// Set default Buildkit host if not specified
	if c.BuildkitHost == "" {
		c.BuildkitHost = "unix:///run/buildkit/buildkitd.sock"
	}

	return nil
}

// Validate performs a comprehensive validation of the configuration.
func (c *Config) Validate() error {
	if c.Server == nil {
		return fmt.Errorf("server configuration block is required")
	}
	if err := c.Server.Validate(); err != nil {
		return fmt.Errorf("server config validation failed: %w", err)
	}

	if c.Database == nil {
		return fmt.Errorf("database configuration block is required")
	}
	if err := c.Database.Validate(); err != nil {
		return fmt.Errorf("database config validation failed: %w", err)
	}

	if c.Auth == nil {
		return fmt.Errorf("auth configuration block is required")
	}
	if err := c.Auth.Validate(); err != nil {
		return fmt.Errorf("auth config validation failed: %w", err)
	}

	if len(c.Providers) == 0 { // Corrected: Removed redundant nil check
		return fmt.Errorf("at least one provider configuration is required in 'providers' block")
	}
	for providerName, providerConfig := range c.Providers {
		if len(providerConfig) == 0 {
			return fmt.Errorf("provider '%s' configuration is empty", providerName)
		}
	}

	return nil
}

// Server holds server configuration
type Server struct {
	Host string     `yaml:"host"`
	Port int        `yaml:"port"`
	Tls  *TlsConfig `yaml:"tls"`
}

func (s *Server) UnmarshalYAML(unmarshal func(interface{}) error) error {
	type plain Server
	err := unmarshal((*plain)(s))
	if err != nil {
		return err
	}
	if s.Host == "" {
		s.Host = "0.0.0.0" // Default to all interfaces
	}
	if s.Port == 0 {
		s.Port = 443 // Default port
	}
	return nil
}

// Validate performs validation for Server configuration.
func (s *Server) Validate() error {
	if strings.TrimSpace(s.Host) == "" {
		return fmt.Errorf("server host is required and cannot be empty")
	}
	if s.Port <= 0 || s.Port > 65535 {
		return fmt.Errorf("server port must be between 1 and 65535, got %d", s.Port)
	}
	if s.Tls == nil {
		return fmt.Errorf("TLS configuration block is required")
	}
	if err := s.Tls.Validate(); err != nil {
		return fmt.Errorf("TLS config validation failed: %w", err)
	}
	return nil
}

// TlsConfig holds TLS configuration
type TlsConfig struct {
	Enabled  bool   `yaml:"enabled"`
	CertFile string `yaml:"cert_file"`
	KeyFile  string `yaml:"key_file"`
}

func (t *TlsConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
	type plain TlsConfig
	err := unmarshal((*plain)(t))
	if err != nil {
		return err
	}
	return nil
}

// Validate performs validation for TlsConfig.
func (t *TlsConfig) Validate() error {
	if t.Enabled {
		if strings.TrimSpace(t.CertFile) == "" {
			return fmt.Errorf("TLS cert_file is required and cannot be empty when TLS is enabled")
		}
		if strings.TrimSpace(t.KeyFile) == "" {
			return fmt.Errorf("TLS key_file is required and cannot be empty when TLS is enabled")
		}
	}
	return nil
}

// Database holds database configuration
type Database struct {
	DSN string `yaml:"dsn"`
}

func (d *Database) UnmarshalYAML(unmarshal func(interface{}) error) error {
	type plain Database
	err := unmarshal((*plain)(d))
	if err != nil {
		return err
	}
	return nil
}

// Validate performs validation for Database configuration.
func (d *Database) Validate() error {
	if strings.TrimSpace(d.DSN) == "" {
		return fmt.Errorf("database DSN is required and cannot be empty")
	}
	if !strings.HasPrefix(d.DSN, "file:") && d.DSN != ":memory:" && !strings.Contains(d.DSN, ".db") {
		// This is a basic check, might need refinement based on actual DSN formats used
		fmt.Printf("Warning: DSN '%s' might not be a typical SQLite DSN\n", d.DSN)
	}
	return nil
}

// Sql holds SQL database configuration
type Sqlite struct {
	File string `yaml:"file"`
}

func (c *Sqlite) UnmarshalYAML(unmarshal func(interface{}) error) error {
	type plain Sqlite
	err := unmarshal((*plain)(c))
	if err != nil {
		return err
	}
	if c.File == "" {
		return fmt.Errorf("SQLite file is required")
	}
	return nil
}

// Auth holds authentication configuration
type Auth struct {
	PrivateKey      string `yaml:"private_key"`
	TokenDuration   int    `yaml:"token_duration"`
	CleanupInterval int    `yaml:"cleanup_interval"`
}

func (a *Auth) UnmarshalYAML(unmarshal func(interface{}) error) error {
	type plain Auth
	err := unmarshal((*plain)(a))
	if err != nil {
		return err
	}
	if a.TokenDuration == 0 {
		a.TokenDuration = 3600 // Default to 1 hour
	}
	if a.CleanupInterval == 0 {
		a.CleanupInterval = 3600 // Default to 1 hour
	}
	return nil
}

// Validate performs validation for Auth configuration.
func (a *Auth) Validate() error {
	if strings.TrimSpace(a.PrivateKey) == "" {
		return fmt.Errorf("auth private_key is required and cannot be empty")
	}
	if a.TokenDuration <= 0 {
		return fmt.Errorf("auth token_duration must be a positive integer, got %d", a.TokenDuration)
	}
	if a.CleanupInterval <= 0 {
		return fmt.Errorf("auth cleanup_interval must be a positive integer, got %d", a.CleanupInterval)
	}
	return nil
}

func Load(configPath string) (*Config, error) {
	cnf := &Config{}
	b, err := os.ReadFile(configPath)
	if err != nil {
		return nil, err
	}
	err = yaml.Unmarshal(b, cnf)
	if err != nil {
		return nil, err
	}

	// Validate the loaded configuration
	if err := cnf.Validate(); err != nil {
		return nil, fmt.Errorf("configuration validation failed: %w", err)
	}

	return cnf, nil
}
