package routes

import (
	"fmt"
	"net/http"
	"strings"

	handlers "go-server/internal/handlers"
	"go-server/internal/middleware"
	"go-server/internal/repository"
	"go-server/internal/service"
	"go-server/internal/templates"

	"github.com/a-h/templ"
	"github.com/gin-gonic/gin"

	"gorm.io/gorm"
)

// Route defines the structure for dynamic routing
type Route struct {
	Method         string
	Path           string
	HandlerFunc    gin.HandlerFunc
	IsAuthRequired bool
}

// Controller defines the structure for a controller with routes
type Controller struct {
	Routes []Route
}

// SetupRouter dynamically sets up routes
func SetupRouter(db *gorm.DB) *gin.Engine {
	gin.SetMode(gin.ReleaseMode)

	r := gin.New()
	r.Use(middleware.CORS())
	r.Use(middleware.Logger())
	r.Use(gin.Recovery())

	// Cache headers for static files
	r.Use(func(c *gin.Context) {
		if strings.HasPrefix(c.Request.URL.Path, "/static/") || c.Request.URL.Path == "/favicon.ico" {
			c.Header("Cache-Control", "public, max-age=31536000")
		}
		c.Next()
	})

	// Serve static files
	r.Static("/static", "./static")
	r.StaticFile("/favicon.ico", "./static/favicon.ico")

	// Serve home page
	r.GET("/", func(c *gin.Context) {
		ctx := templ.WithChildren(c.Request.Context(), templates.Home())
		templates.Layout("Home").Render(ctx, c.Writer)
	})

	// Serve login page
	r.GET("/login", func(c *gin.Context) {
		ctx := templ.WithChildren(c.Request.Context(), templates.Login())
		templates.Layout("Login").Render(ctx, c.Writer)
	})

	// Custom 404 handler
	r.NoRoute(func(c *gin.Context) {
		c.String(http.StatusNotFound, "Not Found")
	})

	// Initialize Repositories
	userRepo := repository.NewUserRepository(db)
	nutrientRepo := repository.NewNutrientRepository(db)
	supplementRepo := repository.NewSupplementRepository(db)
	dailyOverviewRepo := repository.NewDailyOverviewRepository(db)
	categoryRepo := repository.NewCategoryRepository(db)
	todoRepo := repository.NewTodoRepository(db)

	// Initialize Services
	userService := service.NewUserService(userRepo)
	nutrientService := service.NewNutrientService(nutrientRepo)
	supplementService := service.NewSupplementService(supplementRepo, nutrientRepo)
	dailyOverviewService := service.NewDailyOverviewService(dailyOverviewRepo)
	categoryService := service.NewCategoryService(categoryRepo)
	todoService := service.NewTodoService(todoRepo)

	// Initialize Controllers
	adminController := handlers.NewAdminController(userService)
	nutrientController := handlers.NewNutrientController(nutrientService)
	supplementController := handlers.NewSupplementController(supplementService)
	dailyOverviewController := handlers.NewDailyOverviewController(dailyOverviewService)
	categoryController := handlers.NewCategoryController(categoryService)
	todoController := handlers.NewTodoController(todoService)
	loginHandler := handlers.NewLoginHandler()

	skipAuth := true

	// Define controllers and their routes
	controllers := map[string]Controller{
		"admin": {
			Routes: []Route{
				{"GET", "/user/get-all", adminController.GetUsers, true},
				{"DELETE", "/user/:id", adminController.DeleteUser, true},
				{"POST", "/user/:id/change-password", adminController.ChangePassword, true},
				{"POST", "/user", adminController.CreateUser, true},
			},
		},
		"nutrient": {
			Routes: []Route{
				{"GET", "/get-all", nutrientController.GetAll, !skipAuth},
			},
		},
		"supplement": {
			Routes: []Route{
				{"GET", "/get-all", supplementController.GetAll, !skipAuth},
				{"GET", "/get-daily-supplements-overview", supplementController.GetDailySupplementsOverview, !skipAuth},
			},
		},
		"daily-overview": {
			Routes: []Route{
				{"GET", "/overview", dailyOverviewController.GetDailyOverview, !skipAuth},        // Complete overview
				{"GET", "/totals", dailyOverviewController.GetNutrientTotals, !skipAuth},         // Just nutrient totals
				{"GET", "/breakdown", dailyOverviewController.GetSupplementBreakdown, !skipAuth}, // Supplement breakdown
				{"POST", "/query", dailyOverviewController.ExecuteCustomQuery, !skipAuth},        // Custom SQL queries
			},
		},
		"category": {
			Routes: []Route{
				{"GET", "/get-all", categoryController.GetAll, !skipAuth},
			},
		},
		"todo": {
			Routes: []Route{
				{"POST", "/create", todoController.CreateTodo, !skipAuth},                  // Create new todo
				{"GET", "/list", todoController.GetTodos, !skipAuth},                       // Get all todos with stats
				{"GET", "/today", todoController.GetTodaysSummary, !skipAuth},              // Get today's summary
				{"PUT", "/:id", todoController.UpdateTodo, !skipAuth},                      // Update todo
				{"DELETE", "/:id", todoController.DeleteTodo, !skipAuth},                   // Delete todo
				{"POST", "/:id/complete", todoController.CompleteTodo, !skipAuth},          // Complete todo
				{"GET", "/activity", todoController.GetActivityLog, !skipAuth},             // Get activity log
				{"GET", "/activity/:date", todoController.GetActivityLogByDate, !skipAuth}, // Get activity for date
				{"GET", "/weekly", todoController.GetWeeklySummary, !skipAuth},             // Get weekly summary
			},
		},
		"user": {
			Routes: []Route{
				{"POST", "/login", loginHandler.Login, false},
			},
		},
	}

	// Register all routes dynamically
	api := r.Group("/api")
	apiPublic := api.Group("")
	apiAuth := api.Group("")
	apiAuth.Use(middleware.AuthRequired())

	for key, controller := range controllers {
		for _, route := range controller.Routes {
			path := fmt.Sprintf("/%s%s", key, route.Path)
			fmt.Println("Route registered", route.Method, path)
			if route.IsAuthRequired {
				apiAuth.Handle(route.Method, path, route.HandlerFunc)
			} else {
				apiPublic.Handle(route.Method, path, route.HandlerFunc)
			}
		}
	}

	return r
}
