package config

import (
	"time"

	"github.com/creasty/defaults"
	"github.com/go-playground/validator/v10"
)

var validate = validator.New()

type RootConfig struct {
	Base BaseConfig `yaml:"base"`

	Log LogConfig `yaml:"log"`

	OlympusDB DatabaseConfig `yaml:"olympusDB"`

	APIServer APIServerConfig `yaml:"apiServer"`

	Lark LarkConfig `yaml:"lark"`

	Ali AliConfig `yaml:"ali"`

	Twilio TwilioConfig `yaml:"twilio"`

	Services Services `yaml:"services"`
}

// BaseConfig contains the base information.
type BaseConfig struct {
	Env string `yaml:"env" validate:"required"` // env contains dev, staging, prod.
}

type LogConfig struct {
	Level int16 `yaml:"level" default:"0"`
}

type DatabaseConfig struct {
	Host     string `yaml:"host" validate:"required"`
	Port     uint16 `yaml:"port" validate:"required"`
	User     string `yaml:"user" validate:"required"`
	Password string `yaml:"password" validate:"required"`
	Database string `yaml:"database" validate:"required"`

	TLSConfigKey    string        `yaml:"tlsConfigKey"`
	DailTimeout     time.Duration `yaml:"dailTimeout" default:"60s"`
	ReadTimeout     time.Duration `yaml:"readTimeout" default:"30s"`
	WriteTimeout    time.Duration `yaml:"writeTimeout" default:"30s"`
	ConnMaxLifetime time.Duration `yaml:"connMaxLifetime" default:"3m"`
	MaxIdleConns    int           `yaml:"maxIdleConns" default:"100"`
	MaxOpenConns    int           `yaml:"maxOpenConns" default:"100"`

	LogLevel         int           `yaml:"logLevel" default:"4"` // 1: silent, 2: error, 3: warn, 4: info
	LogSlowThreshold time.Duration `yaml:"logSlowThreshold" default:"200ms"`
	TraceQuerySQL    bool          `yaml:"traceQuerySQL" default:"false"`
}

type APIServerConfig struct {
	ListenAddr        string        `yaml:"listenAddr" default:":8080"`
	ReadHeaderTimeout time.Duration `yaml:"readHeaderTimeout" default:"10s"`
}

type LarkConfig struct {
	Clients []LarkClientConfig `yaml:"clients"`
}

type LarkClientConfig struct {
	ClientKey   string `yaml:"clientKey" validate:"required"`
	LarkBaseURL string `yaml:"larkBaseURL" default:"pingcap.feishu.cn"`
	AppCode     string `yaml:"appCode" validate:"required"`
	AppSecret   string `yaml:"appSecret" validate:"required"`
}

type TwilioConfig struct {
	AccountSid     string                      `yaml:"accountSid"`
	AuthToken      string                      `yaml:"authToken"`
	CalloutNumbers []TwilioCalloutNumberConfig `yaml:"calloutNumbers"`
}

type TwilioCalloutNumberConfig struct {
	Prefix string `yaml:"prefix"`
	Number string `yaml:"number"`
}

type RateLimitConfig struct {
	GeneralRateLimit    GeneralRateLimitConfig    `yaml:"generalRateLimit"`
	PerPhoneNoRateLimit PerPhoneNoRateLimitConfig `yaml:"perPhoneNoRateLimit"`
}

type GeneralRateLimitConfig struct {
	PerMinuteBurst int           `yaml:"perMinuteBurst" default:"20"`
	MaxWaitTimeout time.Duration `yaml:"maxWaitTimeout" default:"5s"`
}

type PerPhoneNoRateLimitConfig struct {
	PerMinute int `yaml:"perMinute" default:"1"`
	PerHour   int `yaml:"perHour" default:"5"`
	PerDay    int `yaml:"perDay" default:"20"`
}

type AliConfig struct {
	RateLimit       RateLimitConfig `yaml:"rateLimit"`
	TtsCode         string          `yaml:"ttsCode"`
	AccessKeyId     string          `yaml:"accessKeyId"`
	AccessKeySecret string          `yaml:"accessKeySecret"`
	CalloutNumbers  []string        `yaml:"calloutNumbers" validate:"required"`
}

func NewDefault() (*RootConfig, error) {
	conf := &RootConfig{}
	err := defaults.Set(conf)
	return conf, err
}

func (c *RootConfig) Validate() error {
	return validate.Struct(c)
}
