package config

import (
	"net/url"
	"os"
	"slices"
	"strings"

	"gopkg.in/yaml.v3"
)

type Access struct {
	User   string `yaml:"user,omitempty"`
	Group  string `yaml:"group,omitempty"`
	Groups string `yaml:"groups,omitempty"`
	Mode   string `yaml:"mode"` // "read-only" or "read-write"
	ICS    string `yaml:"ics,omitempty"`
}

type Calendar struct {
	ID     string   `yaml:"id"`
	Owner  string   `yaml:"owner"`
	Color  string   `yaml:"color,omitempty"`
	Access []Access `yaml:"access,omitempty"`
}

type AddressBook struct {
	ID     string   `yaml:"id"`
	Owner  string   `yaml:"owner"`
	Access []Access `yaml:"access,omitempty"`
}

type Aggregate struct {
	ID      string   `yaml:"id"`
	Owner   string   `yaml:"owner"`
	Color   string   `yaml:"color,omitempty"`
	Sources []string `yaml:"sources"` // Calendar IDs
	Access  []Access `yaml:"access,omitempty"`
}

type User struct {
	Name        string   `yaml:"name"`
	Password    string   `yaml:"password"`
	PasswordCmd string   `yaml:"password_cmd"`
	Groups      []string `yaml:"groups,omitempty"`
}

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

type ServerConfig struct {
	BindAddress  string `yaml:"bind_address"`
	PublicURL    string `yaml:"public_url"`
	EmailDomain  string `yaml:"email_domain"`
	Redaction    string `yaml:"redaction_text"` // "[-]"
	DefaultClass string `yaml:"default_class"` // CONFIDENTIAL/PRIVATE/PUBLIC
}
func (s ServerConfig) BasePath() string {
	u, err := url.Parse(s.PublicURL)
	if err != nil { return "" }
	return strings.TrimSuffix(u.Path, "/")
}


type SMTPConfig struct {
	Host     string `yaml:"host"`
	Port     int    `yaml:"port"`
	User     string `yaml:"user"`
	Password string `yaml:"password"`
}

type Config struct {
	Server       ServerConfig   `yaml:"server"`
	Database     DatabaseConfig `yaml:"database"`
	SMTP         SMTPConfig     `yaml:"smtp"`
	Users        []User         `yaml:"users"`
	Calendars    []Calendar     `yaml:"calendars"`
	AddressBooks []AddressBook  `yaml:"address_books"`
	Aggregates   []Aggregate    `yaml:"aggregates"`
}
func (c *Config) setDefaults() {
	if c.Server.BindAddress == ""  { c.Server.BindAddress = ":8080" }
	if c.Server.Redaction == ""    { c.Server.Redaction = "Busy" }
	if c.Server.DefaultClass == "" { c.Server.DefaultClass = "CONFIDENTIAL" }
	if c.Server.EmailDomain == ""  { c.Server.EmailDomain = "nx2.site" }
	if c.Database.URL == ""        { c.Database.URL = "postgres://nxcaldav@localhost:5432/nxcaldav?sslmode=disable" }
	if c.SMTP.Host == ""           { c.SMTP.Host = "localhost" }
	if c.SMTP.Port == 0            { c.SMTP.Port = 25 }
}
func (c *Config) checkConfig() {
	if !(slices.Contains([]string{"PUBLIC", "PRIVATE", "CONFIDENTIAL"}, c.Server.DefaultClass)) {
		panic("Invaldi Config, default_class")
	}
}

func Load(path string) (*Config, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	var cfg Config
	err = yaml.NewDecoder(f).Decode(&cfg)
	if err != nil {
		return nil, err
	}

	cfg.checkConfig()
	cfg.setDefaults()
	return &cfg, nil
}

