package config

import (
	"errors"
	"fmt"
	"log/slog"
)

var (
	ErrMissingLoggingFileConfig = errors.New("config.Logging: missing value parameters in logging block")
	ErrInvalidLoggingSink       = errors.New("config.Logging: invalid sink")
	ErrInvalidLoggingFileConfig = errors.New("config.LoggingFileConfig: invalid parameters")
	ErrOutOfRange               = errors.New("config: error out of range")
)

type Logging struct {
	Sink       string             `json:"sink"`       // Logging sink, either "stdio" or "file"
	Level      *slog.Level        `json:"level"`      // Log level, if set supersedes the level in flags
	Parameters *LoggingFileConfig `json:"parameters"` // Logging parameters, to be dynamic in the future
}

const (
	LogSinkStdio = "stdio"
	LogSinkFile  = "file"
)

func (l *Logging) Valid() error {
	var errs []error

	switch l.Sink {
	case LogSinkStdio:
		// no validation needed
	case LogSinkFile:
		if l.Parameters == nil {
			errs = append(errs, ErrMissingLoggingFileConfig)
		}

		if err := l.Parameters.Valid(); err != nil {
			errs = append(errs, err)
		}
	default:
		errs = append(errs, fmt.Errorf("%w: sink %s is unknown to me", ErrInvalidLoggingSink, l.Sink))
	}

	if len(errs) != 0 {
		return errors.Join(errs...)
	}

	return nil
}

func (Logging) Default() *Logging {
	return &Logging{
		Sink: "stdio",
	}
}

type LoggingFileConfig struct {
	Filename     string `json:"file"`
	MaxBackups   int    `json:"maxBackups"`
	MaxBytes     int64  `json:"maxBytes"`
	MaxAge       int    `json:"maxAge"`
	Compress     bool   `json:"compress"`
	UseLocalTime bool   `json:"useLocalTime"`
}

func (lfc *LoggingFileConfig) Valid() error {
	if lfc == nil {
		return fmt.Errorf("logging file config is nil, why are you calling this?")
	}

	var errs []error

	if lfc.Zero() {
		errs = append(errs, ErrMissingValue)
	}

	if lfc.Filename == "" {
		errs = append(errs, fmt.Errorf("%w: filename", ErrMissingValue))
	}

	if lfc.MaxBackups < 0 {
		errs = append(errs, fmt.Errorf("%w: max backup count %d is not greater than or equal to zero", ErrOutOfRange, lfc.MaxBackups))
	}

	if lfc.MaxAge < 0 {
		errs = append(errs, fmt.Errorf("%w: max backup count %d is not greater than or equal to zero", ErrOutOfRange, lfc.MaxAge))
	}

	if len(errs) != 0 {
		errs = append([]error{ErrInvalidLoggingFileConfig}, errs...)
		return errors.Join(errs...)
	}

	return nil
}

func (lfc LoggingFileConfig) Zero() bool {
	for _, cond := range []bool{
		lfc.Filename != "",
		lfc.MaxBackups != 0,
		lfc.MaxBytes != 0,
		lfc.MaxAge != 0,
		lfc.Compress,
		lfc.UseLocalTime,
	} {
		if cond {
			return false
		}
	}

	return true
}

func (LoggingFileConfig) Default() *LoggingFileConfig {
	return &LoggingFileConfig{
		Filename:     "./var/anubis.log",
		MaxBackups:   3,
		MaxBytes:     104857600, // 100 Mi
		MaxAge:       7,         // 7 days
		Compress:     true,
		UseLocalTime: false,
	}
}
