// Copyright (C) 2022 Marius Schellenberger

package config

import (
	"errors"
	"os"
	"regexp"

	"gopkg.in/yaml.v3"
)

func ParseFile(file string) (cfg *Config, err error) {
	if file == "" {
		return nil, errors.New("missing config file")
	}
	f, err := os.Open(file)
	if err != nil {
		return
	}
	defer f.Close()
	cfg = new(Config)
	err = yaml.NewDecoder(f).Decode(cfg)
	if err != nil {
		return
	}
	err = Validate(cfg)
	return
}

type Config struct {
	Server Server         `yaml:"server"`
	Cache  Cache          `yaml:"cache"`
	Path   string         `yaml:"path"`
	REPath *regexp.Regexp `yaml:"-"`
}

type Server struct {
	HTTP   Listen `yaml:"http"`
	WebDav Listen `yaml:"webdav"`
	Cache  Listen `yaml:"cache"`
	Plain  Listen `yaml:"plain"`
}

type Listen struct {
	Addr string `yaml:"addr"`
}

type Cache struct {
	Metadata  string `yaml:"metadata"`
	Src       Path   `yaml:"src"`
	Dst       Path   `yaml:"dst"`
	Preloads  int    `yaml:"preloads"`
	Buffer    int    `yaml:"buffer"`
	Quota     int64  `yaml:"quota"`
	BlockSFTP *bool  `yaml:"blockSFTP"`
}

type Path struct {
	Path string `yaml:"path"`
	Key  string `yaml:"key"`
}

const (
	defListenHTTP = "127.0.0.1:8080"
	defPreloads   = 1
	defBuffer     = 8192
	defQuota      = 1
	defBlockSFTP  = true
	gib           = 1024 * 1024 * 1024
)

func Validate(cfg *Config) error {
	if cfg.Server.HTTP.Addr == "" {
		cfg.Server.HTTP.Addr = defListenHTTP
	}
	c := &cfg.Cache
	if c.Metadata == "" {
		return errors.New("cache.metadata is empty")
	}
	if c.Src.Path == "" {
		return errors.New("cache.src is empty")
	}
	if c.Dst.Path == "" {
		return errors.New("cache.dst is empty")
	}
	if c.Preloads <= 0 {
		c.Preloads = defPreloads
	}
	if c.Buffer < 1024 {
		c.Buffer = defBuffer
	}
	if c.Quota < 1 {
		c.Quota = defQuota
	}
	c.Quota *= gib
	if c.BlockSFTP == nil {
		c.BlockSFTP = new(bool)
		*c.BlockSFTP = defBlockSFTP
	}
	var err error
	if cfg.Path != "" {
		cfg.REPath, err = regexp.Compile(cfg.Path)
	}
	return err
}
