package config

import (
	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/compress"
	"github.com/pelletier/go-toml/v2"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"time"
)

type app = struct {
	Name         string        `toml:"name"`
	Host         string        `toml:"host"`
	Domain       string        `toml:"domain"`
	Port         string        `toml:"port"`
	ExternalPort string        `toml:"external-port"`
	PrintRoutes  bool          `toml:"print-routes"`
	Prefork      bool          `toml:"prefork"`
	Production   bool          `toml:"production"`
	IdleTimeout  time.Duration `toml:"idle-timeout"`
	BodyLimit    int           `toml:"body-limit"`
}

// db struct config
type db = struct {
	Postgres struct {
		DSN     string `toml:"dsn"`
		LogMode string `toml:"log-mode"`
		Migrate bool   `toml:"migrate"`
		Seed    bool   `toml:"seed"`
	}
}

// log struct config
type logger = struct {
	TimeFormat string        `toml:"time-format"`
	Level      zerolog.Level `toml:"level"`
	Prettier   bool          `toml:"prettier"`
}

// middleware
type middleware = struct {
	Compress struct {
		Enable bool
		Level  compress.Level
	}

	Recover struct {
		Enable bool
	}

	Monitor struct {
		Enable bool
		Path   string
	}

	Pprof struct {
		Enable bool
	}

	Cors struct {
		Enable bool
	}

	Limiter struct {
		Enable     bool
		Max        int
		Expiration time.Duration `toml:"expiration_seconds"`
	}

	Csrf struct {
		Enable            bool
		CookieName        string `toml:"cookie-name"`
		CookieSameSite    string `toml:"cookie-same-site"`
		CookieSecure      bool   `toml:"cookie-secure"`
		CookieSessionOnly bool   `toml:"cookie-session-only"`
		CookieHttpOnly    bool   `toml:"cookie-http-only"`
	}

	AuditTrails struct {
		Enable    bool
		Retention int
	}
}

// minio struct config
type objectStorage = struct {
	MinioStorage struct {
		Endpoint        string `toml:"endpoint"`
		AccessKeyID     string `toml:"access-key-id"`
		SecretAccessKey string `toml:"secret-access-key"`
		UseSSL          bool   `toml:"use-ssl"`
		BucketName      string `toml:"bucket-name"`
		Location        string `toml:"location"`
	}
}

type keycloak = struct {
	Endpoint      string `toml:"endpoint"`
	Realm         string `toml:"realm"`
	ClientId      string `toml:"client-id"`
	ClientSecret  string `toml:"client-secret"`
	AdminUsername string `toml:"admin-username"`
	AdminPassword string `toml:"admin-password"`
}

type smtp = struct {
	Host        string `toml:"host"`
	Port        int    `toml:"port"`
	Username    string `toml:"username"`
	Password    string `toml:"password"`
	FromAddress string `toml:"from-address"`
	FromName    string `toml:"from-name"`
}

type Config struct {
	App           app
	DB            db
	Logger        logger
	Middleware    middleware
	ObjectStorage objectStorage
	Keycloak      keycloak
	Smtp          smtp
}

// NewConfig : initialize config
func NewConfig() *Config {
	config, err := ParseConfig("config")
	if err != nil && !fiber.IsChild() {
		// panic if config is not found
		log.Panic().Err(err).Msg("config not found")
	}

	return config
}

// ParseConfig : func to parse config
func ParseConfig(name string, debug ...bool) (*Config, error) {
	var (
		contents *Config
		file     []byte
		err      error
	)

	if len(debug) > 0 {
		file, err = os.ReadFile(name)
	} else {
		_, b, _, _ := runtime.Caller(0)
		// get base path
		path := filepath.Dir(filepath.Dir(filepath.Dir(b)))
		file, err = os.ReadFile(filepath.Join(path, "./config/toml/", name+".toml"))
	}

	if err != nil {
		return &Config{}, err
	}

	err = toml.Unmarshal(file, &contents)

	return contents, err
}

// ParseAddress : func to parse address
func ParseAddress(raw string) (host, port string) {
	if i := strings.LastIndex(raw, ":"); i > 0 {
		return raw[:i], raw[i+1:]
	}

	return raw, ""
}
