package main

import (
	"context"
	"fmt"
	"log/slog"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"

	"github.com/ultisuite/ulti-backend/internal/config"
	"github.com/ultisuite/ulti-backend/internal/dbmigrate"
	"github.com/ultisuite/ulti-backend/internal/envexpand"
	"github.com/ultisuite/ulti-backend/internal/server"
)

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	loadDotEnv()

	cfg, err := config.Load()
	if err != nil {
		slog.Error("failed to load config", "error", err)
		os.Exit(1)
	}

	if err := dbmigrate.Up(cfg.DatabaseURL); err != nil {
		slog.Error("database migration failed", "error", err)
		os.Exit(1)
	}

	app, err := server.New(ctx, cfg, server.Options{})
	if err != nil {
		slog.Error("failed to bootstrap server", "error", err)
		os.Exit(1)
	}
	defer app.Close()

	srv := &http.Server{
		Addr:    fmt.Sprintf(":%d", cfg.Port),
		Handler: app.Router,
	}

	errCh := make(chan error, 1)
	go func() {
		slog.Info("server starting", "port", cfg.Port)
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			errCh <- err
		}
	}()

	quit := make(chan os.Signal, 1)
	signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)

	select {
	case <-quit:
	case err := <-errCh:
		slog.Error("server error", "error", err)
	}

	slog.Info("shutting down server")
	cancel()

	shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer shutdownCancel()

	if err := srv.Shutdown(shutdownCtx); err != nil {
		slog.Error("server forced shutdown", "error", err)
		os.Exit(1)
	}
	slog.Info("server stopped")
}

func loadDotEnv() {
	for _, path := range []string{".env", "../.env"} {
		if err := envexpand.ApplyFile(path); err == nil {
			slog.Debug("loaded env file", "path", path)
			return
		}
	}
}
