package config

import (
	"log/slog"
	"os"
	"reflect"
	"strconv"
	"time"
)

type Config struct {
	// time configuration
	TimeFormat    string         `default:"2006-01-02 15:04:05" env:"time_format"`
	TimeZoneLocal string         `default:"America/Chicago"     env:"time_zone"`
	TZLocal       *time.Location `ignored:"true"`
	TZUTC         *time.Location `ignored:"true"`

	// logging
	LogLevel  int            `default:"50"   env:"log_level"`
	Log       *slog.Logger   `ignored:"true"`
	SLogLevel *slog.LevelVar `ignored:"true"`

	// webserver
	WebServerPort         int    `default:"8080"    env:"webserver_port"`
	WebServerIP           string `default:"0.0.0.0" env:"webserver_ip"`
	WebServerReadTimeout  int    `default:"5"       env:"webserver_read_timeout"`
	WebServerWriteTimeout int    `default:"1"       env:"webserver_write_timeout"`
	WebServerIdleTimeout  int    `default:"2"       env:"webserver_idle_timeout"`
}

// New initializes the config variable for use with a prepared set of defaults.
func New() Config {
	cfg := Config{
		SLogLevel: new(slog.LevelVar),
	}

	cfg.Log = slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
		Level: cfg.SLogLevel,
	}))

	return cfg
}

func setLogLevel(cfg *Config) {
	switch {
	// error
	case cfg.LogLevel <= 20:
		cfg.SLogLevel.Set(slog.LevelError)
		cfg.Log.Info("Log level updated", "level", slog.LevelError)
	// warning
	case cfg.LogLevel > 20 && cfg.LogLevel <= 40:
		cfg.SLogLevel.Set(slog.LevelWarn)
		cfg.Log.Info("Log level updated", "level", slog.LevelWarn)
	// info
	case cfg.LogLevel > 40 && cfg.LogLevel <= 60:
		cfg.SLogLevel.Set(slog.LevelInfo)
		cfg.Log.Info("Log level updated", "level", slog.LevelInfo)
	// debug
	case cfg.LogLevel > 60:
		cfg.SLogLevel.Set(slog.LevelDebug)
		cfg.Log.Info("Log level updated", "level", slog.LevelDebug)
	}
	// set default logger
	slog.SetDefault(cfg.Log)
}

func printRunningConfig(cfg *Config, cfgInfo []structInfo) {
	var logRunningConfiguration = "Running Configuration"

	for _, info := range cfgInfo {
		if info.Secret {
			cfg.Log.Debug(logRunningConfiguration, info.Name, "REDACTED")
		} else {
			switch info.Type.String() {
			case "string":
				p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*string)
				cfg.Log.Debug("Running Configuration", info.Alt, *p)
			case "bool":
				p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*bool)
				cfg.Log.Debug("Running Configuration", info.Alt, strconv.FormatBool(*p))
			case "int":
				p := reflect.ValueOf(cfg).Elem().FieldByName(info.Name).Addr().Interface().(*int)
				cfg.Log.Debug("Running Configuration", info.Alt, strconv.FormatInt(int64(*p), 10))
			}
		}
	}
}