package config

import (
	"fmt"
	"os"

	"gopkg.in/yaml.v3"
)

// SeedConfig represents the top-level YAML seed configuration.
type SeedConfig struct {
	Global     GlobalConfig            `yaml:"global"`
	Registries map[string]RegistryDef  `yaml:"registries"`
	Projects   map[string]ProjectDef   `yaml:"projects"`
}

// GlobalConfig holds domain-wide settings from the seed file.
type GlobalConfig struct {
	Domain           string    `yaml:"domain"`
	ServerIP         string    `yaml:"server_ip"`
	Network          string    `yaml:"network"`
	SubdomainPattern string    `yaml:"subdomain_pattern"`
	NotificationURL  string    `yaml:"notification_url"`
	Npm              NpmConfig `yaml:"npm"`
}

// NpmConfig holds Nginx Proxy Manager connection details.
type NpmConfig struct {
	URL      string `yaml:"url"`
	Email    string `yaml:"email"`
	Password string `yaml:"password"`
}

// RegistryDef defines a container registry from the seed file.
type RegistryDef struct {
	URL   string `yaml:"url"`
	Type  string `yaml:"type"`
	Token string `yaml:"token"`
}

// ProjectDef defines a project from the seed file.
type ProjectDef struct {
	Registry    string            `yaml:"registry"`
	Image       string            `yaml:"image"`
	Port        int               `yaml:"port"`
	Healthcheck string            `yaml:"healthcheck"`
	Env         map[string]string `yaml:"env"`
	Volumes     map[string]string `yaml:"volumes"`
	Stages      map[string]StageDef `yaml:"stages"`
}

// StageDef defines a deployment stage from the seed file.
type StageDef struct {
	TagPattern   string `yaml:"tag_pattern"`
	AutoDeploy   bool   `yaml:"auto_deploy"`
	MaxInstances int    `yaml:"max_instances"`
	Confirm      bool   `yaml:"confirm"`
	PromoteFrom  string `yaml:"promote_from"`
	Subdomain    string `yaml:"subdomain"`
}

// LoadSeedFile reads and parses the YAML seed config from the given path.
func LoadSeedFile(path string) (SeedConfig, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return SeedConfig{}, fmt.Errorf("read seed file: %w", err)
	}

	return ParseSeed(data)
}

// ParseSeed parses raw YAML bytes into a SeedConfig.
func ParseSeed(data []byte) (SeedConfig, error) {
	var cfg SeedConfig
	if err := yaml.Unmarshal(data, &cfg); err != nil {
		return SeedConfig{}, fmt.Errorf("parse yaml: %w", err)
	}

	if err := validate(cfg); err != nil {
		return SeedConfig{}, fmt.Errorf("validate seed config: %w", err)
	}

	return cfg, nil
}

// validate checks that required fields are present in the seed config.
func validate(cfg SeedConfig) error {
	if cfg.Global.Domain == "" {
		return fmt.Errorf("global.domain is required")
	}

	for name, proj := range cfg.Projects {
		if proj.Image == "" {
			return fmt.Errorf("project %q: image is required", name)
		}
		if proj.Registry != "" {
			if _, ok := cfg.Registries[proj.Registry]; !ok {
				return fmt.Errorf("project %q: references unknown registry %q", name, proj.Registry)
			}
		}
		for stageName, stage := range proj.Stages {
			if stage.TagPattern == "" {
				return fmt.Errorf("project %q stage %q: tag_pattern is required", name, stageName)
			}
			if stage.MaxInstances < 0 {
				return fmt.Errorf("project %q stage %q: max_instances must be >= 0", name, stageName)
			}
		}
	}

	return nil
}
