// Copyright 2026 MarketAlly. All rights reserved.
// SPDX-License-Identifier: MIT

package errors

import (
	"fmt"

	"code.gitea.io/gitea/modules/setting"
)

// APIErrorResponse is the top-level error response wrapper
type APIErrorResponse struct {
	Error *APIError `json:"error"`
}

// APIError represents a structured API error following RFC 7807 Problem Details
// with additional fields for AI-friendly error handling
type APIError struct {
	// Machine-readable error code (e.g., "REPO_NOT_FOUND")
	Code string `json:"code"`

	// Human-readable error message
	Message string `json:"message"`

	// HTTP status code
	Status int `json:"status"`

	// Additional context about the error
	Details map[string]any `json:"details,omitempty"`

	// URL to documentation about this error
	DocumentationURL string `json:"documentation_url,omitempty"`

	// Unique request ID for tracing
	RequestID string `json:"request_id,omitempty"`

	// Suggested actions or alternatives
	Suggestions []string `json:"suggestions,omitempty"`

	// RFC 7807 Problem Details fields
	Type     string `json:"type,omitempty"`     // URI reference identifying the problem type
	Title    string `json:"title,omitempty"`    // Short summary of the problem type
	Instance string `json:"instance,omitempty"` // URI reference for this specific occurrence
}

// NewAPIError creates a new structured API error
func NewAPIError(code ErrorCode, requestID string) *APIError {
	docURL := fmt.Sprintf("%s/api/errors#%s", setting.AppURL, code)

	return &APIError{
		Code:             code.String(),
		Message:          code.Message(),
		Status:           code.HTTPStatus(),
		DocumentationURL: docURL,
		RequestID:        requestID,
		Type:             "about:blank",
		Title:            code.Message(),
		Instance:         requestID,
	}
}

// WithDetails adds details to the error
func (e *APIError) WithDetails(details map[string]any) *APIError {
	e.Details = details
	return e
}

// WithDetail adds a single detail to the error
func (e *APIError) WithDetail(key string, value any) *APIError {
	if e.Details == nil {
		e.Details = make(map[string]any)
	}
	e.Details[key] = value
	return e
}

// WithMessage overrides the default message
func (e *APIError) WithMessage(message string) *APIError {
	e.Message = message
	e.Title = message
	return e
}

// WithSuggestions adds suggested actions
func (e *APIError) WithSuggestions(suggestions ...string) *APIError {
	e.Suggestions = append(e.Suggestions, suggestions...)
	return e
}

// Response wraps the error in an APIErrorResponse
func (e *APIError) Response() *APIErrorResponse {
	return &APIErrorResponse{Error: e}
}

// ValidationError represents a field-level validation error
type ValidationError struct {
	Field   string `json:"field"`
	Message string `json:"message"`
	Code    string `json:"code,omitempty"`
}

// APIValidationError represents a validation error with field-level details
type APIValidationError struct {
	*APIError
	Errors []ValidationError `json:"errors,omitempty"`
}

// NewValidationError creates a new validation error
func NewValidationError(requestID string, errors ...ValidationError) *APIValidationError {
	baseErr := NewAPIError(ValInvalidInput, requestID)
	return &APIValidationError{
		APIError: baseErr,
		Errors:   errors,
	}
}

// AddFieldError adds a field validation error
func (e *APIValidationError) AddFieldError(field, message string, code ...string) *APIValidationError {
	ve := ValidationError{
		Field:   field,
		Message: message,
	}
	if len(code) > 0 {
		ve.Code = code[0]
	}
	e.Errors = append(e.Errors, ve)
	return e
}
