package main

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

	"context"
	"encoding/json"
	"lune/talentscale/infra/cache"
	"lune/talentscale/infra/queue"
	"lune/talentscale/internal/config"
	"lune/talentscale/internal/domain"
	assessmentHandler "lune/talentscale/internal/features/assessment/handler"
	assessmentRepo "lune/talentscale/internal/features/assessment/repository"
	assessmentUsecase "lune/talentscale/internal/features/assessment/usecase"
	"lune/talentscale/internal/features/assessment_result"
	authHandler "lune/talentscale/internal/features/auth/handler"
	authUsecase "lune/talentscale/internal/features/auth/usecase"
	candidateHandler "lune/talentscale/internal/features/candidate/handler"
	candidateRepo "lune/talentscale/internal/features/candidate/repository"
	candidateUsecase "lune/talentscale/internal/features/candidate/usecase"
	companyHandler "lune/talentscale/internal/features/company/handler"
	companyRepo "lune/talentscale/internal/features/company/repository"
	companyUsecase "lune/talentscale/internal/features/company/usecase"
	dashboardHandler "lune/talentscale/internal/features/dashboard/handler"
	dashboardRepo "lune/talentscale/internal/features/dashboard/repository"
	dashboardUsecase "lune/talentscale/internal/features/dashboard/usecase"
	"lune/talentscale/internal/features/hr_analytics"
	"lune/talentscale/internal/features/hr_dashboard"
	mediaHandler "lune/talentscale/internal/features/media/handler"
	packageHandler "lune/talentscale/internal/features/package/handler"
	packageRepo "lune/talentscale/internal/features/package/repository"
	packageUsecase "lune/talentscale/internal/features/package/usecase"
	permissionHandler "lune/talentscale/internal/features/permission/handler"
	permissionRepo "lune/talentscale/internal/features/permission/repository"
	permissionUsecase "lune/talentscale/internal/features/permission/usecase"
	"lune/talentscale/internal/features/psikotest"
	questionHandler "lune/talentscale/internal/features/question/handler"
	questionRepo "lune/talentscale/internal/features/question/repository"
	questionUsecase "lune/talentscale/internal/features/question/usecase"
	recruitmentHandler "lune/talentscale/internal/features/recruitment/handler"
	recruitmentRepo "lune/talentscale/internal/features/recruitment/repository"
	recruitmentUsecase "lune/talentscale/internal/features/recruitment/usecase"
	resultSvc "lune/talentscale/internal/features/result_service"
	roleHandler "lune/talentscale/internal/features/role/handler"
	roleRepo "lune/talentscale/internal/features/role/repository"
	roleUsecase "lune/talentscale/internal/features/role/usecase"
	"lune/talentscale/internal/features/scoring"
	subscriptionHandler "lune/talentscale/internal/features/subscription/handler"
	subscriptionRepo "lune/talentscale/internal/features/subscription/repository"
	subscriptionUsecase "lune/talentscale/internal/features/subscription/usecase"
	systemRepo "lune/talentscale/internal/features/system/repository"
	testTypeHandler "lune/talentscale/internal/features/test_type/handler"
	testTypeRepo "lune/talentscale/internal/features/test_type/repository"
	testTypeUsecase "lune/talentscale/internal/features/test_type/usecase"
	userHandler "lune/talentscale/internal/features/user/handler"
	userRepo "lune/talentscale/internal/features/user/repository"
	userUsecase "lune/talentscale/internal/features/user/usecase"
	"lune/talentscale/internal/middleware"

	testSessionHandler "lune/talentscale/internal/features/test_session/handler"
	testSessionRepo "lune/talentscale/internal/features/test_session/repository"
	testSessionUsecase "lune/talentscale/internal/features/test_session/usecase"

	// Billing Module (Clean Architecture)
	billingHandlers "lune/talentscale/internal/modules/billing/handlers"
	billingRepo "lune/talentscale/internal/modules/billing/repositories"
	billingRoutes "lune/talentscale/internal/modules/billing/routes"
	billingServices "lune/talentscale/internal/modules/billing/services"

	"lune/talentscale/internal/pkg/email"
	firebasePkg "lune/talentscale/internal/pkg/firebase"
	"lune/talentscale/pkg/database"
	"lune/talentscale/pkg/logger"
	"lune/talentscale/pkg/response"
	"time"

	"github.com/gofiber/fiber/v2"
	"github.com/gofiber/fiber/v2/middleware/cors"
	"github.com/gofiber/fiber/v2/middleware/recover"
)

func main() {
	// ─── 1. Config ───────────────────────────────────────────────────────────────
	cfg := config.LoadConfig()

	// ─── 1b. Cache ───────────────────────────────────────────────────────────────
	cache.InitRedis(cfg.RedisHost, cfg.RedisPort, cfg.RedisPassword, cfg.RedisDB)

	// ─── 2. Database ─────────────────────────────────────────────────────────────
	db := database.NewPostgresDB(cfg.DatabaseURL)
	defer db.Close()

	// ─── 2b. Firebase ────────────────────────────────────────────────────────────
	fbApp, err := config.InitFirebase(cfg.FirebaseCredentialsPath)
	if err != nil {
		log.Fatalf("Firebase initialization failed: %v", err)
	}
	storageService := firebasePkg.NewStorageService(fbApp, cfg.FirebaseBucket)

	// ─── 2c. System Logger ───────────────────────────────────────────────────────
	sysLogRepo := systemRepo.NewPostgresSystemLogRepository(db)
	logger.Init(sysLogRepo, cfg.LogAsync)

	// ─── 3. Repositories ─────────────────────────────────────────────────────────
	uRepo := userRepo.NewPostgresUserRepository(db)
	pRepo := packageRepo.NewPostgresPackageRepository(db)
	cRepo := companyRepo.NewPostgresCompanyRepository(db)
	candRepo := candidateRepo.NewPostgresCandidateRepository(db)
	subRepo := subscriptionRepo.NewPostgresSubscriptionRepository(db)
	assRepo := assessmentRepo.NewPostgresAssessmentRepository(db)
	rRepo := roleRepo.NewPostgresRoleRepository(db)
	permRepo := permissionRepo.NewPostgresPermissionRepository(db)
	ttRepo := testTypeRepo.NewPostgresTestTypeRepository(db)
	qRepo := questionRepo.NewPostgresQuestionRepository(db)
	dashRepo := dashboardRepo.NewPostgresDashboardRepository(db)
	recruitRepo := recruitmentRepo.NewPostgresRecruitmentRepository(db)
	tsRepo := testSessionRepo.NewPostgresTestSessionRepository(db)

	// ─── 3b. Shared Services ─────────────────────────────────────────────────────
	emailSvc := email.NewServiceFromEnv()

	// ─── 4. Usecases ─────────────────────────────────────────────────────────────
	aUsecase := authUsecase.NewAuthUsecase(uRepo, rRepo, cfg.JWTSecret)
	uUsecase := userUsecase.NewUserUsecase(uRepo)
	pUsecase := packageUsecase.NewPackageUsecase(pRepo)
	compUsecase := companyUsecase.NewCompanyUsecase(cRepo)
	candUsecase := candidateUsecase.NewCandidateUsecase(candRepo, emailSvc)
	subUsecase := subscriptionUsecase.NewSubscriptionUsecase(subRepo, pRepo)
	assUsecase := assessmentUsecase.NewAssessmentUsecase(assRepo, cache.Client)
	rUsecase := roleUsecase.NewRoleUsecase(rRepo)
	pUsecasePerm := permissionUsecase.NewPermissionUsecase(permRepo)
	ttUsecase := testTypeUsecase.NewTestTypeUsecase(ttRepo)
	qUsecase := questionUsecase.NewQuestionUsecase(qRepo)
	tsUsecase := testSessionUsecase.NewTestSessionUsecase(tsRepo, candRepo, uRepo, rRepo, emailSvc)
	dashUsecase := dashboardUsecase.NewDashboardUsecase(dashRepo)
	recruitUsecase := recruitmentUsecase.NewRecruitmentUsecase(recruitRepo, candRepo, assUsecase)

	// ─── 4b. Background Workers ──────────────────────────────────────────────────
	jobHandler := func(job queue.Job) error {
		switch job.Type {
		case "submit_test":
			var answer domain.CandidateAnswer
			payloadBytes, _ := json.Marshal(job.Payload)
			if err := json.Unmarshal(payloadBytes, &answer); err != nil {
				return err
			}
			return assUsecase.SubmitAnswer(context.Background(), &answer)
		default:
			return fmt.Errorf("unknown job type: %s", job.Type)
		}
	}
	queue.StartWorkerPool(cfg.QueueWorkerCount, jobHandler)

	// ─── 4c. Retention Worker ────────────────────────────────────────────────────
	go func() {
		ticker := time.NewTicker(24 * time.Hour)
		for range ticker.C {
			log.Println("🧹 Cleaning up old logs (30 days retention)...")
			ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
			if err := sysLogRepo.DeleteOldLogs(ctx, 30); err != nil {
				log.Printf("⚠️ Cleanup failed: %v", err)
			}
			cancel()
		}
	}()

	// ─── 5. Handlers ─────────────────────────────────────────────────────────────
	aHandler := authHandler.NewAuthHandler(aUsecase)
	pHandler := packageHandler.NewPackageHandler(pUsecase)
	compHandler := companyHandler.NewCompanyHandler(compUsecase)
	candHandler := candidateHandler.NewCandidateHandler(candUsecase)
	subHandler := subscriptionHandler.NewSubscriptionHandler(subUsecase)
	assHandler := assessmentHandler.NewAssessmentHandler(assUsecase)
	rHandler := roleHandler.NewRoleHandler(rUsecase)
	permHandler := permissionHandler.NewPermissionHandler(pUsecasePerm)
	userHandler := userHandler.NewUserHandler(uUsecase)
	ttHandler := testTypeHandler.NewTestTypeHandler(ttUsecase)
	qHandler := questionHandler.NewQuestionHandler(qUsecase)
	dashHandler := dashboardHandler.NewDashboardHandler(dashUsecase)
	recruitHandler := recruitmentHandler.NewRecruitmentHandler(recruitUsecase)
	mHandler := mediaHandler.NewMediaHandler(storageService)
	tsHandler := testSessionHandler.NewTestSessionHandler(tsUsecase, uRepo)

	// Result Service (Centralized Calculation Pipeline)
	resultRepo := resultSvc.NewRepository(db)
	resultService := resultSvc.NewService(resultRepo)

	// Psikotest Engine — inject ResultService via function type to break import cycle
	psikoRepo := psikotest.NewRepository(db)
	psikoService := psikotest.NewService(psikoRepo, resultService.CalculateAndSave)
	psikoHandler := psikotest.NewHandler(psikoService)

	// Scoring Engine
	scRepo := scoring.NewRepository(db)
	scService := scoring.NewService(scRepo)
	scHandler := scoring.NewHandler(scService)

	// Assessment Result Engine (Universal)
	arRepo := assessment_result.NewRepository(db)
	arService := assessment_result.NewService(arRepo)
	arHandler := assessment_result.NewHandler(arService)

	// ─── Billing Module (Clean Architecture) ──────────────────────────────────
	bRepo := billingRepo.NewBillingPostgresRepository(db)
	midtransSvc := billingServices.NewMidtransService()
	billingEmailSvc := billingServices.NewEmailService(bRepo)
	cacheAdapter := billingServices.NewRedisCacheAdapter()
	bService := billingServices.NewBillingService(bRepo, midtransSvc, billingEmailSvc, cacheAdapter)

	checkoutH := billingHandlers.NewCheckoutHandler(bService)
	invoiceH := billingHandlers.NewInvoiceHandler(bService)
	subH := billingHandlers.NewSubscriptionHandler(bService)
	pkgH := billingHandlers.NewPackageHandler(bService)
	webhookH := billingHandlers.NewWebhookHandler(bService)

	// HR Dashboard & Analytics
	hrDashRepo := hr_dashboard.NewRepository(db)
	hrDashService := hr_dashboard.NewService(hrDashRepo, bRepo)
	hrDashHandler := hr_dashboard.NewHandler(hrDashService)

	hrAnalyticsRepo := hr_analytics.NewRepository(db)
	hrAnalyticsSvc := hr_analytics.NewService(hrAnalyticsRepo)
	hrAnalyticsHandler := hr_analytics.NewHandler(hrAnalyticsSvc)

	// ─── 6. Fiber App ────────────────────────────────────────────────────────────
	app := fiber.New(fiber.Config{
		AppName: "TalentScale SaaS API",
		ErrorHandler: func(c *fiber.Ctx, err error) error {
			code := fiber.StatusInternalServerError
			if e, ok := err.(*fiber.Error); ok {
				code = e.Code
			}
			return response.Error(c, code, err.Error())
		},
	})

	// ─── 7. Global Middlewares ───────────────────────────────────────────────────
	app.Use(recover.New())
	// PRO MONITORING UPGRADE
	app.Use(middleware.MonitoringMiddleware())

	app.Use(cors.New(cors.Config{
		AllowOrigins: "*",
		AllowHeaders: "Origin, Content-Type, Accept, Authorization, x-company-id",
		AllowMethods: "GET, POST, PUT, PATCH, DELETE, OPTIONS",
	}))

	// ─── 8. Routes ───────────────────────────────────────────────────────────────
	apiV1 := app.Group("/api/v1")

	// Public Routes (No Auth)
	public := apiV1.Group("/public")
	public.Get("/packages", func(c *fiber.Ctx) error {
		log.Println("GET /api/v1/public/packages hit")
		return pHandler.ListActive(c)
	})
	public.Get("/test-types", ttHandler.ListActive)
	public.Get("/report-previews", func(c *fiber.Ctx) error {
		previews := []fiber.Map{
			{
				"id":          "disc",
				"name":        "DISC Analysis",
				"type":        "Behavioral",
				"description": "Dominance, Influence, Steadiness, and Compliance metrics.",
				"mock_data": fiber.Map{
					"dominance":  75,
					"influence":  60,
					"steadiness": 45,
					"compliance": 80,
				},
			},
			{
				"id":          "mbti",
				"name":        "MBTI Personality",
				"type":        "Personality",
				"description": "16 personality types based on Jungian theory.",
				"mock_data": fiber.Map{
					"type": "ENTJ",
					"traits": fiber.Map{
						"extroversion": 85,
						"intuition":    70,
						"thinking":     90,
						"judging":      75,
					},
				},
			},
			{
				"id":          "cfit",
				"name":        "CFIT IQ Test",
				"type":        "Cognitive",
				"description": "Culture Fair Intelligence Test for objective IQ measurement.",
				"mock_data": fiber.Map{
					"iq_score":   125,
					"percentile": 95,
					"category":   "Superior",
				},
			},
		}
		return response.OK(c, "Report previews retrieved", previews)
	})

	api := apiV1
	auth := middleware.AuthMiddleware(cfg.JWTSecret)
	tenant := middleware.TenantMiddleware()

	// General Rate Limit (60/min)
	if cfg.RateLimitEnabled {
		api.Use(middleware.RateLimiter(60, 1*time.Minute, "general"))
	}

	// Health
	api.Get("/health", func(c *fiber.Ctx) error {
		return c.JSON(fiber.Map{"success": true, "message": "OK"})
	})

	// ── Auth (Public) ────────────────────────────────────────────────────────────
	// Login Rate Limit (5/min)
	if cfg.RateLimitEnabled {
		api.Post("/auth/login", middleware.RateLimiter(5, 1*time.Minute, "login"), aHandler.Login)
	} else {
		api.Post("/auth/login", aHandler.Login)
	}
	api.Post("/auth/register", aHandler.Register)
	api.Get("/auth/me", auth, aHandler.Me)
	api.Post("/auth/logout", auth, aHandler.Logout)

	// ── Upload (Protected) ──────────────────────────────────────────────────────
	api.Post("/upload", auth, mHandler.Upload)

	// ── Packages ─────────────────────────────────────────────────────────────────
	// Protected by RBAC
	api.Get("/packages", auth, tenant, middleware.PermissionMiddleware(rRepo, "package.read"), pHandler.List)
	api.Get("/packages/:id", auth, tenant, middleware.PermissionMiddleware(rRepo, "package.read"), pHandler.GetByID)
	api.Post("/packages", auth, tenant, middleware.PermissionMiddleware(rRepo, "package.create"), pHandler.Create)
	api.Put("/packages/:id", auth, tenant, middleware.PermissionMiddleware(rRepo, "package.update"), pHandler.Update)
	api.Delete("/packages/:id", auth, tenant, middleware.PermissionMiddleware(rRepo, "package.delete"), pHandler.Delete)

	// ── Companies ────────────────────────────────────────────────────────────────
	api.Post("/companies/register", compHandler.Register)
	api.Post("/companies", auth, middleware.PermissionMiddleware(rRepo, "company.create"), compHandler.Register)
	// Protected by RBAC
	api.Get("/companies", auth, middleware.PermissionMiddleware(rRepo, "company.read"), compHandler.List)
	api.Get("/companies/:id", auth, middleware.PermissionMiddleware(rRepo, "company.read"), compHandler.GetByID)
	api.Put("/companies/:id", auth, middleware.PermissionMiddleware(rRepo, "company.update"), compHandler.Update)
	api.Patch("/companies/:id/suspend", auth, middleware.PermissionMiddleware(rRepo, "company.update"), compHandler.Suspend)
	api.Patch("/companies/:id/activate", auth, middleware.PermissionMiddleware(rRepo, "company.update"), compHandler.Activate)

	// ── Subscriptions ────────────────────────────────────────────────────────────
	api.Post("/subscriptions", auth, middleware.PermissionMiddleware(rRepo, "subscription.create"), subHandler.Subscribe)
	api.Get("/subscriptions/active", auth, middleware.PermissionMiddleware(rRepo, "subscription.read"), subHandler.GetActive)

	// ── Candidates ───────────────────────────────────────────────────────────────
	api.Post("/candidates", auth, tenant, middleware.PermissionMiddleware(rRepo, "candidate.create"), candHandler.Create)
	api.Post("/candidates/bulk-invite", auth, tenant, middleware.PermissionMiddleware(rRepo, "candidate.create"), candHandler.BulkInvite)
	api.Get("/candidates", auth, tenant, middleware.PermissionMiddleware(rRepo, "candidate.read"), candHandler.List)
	api.Get("/candidates/:id", auth, tenant, middleware.PermissionMiddleware(rRepo, "candidate.read"), candHandler.GetByID)
	api.Put("/candidates/:id", auth, tenant, middleware.PermissionMiddleware(rRepo, "candidate.update"), candHandler.Update)
	api.Delete("/candidates/:id", auth, tenant, middleware.PermissionMiddleware(rRepo, "candidate.delete"), candHandler.Delete)

	// ── Dashboard ────────────────────────────────────────────────────────────────
	api.Get("/dashboard", auth, middleware.PermissionMiddleware(rRepo, "dashboard.read"), dashHandler.GetStats)

	// ── Assessments ──────────────────────────────────────────────────────────────
	api.Post("/assessments/start", auth, middleware.PermissionMiddleware(rRepo, "assessment.create"), assHandler.StartSession)
	api.Get("/assessments/sessions/:id/questions", auth, middleware.PermissionMiddleware(rRepo, "assessment.read"), assHandler.GetQuestions)

	// Submit Rate Limit (10/min)
	if cfg.RateLimitEnabled {
		api.Post("/assessments/sessions/:id/submit", auth, middleware.PermissionMiddleware(rRepo, "assessment.update"), middleware.RateLimiter(10, 1*time.Minute, "submit"), assHandler.SubmitAnswer)
	} else {
		api.Post("/assessments/sessions/:id/submit", auth, middleware.PermissionMiddleware(rRepo, "assessment.update"), assHandler.SubmitAnswer)
	}

	api.Post("/assessments/sessions/:id/complete", auth, middleware.PermissionMiddleware(rRepo, "assessment.update"), assHandler.CompleteSession)
	api.Get("/assessments/sessions/:id/results", auth, middleware.PermissionMiddleware(rRepo, "assessment.read"), assHandler.GetDISCResults)
	api.Get("/assessments/sessions/:id/results/mbti", auth, middleware.PermissionMiddleware(rRepo, "assessment.read"), assHandler.GetMBTIResults)

	// Universal Assessment Results (New Engine)
	// matikan dahulu middlewarenya
	// ex middleware.PermissionMiddleware(rRepo, "assessment.results")
	api.Get("/assessments/results", auth, tenant, arHandler.GetAllResult)
	api.Get("/assessments/results/:sessionId", auth, tenant, arHandler.GetResult)
	api.Get("/assessment-results/:candidateId", auth, tenant, arHandler.GetCandidateReport)

	// ── Recruitment (Public) ─────────────────────────────────────────────────────
	// api.Get("/public/jobs", recruitHandler.ListPublicJobs)
	// api.Get("/public/jobs/:id", recruitHandler.GetJobDetail)
	// api.Post("/public/apply", recruitHandler.Apply)

	// ── Recruitment (Admin) ──────────────────────────────────────────────────────
	api.Get("/jobs", auth, middleware.PermissionMiddleware(rRepo, "job.read"), recruitHandler.ManageJobs)
	api.Post("/jobs", auth, middleware.PermissionMiddleware(rRepo, "job.create"), recruitHandler.CreateJob)
	api.Put("/jobs/:id", auth, middleware.PermissionMiddleware(rRepo, "job.update"), recruitHandler.UpdateJob)
	api.Get("/applications", auth, middleware.PermissionMiddleware(rRepo, "application.read"), recruitHandler.ListApplications)
	api.Patch("/applications/:id/status", auth, middleware.PermissionMiddleware(rRepo, "application.update"), recruitHandler.UpdateStatus)

	// ── Roles & Permissions ──────────────────────────────────────────────────────
	api.Get("/roles", auth, middleware.PermissionMiddleware(rRepo, "role.read"), rHandler.List)
	api.Get("/roles/:id", auth, middleware.PermissionMiddleware(rRepo, "role.read"), rHandler.GetByID)
	api.Post("/roles", auth, middleware.PermissionMiddleware(rRepo, "role.create"), rHandler.Create)
	api.Put("/roles/:id", auth, middleware.PermissionMiddleware(rRepo, "role.update"), rHandler.Update)
	api.Delete("/roles/:id", auth, middleware.PermissionMiddleware(rRepo, "role.delete"), rHandler.Delete)

	api.Get("/roles/:id/permissions", auth, middleware.PermissionMiddleware(rRepo, "role.read"), rHandler.GetPermissions)
	api.Post("/roles/:id/permissions/sync", auth, middleware.PermissionMiddleware(rRepo, "role.update"), rHandler.SyncPermissions)

	api.Get("/permissions", auth, middleware.PermissionMiddleware(rRepo, "permission.read"), permHandler.List)
	api.Get("/permissions/:id", auth, middleware.PermissionMiddleware(rRepo, "permission.read"), permHandler.GetByID)
	api.Post("/permissions", auth, middleware.PermissionMiddleware(rRepo, "permission.create"), permHandler.Create)
	api.Put("/permissions/:id", auth, middleware.PermissionMiddleware(rRepo, "permission.update"), permHandler.Update)
	api.Delete("/permissions/:id", auth, middleware.PermissionMiddleware(rRepo, "permission.delete"), permHandler.Delete)

	// ── Users ──────────────────────────────────────────────────────────────
	// Protected by RBAC
	api.Post("/users", auth, tenant, middleware.PermissionMiddleware(rRepo, "user.create"), userHandler.Create)
	api.Get("/users", auth, tenant, middleware.PermissionMiddleware(rRepo, "user.read"), userHandler.List)
	api.Get("/users/:id", auth, tenant, middleware.PermissionMiddleware(rRepo, "user.read"), userHandler.GetByID)
	api.Put("/users/:id", auth, tenant, middleware.PermissionMiddleware(rRepo, "user.update"), userHandler.Update)
	api.Delete("/users/:id", auth, tenant, middleware.PermissionMiddleware(rRepo, "user.delete"), userHandler.Delete)

	// ── Test Types ─────────────────────────────────────────────────────────────
	api.Get("/test-types", auth, middleware.PermissionMiddleware(rRepo, "test_type.read"), ttHandler.List)
	api.Get("/test-types/:id", auth, middleware.PermissionMiddleware(rRepo, "test_type.read"), ttHandler.GetByID)
	api.Post("/test-types", auth, middleware.PermissionMiddleware(rRepo, "test_type.create"), ttHandler.Create)
	api.Put("/test-types/:id", auth, middleware.PermissionMiddleware(rRepo, "test_type.update"), ttHandler.Update)
	api.Delete("/test-types/:id", auth, middleware.PermissionMiddleware(rRepo, "test_type.delete"), ttHandler.Delete)

	// ── Questions ──────────────────────────────────────────────────────────────
	api.Get("/test-types/:test_type_id/questions", auth, middleware.PermissionMiddleware(rRepo, "question.read"), qHandler.ListByTestType)
	api.Get("/questions/:id", auth, middleware.PermissionMiddleware(rRepo, "question.read"), qHandler.GetByID)
	api.Post("/questions", auth, middleware.PermissionMiddleware(rRepo, "question.create"), qHandler.Create)
	api.Put("/questions/:id", auth, middleware.PermissionMiddleware(rRepo, "question.update"), qHandler.Update)
	api.Delete("/questions/:id", auth, middleware.PermissionMiddleware(rRepo, "question.delete"), qHandler.Delete)

	// ── Test Sessions ───────────────────────────────────────────────────────────
	// api.Post("/hr/test-sessions", auth, tenant, middleware.PermissionMiddleware(rRepo, "test_session.create"), tsHandler.CreateSession)
	// disable auth for n8n purpose only
	api.Post("/hr/test-sessions", tsHandler.CreateSession)
	api.Get("/hr/test-sessions", auth, tenant, middleware.PermissionMiddleware(rRepo, "test_session.read"), tsHandler.ListSessions)
	api.Get("/hr/test-sessions/:id", auth, tenant, middleware.PermissionMiddleware(rRepo, "test_session.read"), tsHandler.GetSession)

	// ── HR Dashboard, Reports & Analytics (Phase 1) ─────────────────────────────
	api.Get("/hr/dashboard/summary", auth, tenant, hrDashHandler.HandleSummary)
	api.Get("/hr/dashboard/analytics", auth, tenant, hrDashHandler.HandleAnalytics)

	api.Get("/hr/reports", auth, tenant, arHandler.GetAllResult)
	api.Get("/hr/reports/:candidateId", auth, tenant, arHandler.GetCandidateReport)

	api.Get("/hr/analytics/overview", auth, tenant, hrAnalyticsHandler.GetOverview)

	// ── HR Billing Aliases (Phase 2) ──────────────────────────────────────────
	api.Get("/hr/billing/subscription", auth, tenant, subH.GetActive)
	api.Get("/hr/billing/invoices", auth, tenant, invoiceH.ListInvoices)
	api.Get("/hr/billing/invoices/:id", auth, tenant, invoiceH.GetInvoiceDetail)

	// ── Psikotest Engine (Simple Flow) ──────────────────────────────────────────
	psikoEngine := api.Group("/psikotest")
	psikoHandler.RegisterRoutes(psikoEngine)

	// ── Scoring Engine ──────────────────────────────────────────────────────────
	scoringEngine := api.Group("/scoring")
	scoringEngine.Post("/:sessionId/calculate", scHandler.CalculateScore)

	// ── Billing Module Routes ──────────────────────────────────────────────────
	billingRoutes.RegisterBillingRoutes(
		apiV1,
		cfg.JWTSecret,
		checkoutH,
		invoiceH,
		subH,
		pkgH,
		webhookH,
		cfg.RateLimitEnabled,
	)

	// ─── 9. Start Server ─────────────────────────────────────────────────────────
	go func() {
		log.Printf("🚀 TalentScale API listening on :%s\n", cfg.AppPort)

		if err := app.Listen(":" + cfg.AppPort); err != nil {
			log.Fatalf("Server error: %v", err)
		}
	}()

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

	<-quit

	log.Println("⏳ Shutting down gracefully...")

	// channel buat monitor shutdown selesai
	done := make(chan struct{})

	go func() {
		defer close(done)

		if err := app.Shutdown(); err != nil {
			log.Printf("Shutdown error: %v\n", err)
		}
	}()

	select {
	case <-done:
		log.Println("✅ Server stopped gracefully.")
	case <-time.After(3 * time.Second):
		log.Println("🔥 Force shutdown after timeout.")
		os.Exit(0)
	}
}
