// Package org contains browser-facing organization administration routes.
package org

import (
	"log/slog"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/knowledgeqa/protocol"
	"github.com/tidbcloud/AgentTeam/internal/mailer"
)

func handleOrgAuth(handler api.AuthHandler) gin.HandlerFunc {
	return api.HandleAuth(handler)
}

func handleOrgAuthJSON[T any](handler func(api.AuthenticatedJSON[T]) (api.Response, error)) gin.HandlerFunc {
	return api.HandleAuthJSON[T](handler)
}

// Dependencies contains collaborators and config for organization routes.
type Dependencies struct {
	Store                     Store
	Organizations             OrganizationProvider
	PlanStore                 PlanStore
	Runtime                   Runtime
	LLMRegistry               LLMRegistryRefresher
	HostedAvailability        HostedAvailabilityClient
	KnowledgeQAPolicies       KnowledgeQAPolicyStore
	Mailer                    mailer.Mailer
	EmailVerificationRequired bool
	Logger                    *slog.Logger
}

// RegisterRoutes mounts organization administration routes.
func RegisterRoutes(router gin.IRouter, dependencies Dependencies) {
	if router == nil {
		return
	}
	routes := router.Group(
		"/api/v1/orgs",
		api.RequireAuthenticatedUser(dependencies.Store),
		api.RequireVerifiedIdentity(dependencies.EmailVerificationRequired),
	)
	registerOrganizationRoutes(routes, dependencies)
}

func registerOrganizationRoutes(routes gin.IRoutes, dependencies Dependencies) {
	base := organizationHandlerBase{
		organizations:       dependencies.Organizations,
		planStore:           dependencies.PlanStore,
		runtime:             dependencies.Runtime,
		llmRegistry:         dependencies.LLMRegistry,
		hostedModels:        dependencies.HostedAvailability,
		knowledgeQAPolicies: dependencies.KnowledgeQAPolicies,
		mailer:              dependencies.Mailer,
		logger:              dependencies.Logger,
	}
	collection := &CollectionHandler{organizationHandlerBase: base}
	settings := &SettingsHandler{organizationHandlerBase: base}
	hostedModels := &HostedModelHandler{organizationHandlerBase: base}
	knowledgeQA := &KnowledgeQAPolicyHandler{organizationHandlerBase: base}
	plans := &PlanHandler{organizationHandlerBase: base}
	feishu := &FeishuHandler{organizationHandlerBase: base}
	invites := &InviteHandler{organizationHandlerBase: base}
	units := &UnitHandler{organizationHandlerBase: base}
	teams := &TeamHandler{organizationHandlerBase: base}
	members := &MemberHandler{organizationHandlerBase: base}
	workspaces := &WorkspaceAccessHandler{organizationHandlerBase: base}
	providers := &ProviderHandler{organizationHandlerBase: base}

	routes.GET("", handleOrgAuth(collection.List))
	routes.PATCH("/:orgId", handleOrgAuthJSON(collection.Patch))
	routes.GET("/:orgId/settings", handleOrgAuth(settings.Get))
	routes.GET("/:orgId/hosted-models", handleOrgAuth(hostedModels.ModelsList))
	routes.GET("/:orgId/hosted-model-settings", handleOrgAuth(hostedModels.SettingsGet))
	routes.PATCH("/:orgId/hosted-model-settings", handleOrgAuthJSON(hostedModels.SettingsPatch))
	routes.GET("/:orgId/knowledge-qa-policy", handleOrgAuth(knowledgeQA.Get))
	routes.PUT("/:orgId/knowledge-qa-policy", handleOrgAuthJSON[protocol.OrganizationPolicyUpdate](knowledgeQA.Put))
	routes.GET("/:orgId/knowledge-qa-policy/metrics", handleOrgAuth(knowledgeQA.Metrics))
	routes.GET("/:orgId/plan", handleOrgAuth(plans.Get))
	routes.GET("/:orgId/directory-sync-runs/:syncRunId", handleOrgAuth(settings.DirectorySyncRunGet))
	routes.PATCH("/:orgId/settings", handleOrgAuthJSON(settings.Patch))
	routes.GET("/:orgId/enterprise/feishu", handleOrgAuth(feishu.GetEnterprise))
	routes.PUT("/:orgId/enterprise/feishu/credentials", handleOrgAuthJSON(feishu.SetCredentials))
	routes.DELETE("/:orgId/enterprise/feishu/credentials", handleOrgAuth(feishu.DeleteCredentials))
	routes.POST("/:orgId/feishu/sync", handleOrgAuth(feishu.Sync))
	routes.GET("/:orgId/invites", handleOrgAuth(invites.List))
	routes.POST("/:orgId/invites", handleOrgAuthJSON(invites.Create))
	routes.DELETE("/:orgId/invites/:inviteId", handleOrgAuth(invites.Delete))
	routes.GET("/:orgId/units", handleOrgAuth(units.List))
	routes.POST("/:orgId/units", handleOrgAuthJSON(units.Create))
	routes.GET("/:orgId/units/:unitId/members", handleOrgAuth(units.ListMembers))
	routes.POST("/:orgId/units/:unitId/members", handleOrgAuthJSON(units.CreateMember))
	routes.DELETE("/:orgId/units/:unitId/members/:memberId", handleOrgAuth(units.RemoveMember))
	routes.GET("/:orgId/teams", handleOrgAuth(teams.List))
	routes.POST("/:orgId/teams", handleOrgAuthJSON(teams.Create))
	routes.GET("/:orgId/teams/:teamId/members", handleOrgAuth(teams.ListMembers))
	routes.POST("/:orgId/teams/:teamId/members", handleOrgAuthJSON(teams.CreateMember))
	routes.DELETE("/:orgId/teams/:teamId/members/:memberId", handleOrgAuth(teams.RemoveMember))
	routes.GET("/:orgId/members", handleOrgAuth(members.List))
	routes.POST("/:orgId/members", handleOrgAuthJSON(members.Create))
	routes.GET("/:orgId/members/:memberId/removal-impact", handleOrgAuth(members.RemovalImpact))
	routes.DELETE("/:orgId/members/:memberId", handleOrgAuth(members.Remove))
	routes.GET("/:orgId/members/:memberId/units", handleOrgAuth(members.ListUnits))
	routes.PATCH("/:orgId/members/:memberId/primary-team", handleOrgAuthJSON(members.UpdatePrimaryTeam))
	routes.PATCH("/:orgId/members/:memberId/role", handleOrgAuthJSON(members.UpdateRole))
	routes.GET("/:orgId/workspaces", handleOrgAuth(workspaces.List))
	routes.POST("/:orgId/workspaces", handleOrgAuthJSON(workspaces.Create))
	routes.GET("/:orgId/providers", providers.List)
	routes.GET("/:orgId/llm-stats/summary", providers.LLMStatsSummary)
	routes.GET("/:orgId/llm-stats/detail", providers.LLMStatsDetail)
	routes.GET("/:orgId/llm-stats/timeseries", providers.LLMStatsTimeSeries)
	routes.GET("/:orgId/llm-stats/errors/summary", providers.LLMStatsErrorsSummary)
	routes.GET("/:orgId/llm-stats/errors/timeseries", providers.LLMStatsErrorsTimeSeries)
	routes.GET("/:orgId/llm-quota-policies", providers.LLMQuotaPoliciesList)
	routes.PUT("/:orgId/llm-quota-policies/:subjectType/:subjectId", providers.LLMQuotaPolicyUpsert)
	routes.DELETE("/:orgId/llm-quota-policies/:subjectType/:subjectId", providers.LLMQuotaPolicyDelete)
	routes.GET("/:orgId/llm-proxy-keys", providers.LLMProxyKeysList)
	routes.POST("/:orgId/llm-proxy-keys", providers.LLMProxyKeyCreate)
	routes.DELETE("/:orgId/llm-proxy-keys/:keyId", providers.LLMProxyKeyDelete)
	routes.GET("/:orgId/provider-routes", providers.RoutesList)
	routes.POST("/:orgId/provider-routes", providers.RouteCreate)
	routes.PATCH("/:orgId/provider-routes/:routeId", providers.RouteUpdate)
	routes.DELETE("/:orgId/provider-routes/:routeId", providers.RouteDelete)
	routes.GET("/:orgId/provider-routes/:routeId/groups", providers.RouteGroupsList)
	routes.POST("/:orgId/provider-routes/:routeId/groups", providers.RouteGroupCreate)
	routes.PATCH("/:orgId/provider-routes/:routeId/groups/:groupId", providers.RouteGroupUpdate)
	routes.DELETE("/:orgId/provider-routes/:routeId/groups/:groupId", providers.RouteGroupDelete)
	routes.POST("/:orgId/providers", providers.Create)
	routes.GET("/:orgId/providers/:providerId", providers.Get)
	routes.PATCH("/:orgId/providers/:providerId", providers.Update)
	routes.DELETE("/:orgId/providers/:providerId", providers.Delete)
	routes.GET("/:orgId/providers/:providerId/tokens", providers.TokensList)
	routes.POST("/:orgId/providers/:providerId/tokens", providers.TokenCreate)
	routes.DELETE("/:orgId/providers/:providerId/tokens/:tokenId", providers.TokenDelete)
	routes.GET("/:orgId/providers/:providerId/codex/auth", providers.CodexAuthGet)
	routes.POST("/:orgId/providers/:providerId/codex/auth/refresh", providers.CodexAuthRefresh)
	routes.GET("/:orgId/workspaces/:workspaceId/members", handleOrgAuth(workspaces.MemberGrantsList))
	routes.GET("/:orgId/workspaces/:workspaceId/providers", providers.WorkspaceGrantsList)
	routes.POST("/:orgId/workspaces/:workspaceId/providers/:providerId", providers.WorkspaceGrantCreate)
	routes.DELETE("/:orgId/workspaces/:workspaceId/providers/:providerId", providers.WorkspaceGrantDelete)
	routes.GET("/:orgId/workspaces/:workspaceId/provider-routes", providers.WorkspaceRouteGrantsList)
	routes.POST("/:orgId/workspaces/:workspaceId/provider-routes/:routeId", providers.WorkspaceRouteGrantCreate)
	routes.DELETE("/:orgId/workspaces/:workspaceId/provider-routes/:routeId", providers.WorkspaceRouteGrantDelete)
	routes.GET("/:orgId/workspaces/:workspaceId/hosted-model-authorization", handleOrgAuth(hostedModels.WorkspaceAuthorizationGet))
	routes.POST("/:orgId/workspaces/:workspaceId/hosted-model-authorization/preview", handleOrgAuthJSON(hostedModels.WorkspaceAuthorizationPreview))
	routes.PUT("/:orgId/workspaces/:workspaceId/hosted-model-authorization", handleOrgAuthJSON(hostedModels.WorkspaceAuthorizationPut))
	routes.GET("/:orgId/workspaces/:workspaceId/teams", handleOrgAuth(workspaces.TeamGrantsList))
	routes.POST("/:orgId/workspaces/:workspaceId/teams/:teamId", handleOrgAuthJSON(workspaces.TeamGrantCreate))
	routes.DELETE("/:orgId/workspaces/:workspaceId/teams/:teamId", handleOrgAuth(workspaces.TeamGrantDelete))
	routes.POST("/:orgId/workspaces/:workspaceId/members/:memberId", handleOrgAuthJSON(workspaces.MemberGrant))
	routes.DELETE("/:orgId/workspaces/:workspaceId/members/:memberId", handleOrgAuth(workspaces.MemberGrantDelete))
}
