package org

import (
	"net/http"
	"strings"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/api/dto/converter"
	"github.com/tidbcloud/AgentTeam/internal/store/organization"

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

// RoutesList handles GET /api/v1/orgs/:orgId/provider-routes.
func (handler *ProviderHandler) RoutesList(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	if organizationID == "" {
		api.Error(ctx, http.StatusBadRequest, "orgId is required")
		return
	}

	items, err := orgs.ListOrganizationProviderRoutesForUser(ctx.Request.Context(), authenticated.User.ID, organizationID)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, converter.ToOrgProviderRouteViews(items))
}

// RouteCreate handles POST /api/v1/orgs/:orgId/provider-routes.
func (handler *ProviderHandler) RouteCreate(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	if organizationID == "" {
		api.Error(ctx, http.StatusBadRequest, "orgId is required")
		return
	}

	var request dto.OrganizationProviderRouteCreateRequest
	if err := ctx.ShouldBindJSON(&request); err != nil {
		api.Error(ctx, http.StatusBadRequest, "Invalid request body")
		return
	}

	item, err := orgs.CreateOrganizationProviderRouteForUser(
		ctx.Request.Context(),
		authenticated.User.ID,
		organizationID,
		organization.CreateOrganizationProviderRouteParams{
			Vendor:      request.Vendor,
			DisplayName: request.DisplayName,
			Models:      providerModelsFromDTO(request.Models),
		},
	)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	if err := handler.refreshLLMRegistry(ctx.Request.Context()); err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, converter.ToOrgProviderRouteView(item))
}

// RouteUpdate handles PATCH /api/v1/orgs/:orgId/provider-routes/:routeId.
func (handler *ProviderHandler) RouteUpdate(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	routeID := strings.TrimSpace(ctx.Param("routeId"))
	if organizationID == "" || routeID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	var request dto.OrganizationProviderRouteUpdateRequest
	if err := ctx.ShouldBindJSON(&request); err != nil {
		api.Error(ctx, http.StatusBadRequest, "Invalid request body")
		return
	}

	item, err := orgs.UpdateOrganizationProviderRouteForUser(
		ctx.Request.Context(),
		authenticated.User.ID,
		organizationID,
		routeID,
		organization.UpdateOrganizationProviderRouteParams{
			Vendor:      request.Vendor,
			DisplayName: request.DisplayName,
			Models:      providerModelsPtrFromDTO(request.Models),
		},
	)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	if err := handler.refreshLLMRegistry(ctx.Request.Context()); err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, converter.ToOrgProviderRouteView(item))
}

// RouteGroupsList handles GET /api/v1/orgs/:orgId/provider-routes/:routeId/groups.
func (handler *ProviderHandler) RouteGroupsList(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	routeID := strings.TrimSpace(ctx.Param("routeId"))
	if organizationID == "" || routeID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	items, err := orgs.ListOrganizationProviderRouteGroupsForUser(ctx.Request.Context(), authenticated.User.ID, organizationID, routeID)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, converter.ToOrgProviderRouteGroupViews(items))
}

// RouteGroupCreate handles POST /api/v1/orgs/:orgId/provider-routes/:routeId/groups.
func (handler *ProviderHandler) RouteGroupCreate(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	routeID := strings.TrimSpace(ctx.Param("routeId"))
	if organizationID == "" || routeID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	var request dto.OrganizationProviderRouteGroupCreateRequest
	if err := ctx.ShouldBindJSON(&request); err != nil {
		api.Error(ctx, http.StatusBadRequest, "Invalid request body")
		return
	}

	item, err := orgs.CreateOrganizationProviderRouteGroupForUser(
		ctx.Request.Context(),
		authenticated.User.ID,
		organizationID,
		routeID,
		organization.CreateOrganizationProviderRouteGroupParams{
			Models:       request.Models,
			ProviderRefs: request.ProviderRefs,
			Strategy:     request.Strategy,
			Priority:     request.Priority,
		},
	)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	if err := handler.refreshLLMRegistry(ctx.Request.Context()); err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, converter.ToOrgProviderRouteGroupView(item))
}

// RouteGroupUpdate handles PATCH /api/v1/orgs/:orgId/provider-routes/:routeId/groups/:groupId.
func (handler *ProviderHandler) RouteGroupUpdate(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	routeID := strings.TrimSpace(ctx.Param("routeId"))
	groupID := strings.TrimSpace(ctx.Param("groupId"))
	if organizationID == "" || routeID == "" || groupID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	var request dto.OrganizationProviderRouteGroupUpdateRequest
	if err := ctx.ShouldBindJSON(&request); err != nil {
		api.Error(ctx, http.StatusBadRequest, "Invalid request body")
		return
	}

	item, err := orgs.UpdateOrganizationProviderRouteGroupForUser(
		ctx.Request.Context(),
		authenticated.User.ID,
		organizationID,
		routeID,
		groupID,
		organization.UpdateOrganizationProviderRouteGroupParams{
			Models:       request.Models,
			ProviderRefs: request.ProviderRefs,
			Strategy:     request.Strategy,
			Priority:     request.Priority,
		},
	)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	if err := handler.refreshLLMRegistry(ctx.Request.Context()); err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, converter.ToOrgProviderRouteGroupView(item))
}

// RouteGroupDelete handles DELETE /api/v1/orgs/:orgId/provider-routes/:routeId/groups/:groupId.
func (handler *ProviderHandler) RouteGroupDelete(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	routeID := strings.TrimSpace(ctx.Param("routeId"))
	groupID := strings.TrimSpace(ctx.Param("groupId"))
	if organizationID == "" || routeID == "" || groupID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	if err := orgs.DeleteOrganizationProviderRouteGroupForUser(ctx.Request.Context(), authenticated.User.ID, organizationID, routeID, groupID); err != nil {
		api.StoreError(ctx, err)
		return
	}
	if err := handler.refreshLLMRegistry(ctx.Request.Context()); err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, dto.EmptyResponse{})
}

// RouteDelete handles DELETE /api/v1/orgs/:orgId/provider-routes/:routeId.
func (handler *ProviderHandler) RouteDelete(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	routeID := strings.TrimSpace(ctx.Param("routeId"))
	if organizationID == "" || routeID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	if err := orgs.DeleteOrganizationProviderRouteForUser(ctx.Request.Context(), authenticated.User.ID, organizationID, routeID); err != nil {
		api.StoreError(ctx, err)
		return
	}
	if err := handler.refreshLLMRegistry(ctx.Request.Context()); err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, dto.EmptyResponse{})
}

// WorkspaceRouteGrantsList handles GET /api/v1/orgs/:orgId/workspaces/:workspaceId/provider-routes.
func (handler *ProviderHandler) WorkspaceRouteGrantsList(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	workspaceID := strings.TrimSpace(ctx.Param("workspaceId"))
	if organizationID == "" || workspaceID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	grants, err := orgs.ListOrganizationWorkspaceRouteGrantsForUser(ctx.Request.Context(), authenticated.User.ID, organizationID, workspaceID)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, converter.ToOrgWorkspaceRouteGrantViews(grants))
}

// WorkspaceRouteGrantCreate handles POST /api/v1/orgs/:orgId/workspaces/:workspaceId/provider-routes/:routeId.
func (handler *ProviderHandler) WorkspaceRouteGrantCreate(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	workspaceID := strings.TrimSpace(ctx.Param("workspaceId"))
	routeID := strings.TrimSpace(ctx.Param("routeId"))
	if organizationID == "" || workspaceID == "" || routeID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	grant, err := orgs.GrantOrganizationWorkspaceRouteForUser(ctx.Request.Context(), authenticated.User.ID, organizationID, workspaceID, routeID)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	if err := handler.refreshLLMRegistry(ctx.Request.Context()); err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, converter.ToOrgWorkspaceRouteGrantView(grant))
}

// WorkspaceRouteGrantDelete handles DELETE /api/v1/orgs/:orgId/workspaces/:workspaceId/provider-routes/:routeId.
func (handler *ProviderHandler) WorkspaceRouteGrantDelete(ctx *gin.Context) {
	authenticated, ok := api.AuthenticatedUserFromContext(ctx)
	if !ok {
		api.Error(ctx, http.StatusUnauthorized, "Unauthorized")
		return
	}
	orgs, ok := handler.organizationProvider()
	if !ok {
		api.Error(ctx, http.StatusNotFound, "Organization provider not installed")
		return
	}

	organizationID := strings.TrimSpace(ctx.Param("orgId"))
	workspaceID := strings.TrimSpace(ctx.Param("workspaceId"))
	routeID := strings.TrimSpace(ctx.Param("routeId"))
	if organizationID == "" || workspaceID == "" || routeID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	if err := orgs.RevokeOrganizationWorkspaceRouteForUser(ctx.Request.Context(), authenticated.User.ID, organizationID, workspaceID, routeID); err != nil {
		api.StoreError(ctx, err)
		return
	}
	if err := handler.refreshLLMRegistry(ctx.Request.Context()); err != nil {
		api.StoreError(ctx, err)
		return
	}
	ctx.JSON(http.StatusOK, dto.EmptyResponse{})
}
