package config

import (
	"fmt"
	"os"
	"time"

	"gopkg.in/yaml.v3"
)

type Config struct {
	Server  ServerConfig  `yaml:"server"`
	Origin  OriginConfig  `yaml:"origin"`
	Site    SiteConfig    `yaml:"site"`
	Wedding WeddingConfig `yaml:"wedding"`
	Storage StorageConfig `yaml:"storage"`
	Email   EmailConfig   `yaml:"email"`
	Upload  UploadConfig  `yaml:"upload"`
	Webhook WebhookConfig `yaml:"webhook"`
}

type OriginConfig struct {
	ServiceKey string `yaml:"service_key"`
	URL        string `yaml:"url"`
	Version    string `yaml:"version"`
}

type ServerConfig struct {
	Port int `yaml:"port"`
}

type SiteConfig struct {
	URL string `yaml:"url"`
}

type WeddingConfig struct {
	Date         time.Time `yaml:"date"`
	CeremonyTime string    `yaml:"ceremony_time"`
	RSVPBy       time.Time `yaml:"rsvp_by"`
	VenueName    string    `yaml:"venue_name"`
	VenueAddress string    `yaml:"venue_address"`
	RSVPPhone    string    `yaml:"rsvp_phone"`
}

type StorageConfig struct {
	DataDir string `yaml:"data_dir"`
}

type EmailConfig struct {
	SMTPHost string `yaml:"smtp_host"`
	SMTPPort int    `yaml:"smtp_port"`
	SMTPUser string `yaml:"smtp_user"`
	SMTPPass string `yaml:"smtp_pass"`
	From     string `yaml:"from"`
	To       string `yaml:"to"`
}

type UploadConfig struct {
	MaxSizeMB int `yaml:"max_size_mb"`
	MaxFiles  int `yaml:"max_files"`
}

// WebhookConfig is entirely optional: each URL is only called if set, so a
// deployment can wire up RSVP notifications without touching photo uploads
// (or either at all).
type WebhookConfig struct {
	RSVPURL        string            `yaml:"rsvp_url"`
	PhotoURL       string            `yaml:"photo_url"`
	Secret         string            `yaml:"secret"`  // signs the payload via HMAC-SHA256, sent in X-Webhook-Signature
	Headers        map[string]string `yaml:"headers"` // extra headers sent with every webhook request, e.g. Authorization
	TimeoutSeconds int               `yaml:"timeout_seconds"`
}

// Path resolves the config file location: $CONFIG_PATH, or ./config.yaml.
func Path() string {
	if p := os.Getenv("CONFIG_PATH"); p != "" {
		return p
	}
	return "config.yaml"
}

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

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

	if cfg.Server.Port == 0 {
		cfg.Server.Port = 8080
	}
	if cfg.Storage.DataDir == "" {
		cfg.Storage.DataDir = "./data"
	}
	if cfg.Upload.MaxSizeMB == 0 {
		cfg.Upload.MaxSizeMB = 15
	}
	if cfg.Upload.MaxFiles == 0 {
		cfg.Upload.MaxFiles = 10
	}
	if cfg.Webhook.TimeoutSeconds == 0 {
		cfg.Webhook.TimeoutSeconds = 5
	}
	if cfg.Wedding.Date.IsZero() {
		return nil, fmt.Errorf("wedding.date is required in %s", path)
	}
	if cfg.Wedding.RSVPBy.IsZero() {
		return nil, fmt.Errorf("wedding.rsvp_by is required in %s", path)
	}

	return &cfg, nil
}
