package handlers

import (
	"net/http"
	"time"

	"veza-backend-api/internal/errors"

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

// ErrorResponse représente le format d'erreur standardisé selon ORIGIN_API_SPECIFICATION
// GO-014: Harmonisation format erreurs HTTP
type ErrorResponse struct {
	Error struct {
		Code      int                    `json:"code"`
		Message   string                 `json:"message"`
		Details   []errors.ErrorDetail   `json:"details,omitempty"`
		RequestID string                 `json:"request_id,omitempty"`
		Timestamp string                 `json:"timestamp"`
		Context   map[string]interface{} `json:"context,omitempty"`
	} `json:"error"`
}

// RespondWithAppError répond avec une AppError au format standardisé ORIGIN_API_SPECIFICATION
// GO-014: Harmonisation format erreurs HTTP selon ORIGIN_API_SPECIFICATION
func RespondWithAppError(c *gin.Context, appErr *errors.AppError) {
	statusCode := mapErrorCodeToHTTPStatus(appErr.Code)

	errorData := struct {
		Code      int                    `json:"code"`
		Message   string                 `json:"message"`
		Details   []errors.ErrorDetail   `json:"details,omitempty"`
		RequestID string                 `json:"request_id,omitempty"`
		Timestamp string                 `json:"timestamp"`
		Context   map[string]interface{} `json:"context,omitempty"`
	}{
		Code:      int(appErr.Code),
		Message:   appErr.Message,
		Details:   appErr.Details,
		RequestID: c.GetString("request_id"),
		Timestamp: time.Now().UTC().Format(time.RFC3339),
		Context:   appErr.Context,
	}

	c.JSON(statusCode, APIResponse{
		Success: false,
		Data:    nil,
		Error:   errorData,
	})
}

// RespondWithError répond avec un code d'erreur et un message au format standardisé
// GO-014: Harmonisation format erreurs HTTP selon ORIGIN_API_SPECIFICATION
func RespondWithError(c *gin.Context, code int, message string, details ...errors.ErrorDetail) {
	statusCode := mapErrorCodeToHTTPStatus(errors.ErrorCode(code))

	errorData := struct {
		Code      int                  `json:"code"`
		Message   string               `json:"message"`
		Details   []errors.ErrorDetail `json:"details,omitempty"`
		RequestID string               `json:"request_id,omitempty"`
		Timestamp string               `json:"timestamp"`
	}{
		Code:      code,
		Message:   message,
		Details:   details,
		RequestID: c.GetString("request_id"),
		Timestamp: time.Now().UTC().Format(time.RFC3339),
	}

	c.JSON(statusCode, APIResponse{
		Success: false,
		Data:    nil,
		Error:   errorData,
	})
}

// mapErrorCodeToHTTPStatus mappe les codes d'erreur ORIGIN vers les codes HTTP
// GO-014: Harmonisation format erreurs HTTP selon ORIGIN_API_SPECIFICATION
func mapErrorCodeToHTTPStatus(code errors.ErrorCode) int {
	// Authentication & Authorization (1000-1999)
	if code >= 1000 && code < 2000 {
		switch code {
		case 1000, 1001, 1002, 1004, 1007, 1008: // Invalid credentials, token expired/invalid, 2FA
			return http.StatusUnauthorized
		case 1003, 1005, 1006: // Insufficient permissions, account issues
			return http.StatusForbidden
		default:
			return http.StatusUnauthorized
		}
	}

	// Validation Errors (2000-2999)
	if code >= 2000 && code < 3000 {
		return http.StatusBadRequest
	}

	// Resource Errors (3000-3999)
	if code >= 3000 && code < 4000 {
		switch code {
		case 3000, 3003: // Not found, deleted
			return http.StatusNotFound
		case 3001, 3002: // Already exists, conflict
			return http.StatusConflict
		case 3004: // Locked
			return http.StatusLocked
		case 3005: // Quota exceeded
			return http.StatusForbidden
		default:
			return http.StatusNotFound
		}
	}

	// Business Logic Errors (4000-4999)
	if code >= 4000 && code < 5000 {
		return http.StatusUnprocessableEntity
	}

	// Rate Limiting (5000-5099)
	if code >= 5000 && code < 5100 {
		return http.StatusTooManyRequests
	}

	// External Services (6000-6999)
	if code >= 6000 && code < 7000 {
		return http.StatusBadGateway
	}

	// Internal Errors (9000-9999)
	if code >= 9000 && code < 10000 {
		return http.StatusInternalServerError
	}

	// Default
	return http.StatusInternalServerError
}
