package main

import (
	"fmt"
	"log/slog"
	"os"
	"os/signal"
	"syscall"

	"git.savin.nyc/alex/go-receipt-tracker/app"
	"git.savin.nyc/alex/go-receipt-tracker/bus"
	"git.savin.nyc/alex/go-receipt-tracker/config"
	"git.savin.nyc/alex/go-receipt-tracker/database"
	"git.savin.nyc/alex/go-receipt-tracker/hooks/debug"
	"git.savin.nyc/alex/go-receipt-tracker/workers"
)

// var log = *slog.Logger
var cfg = &config.Config{}

const (
	LoggingOutputJson = "JSON"
	LoggingOutputText = "TEXT"
)

func configureLogging(config *config.Logging) *slog.Logger { //nolint:unparam
	if config == nil {
		return nil
	}

	var level slog.Level
	if err := level.UnmarshalText([]byte(config.Level)); err != nil {
		slog.Warn(err.Error())
		slog.Warn(fmt.Sprintf("logging level not recognized, defaulting to level %s", slog.LevelInfo.String()))
		level = slog.LevelInfo
	}

	var handler slog.Handler
	switch config.Output {
	case LoggingOutputJson:
		handler = slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{AddSource: cfg.Logging.Source, Level: level})
	case LoggingOutputText:
		handler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{AddSource: cfg.Logging.Source, Level: level})
	default:
		handler = slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{AddSource: cfg.Logging.Source, Level: level})
	}

	return slog.New(handler)
}

func main() {
	sigs := make(chan os.Signal, 1)
	done := make(chan bool, 1)
	signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
	go func() {
		<-sigs
		done <- true
	}()

	var err error
	cfg, err = config.New()
	if err != nil { // Handle errors reading the config file
		slog.Error("Fatal error config file", "error", err.Error())
		os.Exit(1)
	}

	// LOGGER
	logger := configureLogging(cfg.Logging)
	logger.Debug("CONFIG", "config", cfg)

	// BUS
	evBus := bus.New(cfg.Bus, logger)

	// DATABASE
	db, err := database.NewDB(cfg.DataBase, logger)
	if err != nil {
		logger.Error(err.Error())
		os.Exit(1)
	}

	app := app.New(cfg, evBus, db, logger)

	for _, opts := range cfg.Parsers {
		if opts.Type == "openai" {
			openai := workers.NewOpenAi(opts, evBus)
			err = app.AddWorker(openai)
			if err != nil {
				app.Log.Error(err.Error())
			}
		}
		// if opts.Type == "claude" {
		// 	claude := workers.NewClaude(opts, evBus)
		// 	err = app.AddWorker(claude)
		// 	if err != nil {
		// 		app.Log.Error(err.Error())
		// 	}
		// }
		// if opts.Type == "gemini" {
		// 	gemini := workers.NewGemini(opts, evBus)
		// 	err = app.AddWorker(gemini)
		// 	if err != nil {
		// 		app.Log.Error(err.Error())
		// 	}
		// }
	}

	tb := workers.NewTelegramBot(cfg.Telegram, evBus)
	err = app.AddWorker(tb)
	if err != nil {
		app.Log.Error(err.Error())
		os.Exit(1)
	}

	// if len(cfg.Listeners) > 0 {
	// 	for name, opts := range cfg.Listeners {
	// 		listener := listeners.NewHTTPStats(name, ":"+strconv.Itoa(opts.Port), nil, app.Info)
	// 		err = app.AddListener(listener)
	// 		if err != nil {
	// 			app.Log.Error(err.Error())
	// 		}
	// 	}
	// }

	err = app.AddHook(new(debug.Hook), nil)
	if err != nil {
		app.Log.Error(err.Error())
	}

	// err = app.AddHook(new(consul.Hook), &consul.Options{
	// 	Hostname:  cfg.Consul.Host,
	// 	Port:      cfg.Consul.Port,
	// 	DC:        cfg.Consul.DataCenter,
	// 	ServiceID: "srv-mysubaru-01",
	// 	NodeName:  "mysubaru",
	// 	Tags:      []string{"mysubaru", "hassio", "mqtt"},
	// 	LocalHost: cfg.Consul.Interfaces.WAN,
	// 	LocalPort: cfg.Listeners["stats"].Port,
	// })
	// if err != nil {
	// 	app.Log.Error(err.Error())
	// }

	go func() {
		err := app.Serve()
		if err != nil {
			app.Log.Error(err.Error())
		}
	}()

	<-done
	app.Log.Warn("caught signal, stopping...")
	_ = app.Close()
	app.Log.Info("main.go finished")
}
