package httpapi

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"

	"github.com/easyai/easyai-ai-gateway/apps/api/internal/publicerror"
)

const maxAsyncMediaResultResponseBytes = 64 << 10

func writeJSON(w http.ResponseWriter, status int, value any) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(status)
	_ = json.NewEncoder(w).Encode(value)
}

func writeAsyncMediaResultJSON(w http.ResponseWriter, value any, observer interface {
	ObserveResultDelivery(string, int64)
}) {
	payload, err := json.Marshal(value)
	if err != nil {
		writeError(w, http.StatusInternalServerError, "encode task result failed", "internal_error")
		return
	}
	if len(payload) > maxAsyncMediaResultResponseBytes {
		if observer != nil {
			observer.ObserveResultDelivery("poll_oversized", int64(len(payload)))
		}
		writeErrorWithDetails(w, http.StatusInternalServerError, "task result response exceeds the URL-only size limit", map[string]any{
			"limit_bytes":  maxAsyncMediaResultResponseBytes,
			"actual_bytes": len(payload),
		}, "result_response_too_large")
		return
	}
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.Header().Set("X-Gateway-Response-Format", "url")
	w.Header().Set("Deprecation", "true")
	w.Header().Set("X-Gateway-Deprecated-Fields", "output_content,result")
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write(append(payload, '\n'))
	if observer != nil {
		observer.ObserveResultDelivery("poll_success", int64(len(payload)+1))
	}
}

func writeError(w http.ResponseWriter, status int, message string, codes ...string) {
	writeErrorWithDetails(w, status, message, nil, codes...)
}

func writeErrorWithDetails(w http.ResponseWriter, status int, message string, details map[string]any, codes ...string) {
	code := ""
	if len(codes) > 0 {
		code = strings.TrimSpace(codes[0])
	}
	standard := publicerror.FromFields(code, message, status, status == http.StatusRequestTimeout || status == http.StatusTooManyRequests || status >= 500)
	standard = publicErrorWithRetryAfter(standard, details)
	publicerror.Observe(standard)
	status = standard.HTTPStatus
	errorPayload := map[string]any{
		"message":    standard.Message,
		"status":     status,
		"code":       standard.Code,
		"category":   standard.Category,
		"source":     standard.Source,
		"httpStatus": standard.HTTPStatus,
		"retryable":  standard.Retryable,
		"action":     standard.Action,
		"version":    standard.Version,
	}
	if standard.Code == "invalid_parameter" || standard.Code == "unsupported_response_parameter" {
		errorPayload["type"] = "invalid_request_error"
		if _, ok := details["param"]; !ok {
			errorPayload["param"] = nil
		}
	}
	for key, value := range safePublicErrorDetails(details, standard, false) {
		errorPayload[key] = value
	}
	writeJSON(w, status, map[string]any{"error": errorPayload})
}

func writeLocalUserRequired(w http.ResponseWriter) {
	writeError(w, http.StatusForbidden, "该账号尚未开通 EasyAI Gateway", errorCodeGatewayUserNotProvisioned)
}

func sendSSE(w http.ResponseWriter, event string, payload any) {
	bytes, _ := json.Marshal(payload)
	_, _ = fmt.Fprintf(w, "event: %s\n", event)
	_, _ = fmt.Fprintf(w, "data: %s\n\n", bytes)
}
