package org

import (
	"errors"
	"io"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"

	"github.com/tidbcloud/AgentTeam/internal/api"
	"github.com/tidbcloud/AgentTeam/internal/api/dto"
	"github.com/tidbcloud/AgentTeam/internal/apr/agentteambridge"
)

// CodexAuthGet handles GET /api/v1/orgs/:orgId/providers/:providerId/codex/auth.
func (handler *ProviderHandler) CodexAuthGet(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"))
	providerID := strings.TrimSpace(ctx.Param("providerId"))
	if organizationID == "" || providerID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	provider, err := orgs.GetOrganizationProviderForUser(ctx.Request.Context(), authenticated.User.ID, organizationID, providerID)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	if strings.TrimSpace(provider.DriverKind) != "codex" {
		api.Error(ctx, http.StatusNotFound, "Codex provider not found")
		return
	}

	runtime, ok := handler.codexProviderRuntime()
	if !ok {
		api.Error(ctx, http.StatusServiceUnavailable, "Codex provider runtime is unavailable")
		return
	}

	snapshots, configured := runtime.CodexAuthSnapshots(organizationID, providerID)
	response := dto.OrganizationProviderCodexAuthResponse{
		Configured: configured,
		Auth:       codexAuthSnapshotsToDTO(snapshots),
		TotalCount: len(snapshots),
	}
	if response.Auth == nil {
		response.Auth = []dto.OrganizationProviderCodexAuthSnapshot{}
	}
	ctx.JSON(http.StatusOK, response)
}

// CodexAuthRefresh handles POST /api/v1/orgs/:orgId/providers/:providerId/codex/auth/refresh.
func (handler *ProviderHandler) CodexAuthRefresh(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"))
	providerID := strings.TrimSpace(ctx.Param("providerId"))
	if organizationID == "" || providerID == "" {
		api.Error(ctx, http.StatusBadRequest, "Invalid request")
		return
	}

	provider, err := orgs.GetOrganizationProviderForUser(ctx.Request.Context(), authenticated.User.ID, organizationID, providerID)
	if err != nil {
		api.StoreError(ctx, err)
		return
	}
	if strings.TrimSpace(provider.DriverKind) != "codex" {
		api.Error(ctx, http.StatusNotFound, "Codex provider not found")
		return
	}

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

	runtime, ok := handler.codexProviderRuntime()
	if !ok {
		api.Error(ctx, http.StatusServiceUnavailable, "Codex provider runtime is unavailable")
		return
	}

	results, configured := runtime.ForceRefreshCodexAuth(ctx.Request.Context(), organizationID, providerID, request.Source)
	if !configured {
		api.Error(ctx, http.StatusNotFound, "Codex provider is not configured")
		return
	}
	if len(results) == 0 {
		api.Error(ctx, http.StatusNotFound, "No refreshable Codex auth backend matched")
		return
	}

	status := http.StatusOK
	for _, result := range results {
		if strings.TrimSpace(result.Error) != "" {
			status = http.StatusBadGateway
			break
		}
	}

	ctx.JSON(status, dto.OrganizationProviderCodexAuthRefreshResponse{
		Results: codexAuthRefreshResultsToDTO(results),
	})
}

func codexAuthSnapshotsToDTO(items []agentteambridge.CodexAuthSnapshot) []dto.OrganizationProviderCodexAuthSnapshot {
	if len(items) == 0 {
		return nil
	}
	result := make([]dto.OrganizationProviderCodexAuthSnapshot, 0, len(items))
	for _, item := range items {
		result = append(result, dto.OrganizationProviderCodexAuthSnapshot{
			Source:          item.Source,
			Name:            item.Name,
			BackendID:       item.BackendID,
			BaseURL:         item.BaseURL,
			Mode:            item.Mode,
			Active:          item.Active,
			Weight:          item.Weight,
			AllowedAPIKeys:  append([]string(nil), item.AllowedAPIKeys...),
			HasAccessToken:  item.HasAccessToken,
			HasRefreshToken: item.HasRefreshToken,
			AccessToken:     item.AccessToken,
			APIKey:          item.APIKey,
			AccountID:       item.AccountID,
			LastRefreshAt:   item.LastRefreshAt,
			LastStatus:      item.LastStatus,
			LastError:       item.LastError,
		})
	}
	return result
}

func codexAuthRefreshResultsToDTO(items []agentteambridge.CodexAuthRefreshResult) []dto.OrganizationProviderCodexAuthRefreshResult {
	if len(items) == 0 {
		return nil
	}
	result := make([]dto.OrganizationProviderCodexAuthRefreshResult, 0, len(items))
	for _, item := range items {
		result = append(result, dto.OrganizationProviderCodexAuthRefreshResult{
			Source:    item.Source,
			Refreshed: item.Refreshed,
			Error:     item.Error,
		})
	}
	return result
}
