package main

import (
	"context"
	"io"
	"os"
	"os/signal"
	"sync"
	"time"

	"git.haelnorr.com/h/golib/hlog"
	"github.com/pkg/errors"

	"git.haelnorr.com/h/oslstats/internal/config"
	"git.haelnorr.com/h/oslstats/internal/discord"
	"git.haelnorr.com/h/oslstats/internal/store"
	"git.haelnorr.com/h/oslstats/pkg/embedfs"
)

// Initializes and runs the server
func run(ctx context.Context, w io.Writer, cfg *config.Config) error {
	ctx, cancel := signal.NotifyContext(ctx, os.Interrupt)
	defer cancel()

	// Setup the logger
	logger, err := hlog.NewLogger(cfg.HLOG, w)
	if err != nil {
		return errors.Wrap(err, "hlog.NewLogger")
	}

	// Setup the database connection
	logger.Debug().Msg("Config loaded and logger started")
	logger.Debug().Msg("Connecting to database")
	bun, closedb, err := setupBun(ctx, cfg)
	if err != nil {
		return errors.Wrap(err, "setupDBConn")
	}
	defer closedb()

	// Setup embedded files
	logger.Debug().Msg("Getting embedded files")
	staticFS, err := embedfs.GetEmbeddedFS()
	if err != nil {
		return errors.Wrap(err, "getStaticFiles")
	}

	// Setup session store
	logger.Debug().Msg("Setting up session store")
	store := store.NewStore()

	// Setup Discord API client
	logger.Debug().Msg("Setting up Discord API client")
	discordAPI, err := discord.NewAPIClient(cfg.Discord, logger, cfg.HWSAuth.TrustedHost)
	if err != nil {
		return errors.Wrap(err, "discord.NewAPIClient")
	}

	logger.Debug().Msg("Setting up HTTP server")
	httpServer, err := setupHttpServer(&staticFS, cfg, logger, bun, store, discordAPI)
	if err != nil {
		return errors.Wrap(err, "setupHttpServer")
	}

	// Runs the http server
	logger.Debug().Msg("Starting up the HTTP server")
	err = httpServer.Start(ctx)
	if err != nil {
		return errors.Wrap(err, "httpServer.Start")
	}

	// Handles graceful shutdown
	var wg sync.WaitGroup
	wg.Go(func() {
		<-ctx.Done()
		shutdownCtx := context.Background()
		shutdownCtx, cancel := context.WithTimeout(shutdownCtx, 10*time.Second)
		defer cancel()
		err := httpServer.Shutdown(shutdownCtx)
		if err != nil {
			logger.Error().Err(err).Msg("Graceful shutdown failed")
		}
	})
	wg.Wait()
	logger.Info().Msg("Shutting down")
	return nil
}
