package router

import (
	"github.com/gin-gonic/gin"

	"security-center-backend/internal/handler/agent"
	"security-center-backend/internal/handler/audit"
	"security-center-backend/internal/handler/auth"
	"security-center-backend/internal/handler/health"
	openapistatic "security-center-backend/internal/handler/openapi"
	"security-center-backend/internal/handler/role"
	systemhandler "security-center-backend/internal/handler/system"
	"security-center-backend/internal/handler/user"
	"security-center-backend/internal/middleware"
	alerthandler "security-center-backend/internal/modules/alerts/handler"
	caasmhandler "security-center-backend/internal/modules/caasm/handler"
	depthandler "security-center-backend/internal/modules/department/handler"
	employeehandler "security-center-backend/internal/modules/employee/handler"
	scanhandler "security-center-backend/internal/modules/scan/handler"
	vulnhandler "security-center-backend/internal/modules/vuln/handler"
)

type Dependencies struct {
	Auth                 *auth.Handler
	Health               *health.Handler
	Audit                *audit.Handler
	Users                *user.Handler
	Roles                *role.Handler
	System               *systemhandler.Handler
	Alerts               *alerthandler.Handler
	CAASM                *caasmhandler.Handler
	Scan                 *scanhandler.Handler
	VulnModule           *vulnhandler.Module
	Department           *depthandler.Handler
	Employees            *employeehandler.Handler
	AgentKeys            *agent.Handler
	OpenAPI              *openapistatic.Handler
	AuthMiddleware       gin.HandlerFunc
	AgentAuth            gin.HandlerFunc
	Quota                gin.HandlerFunc
	RequirePermission    func(permission string) gin.HandlerFunc
	AuditTrailMiddleware gin.HandlerFunc
}

func RegisterRoutes(engine *gin.Engine, deps Dependencies) {
	root := engine.Group("")
	deps.Health.RegisterRoutes(root)

	api := engine.Group("/api/v1")
	deps.Auth.RegisterRoutes(api, deps.AuthMiddleware)

	if deps.System != nil {
		publicSystemGroup := api.Group("/system")
		publicSystemGroup.GET("/branding", deps.System.Branding)
	}

	protected := api.Group("")
	if deps.AgentAuth != nil && deps.AuthMiddleware != nil {
		protected.Use(middleware.CombinedAuth(deps.AgentAuth, deps.AuthMiddleware))
	} else if deps.AuthMiddleware != nil {
		protected.Use(deps.AuthMiddleware)
	}
	// Quota 必须在 CombinedAuth 之后装配, 才能读到其写入的 api_key_id。
	if deps.Quota != nil {
		protected.Use(deps.Quota)
	}
	protected.Use(middleware.AgentRouteAllowlist())
	// Apply audit trail middleware after auth middleware so that user is available in context
	if deps.AuditTrailMiddleware != nil {
		protected.Use(deps.AuditTrailMiddleware)
	}

	// Raw Swagger document for OpenAPI tooling; not wrapped in the APIResponse
	// envelope and intentionally not gated by RequirePermission — any
	// authenticated principal (human JWT or agent key) may fetch it.
	if deps.OpenAPI != nil {
		protected.GET("/openapi.json", deps.OpenAPI.GetSpec)
	}

	if deps.Users != nil {
		usersGroup := protected.Group("/users")
		if deps.RequirePermission != nil {
			usersGroup.Use(deps.RequirePermission("auth:manage_users"))
		}
		usersGroup.GET("", deps.Users.List)
		usersGroup.GET(":id", deps.Users.Get)
		usersGroup.PUT(":id", deps.Users.Update)
		usersGroup.POST(":id/link-employee", deps.Users.LinkEmployee)
		usersGroup.POST(":id/roles", deps.Users.AssignRoles)
		usersGroup.DELETE(":id/roles/:roleId", deps.Users.RemoveRole)
	}

	if deps.Roles != nil {
		rolesGroup := protected.Group("/roles")
		if deps.RequirePermission != nil {
			rolesGroup.Use(deps.RequirePermission("auth:manage_users"))
		}
		rolesGroup.GET("", deps.Roles.List)
		rolesGroup.POST("", deps.Roles.Create)
		rolesGroup.PUT(":id", deps.Roles.Update)
		rolesGroup.DELETE(":id", deps.Roles.Delete)
		rolesGroup.POST(":id/permissions", deps.Roles.AssignPermissions)
	}

	if deps.Roles != nil {
		permGroup := protected.Group("/permissions")
		if deps.RequirePermission != nil {
			permGroup.Use(deps.RequirePermission("auth:manage_users"))
		}
		permGroup.GET("", deps.Roles.ListPermissions)
	}
	if deps.System != nil {
		systemGroup := protected.Group("/system")
		if deps.RequirePermission != nil {
			systemGroup.Use(deps.RequirePermission("system:manage_settings"))
		}
		systemGroup.GET("/config", deps.System.GetConfig)
		systemGroup.PUT("/config", deps.System.UpdateConfig)
		systemGroup.GET("/health", deps.System.Health)
		systemGroup.GET("/version", deps.System.Version)
	}

	if deps.Alerts != nil {
		alertsGroup := protected.Group("")
		if deps.RequirePermission != nil {
			alertsGroup.Use(deps.RequirePermission("system:manage_settings"))
		}
		deps.Alerts.RegisterRoutes(alertsGroup)
	}
	if deps.Audit != nil {
		auditGroup := protected.Group("/audit-logs")
		if deps.RequirePermission != nil {
			auditGroup.Use(deps.RequirePermission("audit:view_logs"))
		}
		auditGroup.GET("", deps.Audit.List)
		auditGroup.GET("/stats", deps.Audit.Stats)
		auditGroup.GET(":id", deps.Audit.Get)
		auditGroup.POST("/export", deps.Audit.Export)
	}

	if deps.AgentKeys != nil {
		// whoami 挂在受保护链上但不进 /agent/api-keys 组：不挂
		// agent:manage_own_keys 的 Permission 中间件，任何认证通过的
		// agent Key（含仅 vuln scope 的 Key）或人类 JWT 都可调用，
		// 供 MCP/LLM 调用方解析“我是谁”。
		protected.GET("/agent/whoami", deps.AgentKeys.Whoami)
		agentGroup := protected.Group("/agent/api-keys")
		if deps.RequirePermission != nil {
			agentGroup.Use(deps.RequirePermission("agent:manage_own_keys"))
		}
		deps.AgentKeys.RegisterRoutes(agentGroup)
	}

	if deps.CAASM != nil {
		caasmViewGroup := protected.Group("")
		caasmManageGroup := protected.Group("")
		caasmIngestGroup := protected.Group("")
		if deps.RequirePermission != nil {
			caasmViewGroup.Use(deps.RequirePermission("caasm:view_assets"))
			caasmManageGroup.Use(deps.RequirePermission("caasm:manage_assets"))
		}
		deps.CAASM.RegisterRoutes(caasmViewGroup)
		deps.CAASM.RegisterManageRoutes(caasmManageGroup)
		deps.CAASM.RegisterIngestRoutes(caasmIngestGroup)
		deps.CAASM.RegisterWebhookRoutes(caasmManageGroup)

		portsExportGroup := caasmViewGroup.Group("/caasm/ports")
		if deps.RequirePermission != nil {
			portsExportGroup.Use(deps.RequirePermission("caasm:export_ports"))
		}
		portsExportGroup.GET("/export", deps.CAASM.ExportPorts)

		cloudAccountsView := caasmViewGroup.Group("/caasm/cloud-accounts")
		cloudAccountsManage := caasmManageGroup.Group("/caasm/cloud-accounts")
		deps.CAASM.RegisterCloudAccountRoutes(cloudAccountsView, cloudAccountsManage)

		syncJobsViewGroup := caasmViewGroup.Group("/caasm/sync-jobs")
		syncJobsManageGroup := caasmManageGroup.Group("/caasm/sync-jobs")
		syncJobsIngestGroup := caasmIngestGroup.Group("/caasm/sync-jobs")
		deps.CAASM.RegisterSyncJobRoutes(syncJobsViewGroup, syncJobsManageGroup, syncJobsIngestGroup)

		apiAssetsView := caasmViewGroup.Group("/caasm/api-assets")
		apiAssetsManage := apiAssetsView
		if deps.RequirePermission != nil {
			apiAssetsManage = apiAssetsView.Group("")
			apiAssetsManage.Use(deps.RequirePermission("caasm:manage_api_assets"))
		}
		deps.CAASM.RegisterAPIRouteAssetRoutes(apiAssetsView, apiAssetsManage)
	}

	if deps.VulnModule != nil {
		deps.VulnModule.RegisterRoutes(protected, deps.RequirePermission)
	}

	if deps.Scan != nil {
		scanViewGroup := protected.Group("")
		scanCreateGroup := protected.Group("")
		scanManageGroup := protected.Group("")
		if deps.RequirePermission != nil {
			scanViewGroup.Use(deps.RequirePermission("scan:view_batches"))
			scanCreateGroup.Use(deps.RequirePermission("scan:create_batches"))
			scanManageGroup.Use(deps.RequirePermission("scan:manage_batches"))
		}
		deps.Scan.RegisterViewRoutes(scanViewGroup)
		deps.Scan.RegisterCreateRoutes(scanCreateGroup)
		deps.Scan.RegisterManageRoutes(scanManageGroup)
		deps.Scan.RegisterCallbackRoutes(api)
	}

	if deps.Employees != nil {
		empGroup := protected.Group("/employees")
		if deps.RequirePermission != nil {
			empGroup.Use(deps.RequirePermission("auth:manage_users"))
		}
		deps.Employees.RegisterRoutes(empGroup)
	}

	if deps.Department != nil {
		deptGroup := protected.Group("")
		if deps.RequirePermission != nil {
			deptGroup.Use(deps.RequirePermission("system:manage_settings")) // Or a new permission
		}
		deps.Department.RegisterRoutes(deptGroup)
	}
}
