package global

import (
	"errors"
	"fmt"
	"os"
	"strconv"
	"strings"

	"github.com/jmoiron/sqlx"
	"github.com/pelletier/go-toml/v2"
)

type (
    dbConfig struct {
        Host string `toml:"host"`
        Name string `toml:"name"`
        User string `toml:"user"`
        Pass string `toml:"pass"`
    }

    discordConfig struct {
        AdminID string `toml:"admin_id" comment:"NOTE: admin_id to be deprecated in favour of local accounts and SSO."`
        ClientID string `toml:"client_id"`
        Secret string `toml:"secret"`
    }

    config struct {
        BaseUrl string `toml:"base_url" comment:"Used for OAuth redirects."`
        Port int64 `toml:"port"`
        DataDirectory string `toml:"data_dir"`
        DB dbConfig `toml:"db"`
        Discord discordConfig `toml:"discord"`
    }
)

var Config = func() config {
    configFile := os.Getenv("ARIMELODY_CONFIG")
    if configFile == "" {
        configFile = "config.toml"
    }

    config := config{
        BaseUrl: "https://arimelody.me",
        Port: 8080,
    }

    data, err := os.ReadFile(configFile)
    if err != nil {
        configOut, _ := toml.Marshal(&config)
        os.WriteFile(configFile, configOut, os.ModePerm)
        fmt.Printf(
            "A default config.toml has been created. " +
            "Please configure before running again!\n")
        os.Exit(0)
    }

    err = toml.Unmarshal([]byte(data), &config)
    if err != nil {
        fmt.Fprintf(os.Stderr, "FATAL: Failed to parse configuration file: %s\n", err.Error())
        os.Exit(1)
    }

    err = handleConfigOverrides(&config)
    if err != nil {
        fmt.Fprintf(os.Stderr, "FATAL: Failed to parse environment variable %s\n", err.Error())
        os.Exit(1)
    }

    return config
}()

func handleConfigOverrides(config *config) error {
    var err error

    if env, has := os.LookupEnv("ARIMELODY_BASE_URL"); has { config.BaseUrl = env }
    if env, has := os.LookupEnv("ARIMELODY_PORT"); has {
        config.Port, err = strconv.ParseInt(env, 10, 0)
        if err != nil { return errors.New("ARIMELODY_PORT: " + err.Error()) }
    }
    if env, has := os.LookupEnv("ARIMELODY_DATA_DIR"); has { config.DataDirectory = env }

    if env, has := os.LookupEnv("ARIMELODY_DB_HOST"); has { config.DB.Host = env }
    if env, has := os.LookupEnv("ARIMELODY_DB_NAME"); has { config.DB.Name = env }
    if env, has := os.LookupEnv("ARIMELODY_DB_USER"); has { config.DB.User = env }
    if env, has := os.LookupEnv("ARIMELODY_DB_PASS"); has { config.DB.Pass = env }

    if env, has := os.LookupEnv("ARIMELODY_DISCORD_ADMIN_ID"); has { config.Discord.AdminID = env }
    if env, has := os.LookupEnv("ARIMELODY_DISCORD_CLIENT_ID"); has { config.Discord.ClientID = env }
    if env, has := os.LookupEnv("ARIMELODY_DISCORD_SECRET"); has { config.Discord.Secret = env }

    return nil
}

var Args = func() map[string]string {
    args := map[string]string{}
    
    index := 0
    for index < len(os.Args[1:]) {
        arg := os.Args[index + 1]
        if !strings.HasPrefix(arg, "-") {
            fmt.Printf("FATAL: Parameters must follow an argument (%s).\n", arg)
            os.Exit(1)
        }

        if index + 3 > len(os.Args) || strings.HasPrefix(os.Args[index + 2], "-") {
            args[arg[1:]] = "true"
            index += 1
            continue
        }

        val := os.Args[index + 2]
        args[arg[1:]] = val
        // fmt.Printf("%s: %s\n", arg[1:], val)
        index += 2
    }

    return args
}()

var DB *sqlx.DB
