package llm

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

	"github.com/tidbcloud/AgentTeam/internal/apr/agentteambridge"
	"github.com/tidbcloud/AgentTeam/internal/apr/types"

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

// Responses proxies OpenAI responses API requests through the AgentTeam APR-backed proxy.
func (handler *LLMHandler) Responses(ctx *gin.Context) {
	resolved, ok := handler.resolveRequest(ctx)
	if !ok {
		return
	}
	observation, _ := handler.newUsageObservation(ctx, resolved)
	if !handler.enforceQuota(ctx, observation) {
		return
	}
	queueWait, release, ok := handler.acquireConcurrency(ctx, resolved, "responses")
	if !ok {
		handler.recordObservation(ctx, observation, llmUsageTotals{}, "rate_limit")
		return
	}
	if observation != nil {
		observation.queueWait = queueWait
	}
	defer release()

	responsesProvider, ok := resolved.Provider.(types.ResponsesCompatible)
	if ok {
		if handler.logger != nil {
			handler.logger.Info("llm responses upstream request",
				"provider", resolved.Provider.Name(),
				"model", resolved.Model,
				"body_size", len(resolved.Body),
			)
		}
		resp, err := responsesProvider.CreateResponse(ctx.Request.Context(), ctx.Request.Header, resolved.Body)
		if err == nil {
			fallback := shouldFallbackResponsesToChat(resp, handler)
			if !fallback {
				defer resp.Body.Close()
				handler.copyResponseWithObservation(ctx, resp, observation)
				return
			}
			_ = resp.Body.Close()
		} else if err != agentteambridge.ErrWireAPIUnsupported {
			handler.respondUpstreamError(ctx, observation, resolved.Provider.Name(), resolved.Model, "responses", err)
			return
		}
	}

	openAIProvider, ok := resolved.Provider.(types.OpenAICompatible)
	if !ok {
		ctx.JSON(http.StatusBadRequest, gin.H{"error": "provider does not support OpenAI-compatible responses"})
		handler.recordObservation(ctx, observation, llmUsageTotals{}, "bad_request")
		return
	}
	proxyOpenAIAsResponses(ctx, openAIProvider, resolved.Model, resolved.Body, observation, handler)
}

func shouldFallbackResponsesToChat(resp *http.Response, handler *LLMHandler) bool {
	if resp == nil {
		return false
	}
	switch resp.StatusCode {
	case http.StatusNotFound, http.StatusMethodNotAllowed, http.StatusNotImplemented:
	default:
		return false
	}
	if resp.Body == nil {
		return true
	}
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		if handler != nil && handler.logger != nil {
			handler.logger.Info("llm responses fallback probe",
				"status", resp.StatusCode,
				"body_read_error", err,
			)
		}
		return true
	}
	_ = resp.Body.Close()
	resp.Body = io.NopCloser(strings.NewReader(string(body)))
	if handler != nil && handler.logger != nil {
		handler.logger.Info("llm responses fallback probe",
			"status", resp.StatusCode,
			"body", string(body),
		)
	}
	lowered := strings.ToLower(string(body))
	return strings.Contains(lowered, "/responses") ||
		strings.Contains(lowered, "not found") ||
		strings.Contains(lowered, "not implemented") ||
		strings.Contains(lowered, "method not allowed")
}
