package main

import (
	"context"
	"fmt"
	"log"

	"photum-backend/docs"
	"photum-backend/internal/agenda"
	"photum-backend/internal/anos_formaturas"
	"photum-backend/internal/auth"
	"photum-backend/internal/availability"
	"photum-backend/internal/cadastro_fot"
	"photum-backend/internal/codigos"
	"photum-backend/internal/config"
	"photum-backend/internal/cursos"
	"photum-backend/internal/db"
	"photum-backend/internal/empresas"
	"photum-backend/internal/escalas"
	"photum-backend/internal/finance"
	"photum-backend/internal/funcoes"
	"photum-backend/internal/notification"

	"photum-backend/internal/logistica"
	"photum-backend/internal/profissionais"
	"photum-backend/internal/storage"
	"photum-backend/internal/tipos_eventos"
	"photum-backend/internal/tipos_servicos"
	"strings"

	"github.com/gin-contrib/cors"

	"github.com/gin-gonic/gin"
	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"
	// "photum-backend/docs" is already imported above
)

// @title           Photum Backend API
// @version         1.0
// @description     Backend authentication service for Photum.
// @termsOfService  http://swagger.io/terms/

// @contact.name    API Support
// @contact.url     http://www.swagger.io/support
// @contact.email   support@swagger.io

// @license.name    Apache 2.0
// @license.url     http://www.apache.org/licenses/LICENSE-2.0.html

// @host            localhost:8080
// @BasePath        /
// @tag.name        auth
// @tag.description Authentication related operations
// @tag.name        admin
// @tag.description Administration operations

// @securityDefinitions.apikey BearerAuth
// @in header
// @name Authorization
func main() {
	fmt.Println("=== PHOTUM BACKEND VERSION: 2.1 (UPDATED_AT SORT) ===")
	cfg := config.LoadConfig()
	log.Printf("Loaded DSN: %s", cfg.DBDsn)

	queries, pool := db.Connect(cfg)
	defer pool.Close()

	// Run Migrations
	db.Migrate(pool)

	// Initialize services
	// Initialize services
	notificationService := notification.NewService()
	profissionaisService := profissionais.NewService(queries)
	financeService := finance.NewService(queries, profissionaisService)
	authService := auth.NewService(queries, profissionaisService, cfg)
	funcoesService := funcoes.NewService(queries)
	cursosService := cursos.NewService(queries)
	empresasService := empresas.NewService(queries)
	anosFormaturasService := anos_formaturas.NewService(queries)
	tiposServicosService := tipos_servicos.NewService(queries)
	tiposEventosService := tipos_eventos.NewService(queries)
	cadastroFotService := cadastro_fot.NewService(queries)
	agendaService := agenda.NewService(queries, notificationService, cfg, financeService)
	availabilityService := availability.NewService(queries)
	s3Service := storage.NewS3Service(cfg)

	// Seed Demo Users
	if err := authService.EnsureDemoUsers(context.Background()); err != nil {
		log.Printf("Failed to seed demo users: %v", err)
	}

	// Initialize handlers
	authHandler := auth.NewHandler(authService, s3Service)
	profissionaisHandler := profissionais.NewHandler(profissionaisService)
	funcoesHandler := funcoes.NewHandler(funcoesService)
	cursosHandler := cursos.NewHandler(cursosService)
	empresasHandler := empresas.NewHandler(empresasService)
	anosFormaturasHandler := anos_formaturas.NewHandler(anosFormaturasService)
	tiposServicosHandler := tipos_servicos.NewHandler(tiposServicosService)
	tiposEventosHandler := tipos_eventos.NewHandler(tiposEventosService)
	cadastroFotHandler := cadastro_fot.NewHandler(cadastroFotService)
	agendaHandler := agenda.NewHandler(agendaService)
	availabilityHandler := availability.NewHandler(availabilityService)
	escalasHandler := escalas.NewHandler(escalas.NewService(queries))
	logisticaHandler := logistica.NewHandler(logistica.NewService(queries, notificationService, cfg))
	codigosHandler := codigos.NewHandler(codigos.NewService(queries))
	financeHandler := finance.NewHandler(financeService)

	r := gin.Default()

	// CORS Middleware
	configCors := cors.DefaultConfig()
	if cfg.CorsAllowedOrigins == "*" {
		configCors.AllowAllOrigins = true
	} else {
		configCors.AllowOrigins = strings.Split(cfg.CorsAllowedOrigins, ",")
	}
	configCors.AllowHeaders = []string{"Origin", "Content-Length", "Content-Type", "Authorization", "x-regiao"}
	r.Use(cors.New(configCors))

	// Swagger
	// Dynamically update Swagger Info
	docs.SwaggerInfo.Host = cfg.SwaggerHost
	if cfg.AppEnv == "production" {
		docs.SwaggerInfo.Schemes = []string{"https", "http"}
	} else {
		docs.SwaggerInfo.Schemes = []string{"http", "https"}
	}

	// Swagger UI - usando URL relativa para funcionar em qualquer ambiente
	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler,
		ginSwagger.PersistAuthorization(true),
		ginSwagger.DeepLinking(true),
		ginSwagger.URL("doc.json"),
	))

	// Public Routes
	authGroup := r.Group("/auth")
	{
		authGroup.POST("/register", authHandler.Register)
		authGroup.POST("/login", authHandler.Login)
		authGroup.POST("/refresh", authHandler.Refresh)
		authGroup.POST("/logout", authHandler.Logout)
		authGroup.POST("/upload-url", authHandler.GetUploadURL)
	}

	// Public API Routes (Data Lists) - Need Region Context
	// Simple middleware to extract x-regiao header for public routes
	publicWithRegion := r.Group("/api")
	publicWithRegion.Use(func(c *gin.Context) {
		regiao := c.GetHeader("x-regiao")
		if regiao == "" {
			regiao = "SP" // Default to SP for public access if not specified
		}
		c.Set("regiao", regiao)
		c.Next()
	})
	{
		publicWithRegion.GET("/funcoes", funcoesHandler.List)
		publicWithRegion.GET("/cursos", cursosHandler.List)
		publicWithRegion.GET("/empresas", empresasHandler.List)
		publicWithRegion.GET("/anos-formaturas", anosFormaturasHandler.List)
		publicWithRegion.GET("/profissionais/check", profissionaisHandler.CheckCPF) // Public Check
		publicWithRegion.GET("/tipos-servicos", tiposServicosHandler.List)
		publicWithRegion.GET("/tipos-eventos", tiposEventosHandler.List)
		publicWithRegion.GET("/tipos-eventos/:id/precos", tiposEventosHandler.ListPrices)
		publicWithRegion.GET("/public/codigos-acesso/verificar", codigosHandler.Verify) // already has explicit handler but consistent context helps
	}

	// Protected Routes
	api := r.Group("/api")
	api.Use(auth.AuthMiddleware(cfg))
	{
		api.GET("/me", authHandler.Me)
		api.PUT("/me", authHandler.UpdateMe)

		profGroup := api.Group("/profissionais")
		{
			profGroup.POST("", profissionaisHandler.Create)
			profGroup.POST("/import", profissionaisHandler.Import)
			profGroup.GET("", profissionaisHandler.List)
			profGroup.GET("/me", profissionaisHandler.Me)
			profGroup.GET("/:id", profissionaisHandler.Get)
			profGroup.PUT("/:id", profissionaisHandler.Update)
			profGroup.DELETE("/:id", profissionaisHandler.Delete)
			// Rota de extrato financeiro (usando agendaHandler por conveniência de serviço)
			profGroup.GET("/me/financial-statement", agendaHandler.GetProfessionalFinancialStatement)
		}

		funcoesGroup := api.Group("/funcoes")
		{
			funcoesGroup.POST("", funcoesHandler.Create)
			funcoesGroup.PUT("/:id", funcoesHandler.Update)
			funcoesGroup.DELETE("/:id", funcoesHandler.Delete)
		}

		// protected CRUD (create/update/delete)
		api.POST("/cursos", cursosHandler.Create)
		api.PUT("/cursos/:id", cursosHandler.Update)
		api.DELETE("/cursos/:id", cursosHandler.Delete)

		api.POST("/empresas", empresasHandler.Create)
		api.PUT("/empresas/:id", empresasHandler.Update)
		api.DELETE("/empresas/:id", empresasHandler.Delete)

		api.POST("/anos-formaturas", anosFormaturasHandler.Create)
		api.PUT("/anos-formaturas/:id", anosFormaturasHandler.Update)
		api.DELETE("/anos-formaturas/:id", anosFormaturasHandler.Delete)

		api.POST("/tipos-servicos", tiposServicosHandler.Create)
		api.PUT("/tipos-servicos/:id", tiposServicosHandler.Update)
		api.DELETE("/tipos-servicos/:id", tiposServicosHandler.Delete)

		api.POST("/tipos-eventos", tiposEventosHandler.Create)
		api.PUT("/tipos-eventos/:id", tiposEventosHandler.Update)
		api.DELETE("/tipos-eventos/:id", tiposEventosHandler.Delete)
		api.POST("/tipos-eventos/precos", tiposEventosHandler.SetPrice)

		api.GET("/cadastro-fot", cadastroFotHandler.List)
		api.POST("/cadastro-fot", cadastroFotHandler.Create)
		api.GET("/cadastro-fot/:id", cadastroFotHandler.Get)
		api.PUT("/cadastro-fot/:id", cadastroFotHandler.Update)
		api.DELETE("/cadastro-fot/:id", cadastroFotHandler.Delete)
		api.POST("/cadastro-fot/:id/finalize", cadastroFotHandler.ToggleFinalizada)
		api.POST("/import/fot", cadastroFotHandler.Import)

		// Agenda routes - read access for AGENDA_VIEWER
		api.GET("/agenda", agendaHandler.List)
		api.GET("/agenda/:id", agendaHandler.Get)
		api.GET("/agenda/:id/professionals", agendaHandler.GetProfessionals)
		api.GET("/agenda/:id/available", agendaHandler.ListAvailableProfessionals)

		// Agenda routes - write access (blocked for AGENDA_VIEWER)
		api.POST("/agenda", auth.RequireWriteAccess(), agendaHandler.Create)
		api.PUT("/agenda/:id", auth.RequireWriteAccess(), agendaHandler.Update)
		api.DELETE("/agenda/:id", auth.RequireWriteAccess(), agendaHandler.Delete)
		api.POST("/agenda/:id/professionals", auth.RequireWriteAccess(), agendaHandler.AssignProfessional)
		api.DELETE("/agenda/:id/professionals/:profId", auth.RequireWriteAccess(), agendaHandler.RemoveProfessional)
		api.PATCH("/agenda/:id/professionals/:profId/status", auth.RequireWriteAccess(), agendaHandler.UpdateAssignmentStatus)
		api.PATCH("/agenda/:id/professionals/:profId/position", auth.RequireWriteAccess(), agendaHandler.UpdateAssignmentPosition)
		api.PUT("/agenda/:id/professionals/:profId/coordinator", auth.RequireWriteAccess(), agendaHandler.SetCoordinator)
		api.PATCH("/agenda/:id/status", auth.RequireWriteAccess(), agendaHandler.UpdateStatus)
		api.POST("/agenda/:id/notify-logistics", auth.RequireWriteAccess(), agendaHandler.NotifyLogistics)
		api.POST("/import/agenda", auth.RequireWriteAccess(), agendaHandler.Import)

		api.POST("/availability", availabilityHandler.SetAvailability)
		api.GET("/availability", availabilityHandler.ListAvailability)

		// Escalas Routes
		api.POST("/escalas", escalasHandler.Create)
		api.GET("/escalas", escalasHandler.ListByAgenda)
		api.DELETE("/escalas/:id", escalasHandler.Delete)
		api.PUT("/escalas/:id", escalasHandler.Update)

		// Logistics Routes - blocked for AGENDA_VIEWER
		logisticaGroup := api.Group("/logistica", auth.RequireLogisticsAccess())
		{
			logisticaGroup.POST("/carros", logisticaHandler.CreateCarro)
			logisticaGroup.GET("/carros", logisticaHandler.ListCarros)
			logisticaGroup.DELETE("/carros/:id", logisticaHandler.DeleteCarro)
			logisticaGroup.PUT("/carros/:id", logisticaHandler.UpdateCarro)

			logisticaGroup.POST("/carros/:id/passageiros", logisticaHandler.AddPassenger)
			logisticaGroup.DELETE("/carros/:id/passageiros/:profID", logisticaHandler.RemovePassenger)
			logisticaGroup.GET("/carros/:id/passageiros", logisticaHandler.ListPassengers)
		}

		codigosGroup := api.Group("/codigos-acesso")
		{
			codigosGroup.POST("", codigosHandler.Create)
			codigosGroup.GET("", codigosHandler.List)
			codigosGroup.DELETE("/:id", codigosHandler.Delete)
		}

		financeGroup := api.Group("/finance")
		{
			financeGroup.POST("", financeHandler.Create)
			financeGroup.POST("/import", financeHandler.Import)
			financeGroup.GET("", financeHandler.List)
			financeGroup.GET("/autofill", financeHandler.AutoFill)
			financeGroup.GET("/fot-events", financeHandler.GetFotEvents)
			financeGroup.GET("/fot-search", financeHandler.SearchFot)
			financeGroup.GET("/professionals", financeHandler.SearchProfessionals)
			financeGroup.GET("/price", financeHandler.GetPrice)
			financeGroup.PUT("/:id", financeHandler.Update)
			financeGroup.DELETE("/:id", financeHandler.Delete)
		}

		admin := api.Group("/admin")
		{
			admin.GET("/users", authHandler.ListUsers)
			admin.GET("/users/pending", authHandler.ListPending)
			admin.GET("/users/:id", authHandler.GetUser)
			admin.PATCH("/users/:id/approve", authHandler.Approve)
			admin.POST("/users", authHandler.AdminCreateUser)
			admin.PATCH("/users/:id/role", authHandler.UpdateRole)
			admin.DELETE("/users/:id", authHandler.DeleteUser)
		}
	}

	log.Printf("Swagger Host Configured: %s", cfg.SwaggerHost)
	log.Printf("Server running on port %s", cfg.AppPort)
	r.Run(":" + cfg.AppPort)
}
