package main

import (
	"context"
	"fmt"
	"log"
	"os"
	"os/signal"
	"syscall"
	"time"

	"go-server/internal/config"
	"go-server/internal/database"
	"go-server/internal/models"
	"go-server/internal/routes"
	"go-server/internal/server"

	"gorm.io/gorm"
)

func main() {
	fmt.Println("Starting server...")

	// Load configuration
	cfg, err := config.LoadConfig()
	if err != nil {
		log.Fatalf("Failed to load config: %v", err)
	}

	// init dbs
	_ = database.InitDatabases(database.NewPostgresConfig(), database.RedisConfig(cfg.Redis))

	// Initialize PostgreSQL
	db := database.GetPostgres()
	sqlDb, err := db.DB()
	if err != nil {
		log.Fatalf("Failed to get DB connection: %v", err)
	}
	defer sqlDb.Close()

	// Auto-migrate models to ensure GORM knows about table structures
	err = migrateModels(db)
	if err != nil {
		log.Fatalf("Failed to migrate models: %v", err)
	}

	// Initialize Redis
	redisClient := database.GetRedis()
	defer redisClient.Close()

	// Setup router
	router := routes.SetupRouter(db)

	// Use the server abstraction
	srv := server.NewServer(router)

	// Handle graceful shutdown
	quit := make(chan os.Signal, 1)
	signal.Notify(quit, os.Interrupt, syscall.SIGTERM)
	go func() {
		<-quit
		fmt.Println("Shutting down server...")

		// Create shutdown context with a timeout
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()

		// Shutdown services gracefully
		if err := srv.Shutdown(ctx); err != nil {
			log.Fatalf("Server shutdown failed: %v", err)
		}

		redisClient.Close()
		sqlDb.Close()
		fmt.Println("Server gracefully stopped")
	}()

	// Start server
	port := cfg.Server.Port
	if err := srv.Start(port); err != nil {
		log.Fatalf("Failed to start server: %v", err)
	}
}

// migrateModels auto-migrates all models to ensure GORM knows about table structures
func migrateModels(db *gorm.DB) error {
	return db.AutoMigrate(
		models.User{},
		models.Supplement{},
		models.Nutrient{},
		models.Category{},
		models.NutrientCategory{},
		models.SupplementNutrient{},
		models.Todo{},
		models.TodoCompletion{},
	)
}
