package router

import (
	"eslogad-be/config"
	"eslogad-be/internal/middleware"

	"github.com/gin-gonic/gin"
)

type Router struct {
	config                   *config.Config
	authHandler              AuthHandler
	healthHandler            HealthHandler
	authMiddleware           AuthMiddleware
	userHandler              UserHandler
	fileHandler              FileHandler
	rbacHandler              RBACHandler
	masterHandler            MasterHandler
	letterHandler            LetterHandler
	letterOutgoingHandler    LetterOutgoingHandler
	adminApprovalFlowHandler AdminApprovalFlowHandler
	dispRouteHandler         DispositionRouteHandler
}

func NewRouter(
	cfg *config.Config,
	authHandler AuthHandler,
	authMiddleware AuthMiddleware,
	healthHandler HealthHandler,
	userHandler UserHandler,
	fileHandler FileHandler,
	rbacHandler RBACHandler,
	masterHandler MasterHandler,
	letterHandler LetterHandler,
	letterOutgoingHandler LetterOutgoingHandler,
	adminApprovalFlowHandler AdminApprovalFlowHandler,
	dispRouteHandler DispositionRouteHandler,
) *Router {
	return &Router{
		config:                   cfg,
		authHandler:              authHandler,
		authMiddleware:           authMiddleware,
		healthHandler:            healthHandler,
		userHandler:              userHandler,
		fileHandler:              fileHandler,
		rbacHandler:              rbacHandler,
		masterHandler:            masterHandler,
		letterHandler:            letterHandler,
		letterOutgoingHandler:    letterOutgoingHandler,
		adminApprovalFlowHandler: adminApprovalFlowHandler,
		dispRouteHandler:         dispRouteHandler,
	}
}

func (r *Router) Init() *gin.Engine {
	gin.SetMode(gin.ReleaseMode)
	engine := gin.New()
	engine.Use(
		middleware.JsonAPI(),
		middleware.CorrelationID(),
		middleware.Recover(),
		middleware.HTTPStatLogger(),
		middleware.PopulateContext(),
		middleware.CORS(),
	)

	r.addAppRoutes(engine)
	return engine
}

func (r *Router) addAppRoutes(rg *gin.Engine) {
	rg.GET("/health", r.healthHandler.HealthCheck)

	v1 := rg.Group("/api/v1")
	{
		auth := v1.Group("/auth")
		{
			auth.POST("/login", r.authHandler.Login)
			auth.POST("/refresh", r.authHandler.RefreshToken)
			auth.GET("/profile", r.authHandler.GetProfile)
		}

		users := v1.Group("/users")
		users.Use(r.authMiddleware.RequireAuth())
		{
			users.GET("", r.authMiddleware.RequirePermissions("user.read"), r.userHandler.ListUsers)
			users.GET("/profile", r.userHandler.GetProfile)
			users.GET("/:id/profile", r.userHandler.GetUserProfile)
			users.PUT("/profile", r.userHandler.UpdateProfile)
			users.PUT(":id/password", r.userHandler.ChangePassword)
			users.GET("/titles", r.userHandler.ListTitles)
			users.GET("/mention", r.userHandler.GetActiveUsersForMention)
			users.POST("/profile/avatar", r.fileHandler.UploadProfileAvatar)
		}

		files := v1.Group("/files")
		files.Use(r.authMiddleware.RequireAuth())
		{
			files.POST("/documents", r.fileHandler.UploadDocument)
		}

		rbac := v1.Group("/rbac")
		rbac.Use(r.authMiddleware.RequireAuth())
		{
			rbac.GET("/permissions", r.rbacHandler.ListPermissions)
			rbac.POST("/permissions", r.rbacHandler.CreatePermission)
			rbac.PUT("/permissions/:id", r.rbacHandler.UpdatePermission)
			rbac.DELETE("/permissions/:id", r.rbacHandler.DeletePermission)

			rbac.GET("/roles", r.rbacHandler.ListRoles)
			rbac.POST("/roles", r.rbacHandler.CreateRole)
			rbac.PUT("/roles/:id", r.rbacHandler.UpdateRole)
			rbac.DELETE("/roles/:id", r.rbacHandler.DeleteRole)
		}

		roles := v1.Group("/roles")
		roles.Use(r.authMiddleware.RequireAuth())
		{
			roles.POST("", r.rbacHandler.CreateOrUpdateRole)
			roles.GET("/permissions", r.rbacHandler.GetPermissionsGrouped)
			roles.GET("/:id", r.rbacHandler.GetRoleDetail)
		}

		master := v1.Group("/master")
		master.Use(r.authMiddleware.RequireAuth())
		{
			master.GET("/labels", r.masterHandler.ListLabels)
			master.POST("/labels", r.masterHandler.CreateLabel)
			master.PUT("/labels/:id", r.masterHandler.UpdateLabel)
			master.DELETE("/labels/:id", r.masterHandler.DeleteLabel)

			master.GET("/priorities", r.masterHandler.ListPriorities)
			master.POST("/priorities", r.masterHandler.CreatePriority)
			master.PUT("/priorities/:id", r.masterHandler.UpdatePriority)
			master.DELETE("/priorities/:id", r.masterHandler.DeletePriority)

			master.GET("/institutions", r.masterHandler.ListInstitutions)
			master.POST("/institutions", r.masterHandler.CreateInstitution)
			master.PUT("/institutions/:id", r.masterHandler.UpdateInstitution)
			master.DELETE("/institutions/:id", r.masterHandler.DeleteInstitution)

			master.GET("/disposition-actions", r.masterHandler.ListDispositionActions)
			master.POST("/disposition-actions", r.masterHandler.CreateDispositionAction)
			master.PUT("/disposition-actions/:id", r.masterHandler.UpdateDispositionAction)
			master.DELETE("/disposition-actions/:id", r.masterHandler.DeleteDispositionAction)
		}

		lettersch := v1.Group("/letters")
		lettersch.Use(r.authMiddleware.RequireAuth())
		{
			lettersch.POST("/incoming", r.letterHandler.CreateIncomingLetter)
			lettersch.GET("/incoming/:id", r.letterHandler.GetIncomingLetter)
			lettersch.GET("/incoming", r.letterHandler.ListIncomingLetters)
			lettersch.PUT("/incoming/:id", r.letterHandler.UpdateIncomingLetter)
			lettersch.DELETE("/incoming/:id", r.letterHandler.DeleteIncomingLetter)

			lettersch.POST("/outgoing", r.letterOutgoingHandler.CreateOutgoingLetter)
			lettersch.GET("/outgoing/:id", r.letterOutgoingHandler.GetOutgoingLetter)
			lettersch.GET("/outgoing", r.letterOutgoingHandler.ListOutgoingLetters)
			lettersch.PUT("/outgoing/:id", r.letterOutgoingHandler.UpdateOutgoingLetter)
			lettersch.DELETE("/outgoing/:id", r.letterOutgoingHandler.DeleteOutgoingLetter)

			lettersch.POST("/outgoing/:id/submit", r.letterOutgoingHandler.SubmitForApproval)
			lettersch.POST("/outgoing/:id/approve", r.letterOutgoingHandler.ApproveOutgoingLetter)
			lettersch.POST("/outgoing/:id/reject", r.letterOutgoingHandler.RejectOutgoingLetter)
			lettersch.POST("/outgoing/:id/send", r.letterOutgoingHandler.SendOutgoingLetter)
			lettersch.POST("/outgoing/:id/archive", r.letterOutgoingHandler.ArchiveOutgoingLetter)

			lettersch.POST("/outgoing/:id/recipients", r.letterOutgoingHandler.AddRecipients)
			lettersch.PUT("/outgoing/:id/recipients/:recipient_id", r.letterOutgoingHandler.UpdateRecipient)
			lettersch.DELETE("/outgoing/:id/recipients/:recipient_id", r.letterOutgoingHandler.RemoveRecipient)

			lettersch.POST("/outgoing/:id/attachments", r.letterOutgoingHandler.AddAttachments)
			lettersch.DELETE("/outgoing/:id/attachments/:attachment_id", r.letterOutgoingHandler.RemoveAttachment)

			lettersch.POST("/outgoing/:id/discussions", r.letterOutgoingHandler.CreateDiscussion)
			lettersch.PUT("/outgoing/discussions/:discussion_id", r.letterOutgoingHandler.UpdateDiscussion)
			lettersch.DELETE("/outgoing/discussions/:discussion_id", r.letterOutgoingHandler.DeleteDiscussion)

			lettersch.POST("/dispositions/:letter_id", r.letterHandler.CreateDispositions)
			lettersch.GET("/dispositions/:letter_id", r.letterHandler.GetEnhancedDispositionsByLetter)

			lettersch.POST("/discussions/:letter_id", r.letterHandler.CreateDiscussion)
			lettersch.PUT("/discussions/:letter_id/:discussion_id", r.letterHandler.UpdateDiscussion)
		}

		droutes := v1.Group("/disposition-routes")
		droutes.Use(r.authMiddleware.RequireAuth())
		{
			droutes.POST("", r.dispRouteHandler.Create)
			droutes.GET(":id", r.dispRouteHandler.Get)
			droutes.PUT(":id", r.dispRouteHandler.Update)
			droutes.GET("department", r.dispRouteHandler.ListByFromDept)
			droutes.PUT(":id/active", r.dispRouteHandler.SetActive)
		}

		admin := v1.Group("/setting")
		admin.Use(r.authMiddleware.RequireAuth())
		{
			approvalFlows := admin.Group("/approval-flows")
			{
				approvalFlows.POST("", r.adminApprovalFlowHandler.CreateApprovalFlow)
				approvalFlows.GET("", r.adminApprovalFlowHandler.ListApprovalFlows)
				approvalFlows.GET("/:id", r.adminApprovalFlowHandler.GetApprovalFlow)
				approvalFlows.GET("/department/:department_id", r.adminApprovalFlowHandler.GetApprovalFlowByDepartment)
				approvalFlows.PUT("/:id", r.adminApprovalFlowHandler.UpdateApprovalFlow)
				approvalFlows.DELETE("/:id", r.adminApprovalFlowHandler.DeleteApprovalFlow)
				approvalFlows.POST("/:id/activate", r.adminApprovalFlowHandler.ActivateApprovalFlow)
				approvalFlows.POST("/:id/deactivate", r.adminApprovalFlowHandler.DeactivateApprovalFlow)
				approvalFlows.POST("/:id/clone", r.adminApprovalFlowHandler.CloneApprovalFlow)
			}
		}
	}
}
