package ucxl

import (
	"time"
)

// UCXLCode represents a standardized UCXL response/error code
type UCXLCode string

// Standard UCXL response codes
const (
	// Success codes (2xx range)
	CodeSuccess       UCXLCode = "UCXL-200-SUCCESS"
	CodeCreated       UCXLCode = "UCXL-201-CREATED"
	CodeAccepted      UCXLCode = "UCXL-202-ACCEPTED"
	CodeNoContent     UCXLCode = "UCXL-204-NO_CONTENT"

	// Client error codes (4xx range)
	CodeBadRequest      UCXLCode = "UCXL-400-BAD_REQUEST"
	CodeInvalidAddress  UCXLCode = "UCXL-400-INVALID_ADDRESS"
	CodeInvalidPayload  UCXLCode = "UCXL-400-INVALID_PAYLOAD"
	CodeUnauthorized    UCXLCode = "UCXL-401-UNAUTHORIZED"
	CodeForbidden       UCXLCode = "UCXL-403-FORBIDDEN"
	CodeNotFound        UCXLCode = "UCXL-404-NOT_FOUND"
	CodeMethodNotAllowed UCXLCode = "UCXL-405-METHOD_NOT_ALLOWED"
	CodeConflict        UCXLCode = "UCXL-409-CONFLICT"
	CodeUnprocessable   UCXLCode = "UCXL-422-UNPROCESSABLE"
	CodeTooManyRequests UCXLCode = "UCXL-429-TOO_MANY_REQUESTS"

	// Server error codes (5xx range)
	CodeInternalError   UCXLCode = "UCXL-500-INTERNAL_ERROR"
	CodeNotImplemented  UCXLCode = "UCXL-501-NOT_IMPLEMENTED"
	CodeBadGateway      UCXLCode = "UCXL-502-BAD_GATEWAY"
	CodeServiceUnavailable UCXLCode = "UCXL-503-SERVICE_UNAVAILABLE"
	CodeGatewayTimeout  UCXLCode = "UCXL-504-GATEWAY_TIMEOUT"

	// UCXI-specific codes
	CodeResolutionFailed  UCXLCode = "UCXL-404-RESOLUTION_FAILED"
	CodeStorageFailed     UCXLCode = "UCXL-500-STORAGE_FAILED"
	CodeAnnounceFailed    UCXLCode = "UCXL-500-ANNOUNCE_FAILED"
	CodeNavigationFailed  UCXLCode = "UCXL-422-NAVIGATION_FAILED"
	CodeTemporalInvalid   UCXLCode = "UCXL-400-TEMPORAL_INVALID"

	// Role-based collaboration codes
	CodeCollaborationFailed    UCXLCode = "UCXL-500-COLLABORATION_FAILED"
	CodeInvalidRole           UCXLCode = "UCXL-400-INVALID_ROLE"
	CodeExpertiseNotAvailable UCXLCode = "UCXL-404-EXPERTISE_NOT_AVAILABLE"
	CodeMentorshipUnavailable UCXLCode = "UCXL-404-MENTORSHIP_UNAVAILABLE"
	CodeProjectNotFound       UCXLCode = "UCXL-404-PROJECT_NOT_FOUND"
	CodeCollaborationTimeout  UCXLCode = "UCXL-408-COLLABORATION_TIMEOUT"
)

// UCXLResponse represents a standardized UCXL success response
type UCXLResponse struct {
	Response UCXLResponseData `json:"response"`
}

// UCXLResponseData contains the actual response data
type UCXLResponseData struct {
	Code      UCXLCode    `json:"code"`
	Message   string      `json:"message"`
	Data      interface{} `json:"data,omitempty"`
	Details   interface{} `json:"details,omitempty"`
	RequestID string      `json:"request_id"`
	Timestamp time.Time   `json:"timestamp"`
}

// UCXLError represents a standardized UCXL error response
type UCXLError struct {
	Error UCXLErrorData `json:"error"`
}

// UCXLErrorData contains the actual error data
type UCXLErrorData struct {
	Code      UCXLCode    `json:"code"`
	Message   string      `json:"message"`
	Details   interface{} `json:"details,omitempty"`
	Source    string      `json:"source"`
	Path      string      `json:"path"`
	RequestID string      `json:"request_id"`
	Timestamp time.Time   `json:"timestamp"`
	Cause     *UCXLError  `json:"cause,omitempty"`
}

// ResponseBuilder helps build standardized UCXL responses
type ResponseBuilder struct {
	requestID string
	source    string
}

// NewResponseBuilder creates a new response builder
func NewResponseBuilder(requestID string, source string) *ResponseBuilder {
	if requestID == "" {
		requestID = generateRequestID()
	}
	if source == "" {
		source = "ucxi-server"
	}
	return &ResponseBuilder{
		requestID: requestID,
		source:    source,
	}
}

// Success creates a standardized success response
func (rb *ResponseBuilder) Success(code UCXLCode, message string, data interface{}) *UCXLResponse {
	return &UCXLResponse{
		Response: UCXLResponseData{
			Code:      code,
			Message:   message,
			Data:      data,
			RequestID: rb.requestID,
			Timestamp: time.Now().UTC(),
		},
	}
}

// SuccessWithDetails creates a success response with additional details
func (rb *ResponseBuilder) SuccessWithDetails(code UCXLCode, message string, data interface{}, details interface{}) *UCXLResponse {
	return &UCXLResponse{
		Response: UCXLResponseData{
			Code:      code,
			Message:   message,
			Data:      data,
			Details:   details,
			RequestID: rb.requestID,
			Timestamp: time.Now().UTC(),
		},
	}
}

// Error creates a standardized error response
func (rb *ResponseBuilder) Error(code UCXLCode, message string, path string) *UCXLError {
	return &UCXLError{
		Error: UCXLErrorData{
			Code:      code,
			Message:   message,
			Source:    rb.source,
			Path:      path,
			RequestID: rb.requestID,
			Timestamp: time.Now().UTC(),
		},
	}
}

// ErrorWithDetails creates an error response with additional details
func (rb *ResponseBuilder) ErrorWithDetails(code UCXLCode, message string, path string, details interface{}) *UCXLError {
	return &UCXLError{
		Error: UCXLErrorData{
			Code:      code,
			Message:   message,
			Details:   details,
			Source:    rb.source,
			Path:      path,
			RequestID: rb.requestID,
			Timestamp: time.Now().UTC(),
		},
	}
}

// ErrorWithCause creates an error response with a causal chain
func (rb *ResponseBuilder) ErrorWithCause(code UCXLCode, message string, path string, cause *UCXLError) *UCXLError {
	return &UCXLError{
		Error: UCXLErrorData{
			Code:      code,
			Message:   message,
			Source:    rb.source,
			Path:      path,
			RequestID: rb.requestID,
			Timestamp: time.Now().UTC(),
			Cause:     cause,
		},
	}
}

// Convenience methods for common responses

// OK creates a standard 200 OK response
func (rb *ResponseBuilder) OK(data interface{}) *UCXLResponse {
	return rb.Success(CodeSuccess, "Request completed successfully", data)
}

// Created creates a standard 201 Created response
func (rb *ResponseBuilder) Created(data interface{}) *UCXLResponse {
	return rb.Success(CodeCreated, "Resource created successfully", data)
}

// NoContent creates a standard 204 No Content response
func (rb *ResponseBuilder) NoContent() *UCXLResponse {
	return rb.Success(CodeNoContent, "Request completed with no content", nil)
}

// BadRequest creates a standard 400 Bad Request error
func (rb *ResponseBuilder) BadRequest(message string, path string) *UCXLError {
	return rb.Error(CodeBadRequest, message, path)
}

// InvalidAddress creates a UCXL-specific invalid address error
func (rb *ResponseBuilder) InvalidAddress(message string, path string, addressDetails interface{}) *UCXLError {
	return rb.ErrorWithDetails(CodeInvalidAddress, message, path, map[string]interface{}{
		"field":   "address",
		"address": addressDetails,
	})
}

// NotFound creates a standard 404 Not Found error
func (rb *ResponseBuilder) NotFound(message string, path string) *UCXLError {
	return rb.Error(CodeNotFound, message, path)
}

// Unprocessable creates a standard 422 Unprocessable Entity error
func (rb *ResponseBuilder) Unprocessable(message string, path string, validationErrors interface{}) *UCXLError {
	return rb.ErrorWithDetails(CodeUnprocessable, message, path, map[string]interface{}{
		"validation_errors": validationErrors,
	})
}

// InternalError creates a standard 500 Internal Server Error
func (rb *ResponseBuilder) InternalError(message string, path string) *UCXLError {
	return rb.Error(CodeInternalError, message, path)
}

// MethodNotAllowed creates a standard 405 Method Not Allowed error
func (rb *ResponseBuilder) MethodNotAllowed(allowedMethods []string, path string) *UCXLError {
	return rb.ErrorWithDetails(CodeMethodNotAllowed, "Method not allowed", path, map[string]interface{}{
		"allowed_methods": allowedMethods,
	})
}

// Collaboration-specific error builders

// InvalidRole creates a UCXL-specific invalid role error
func (rb *ResponseBuilder) InvalidRole(message string, path string, roleDetails interface{}) *UCXLError {
	return rb.ErrorWithDetails(CodeInvalidRole, message, path, map[string]interface{}{
		"field": "role",
		"role_details": roleDetails,
	})
}

// ExpertiseNotAvailable creates a UCXL-specific expertise not available error
func (rb *ResponseBuilder) ExpertiseNotAvailable(message string, path string, expertiseDetails interface{}) *UCXLError {
	return rb.ErrorWithDetails(CodeExpertiseNotAvailable, message, path, map[string]interface{}{
		"requested_expertise": expertiseDetails,
		"suggestion": "Try requesting more general expertise or check available experts",
	})
}

// ProjectNotFound creates a UCXL-specific project not found error
func (rb *ResponseBuilder) ProjectNotFound(message string, path string, projectID string) *UCXLError {
	return rb.ErrorWithDetails(CodeProjectNotFound, message, path, map[string]interface{}{
		"field": "project_id",
		"project_id": projectID,
		"suggestion": "Verify the project ID is correct and accessible",
	})
}

// CollaborationTimeout creates a UCXL-specific collaboration timeout error
func (rb *ResponseBuilder) CollaborationTimeout(message string, path string, timeoutDetails interface{}) *UCXLError {
	return rb.ErrorWithDetails(CodeCollaborationTimeout, message, path, map[string]interface{}{
		"timeout_reason": timeoutDetails,
		"suggestion": "Retry the collaboration request or check system load",
	})
}

// CollaborationFailed creates a UCXL-specific collaboration failure error
func (rb *ResponseBuilder) CollaborationFailed(message string, path string, failureDetails interface{}) *UCXLError {
	return rb.ErrorWithDetails(CodeCollaborationFailed, message, path, map[string]interface{}{
		"failure_details": failureDetails,
		"suggestion": "Check system status and pubsub connectivity",
	})
}

// Helper functions

// GetHTTPStatus maps UCXL codes to HTTP status codes
func GetHTTPStatus(code UCXLCode) int {
	switch code {
	case CodeSuccess:
		return 200
	case CodeCreated:
		return 201
	case CodeAccepted:
		return 202
	case CodeNoContent:
		return 204
	case CodeBadRequest, CodeInvalidAddress, CodeInvalidPayload, CodeTemporalInvalid, CodeInvalidRole:
		return 400
	case CodeUnauthorized:
		return 401
	case CodeForbidden:
		return 403
	case CodeNotFound, CodeResolutionFailed, CodeExpertiseNotAvailable, CodeMentorshipUnavailable, CodeProjectNotFound:
		return 404
	case CodeCollaborationTimeout:
		return 408
	case CodeMethodNotAllowed:
		return 405
	case CodeConflict:
		return 409
	case CodeUnprocessable, CodeNavigationFailed:
		return 422
	case CodeTooManyRequests:
		return 429
	case CodeInternalError, CodeStorageFailed, CodeAnnounceFailed, CodeCollaborationFailed:
		return 500
	case CodeNotImplemented:
		return 501
	case CodeBadGateway:
		return 502
	case CodeServiceUnavailable:
		return 503
	case CodeGatewayTimeout:
		return 504
	default:
		return 500
	}
}

// generateRequestID creates a unique request ID
func generateRequestID() string {
	// Simple UUID-like generator for request IDs
	return time.Now().Format("20060102-150405") + "-" + randomString(8)
}

// randomString generates a random string of the specified length
func randomString(length int) string {
	const charset = "abcdefghijklmnopqrstuvwxyz0123456789"
	result := make([]byte, length)
	for i := range result {
		result[i] = charset[time.Now().UnixNano()%(int64(len(charset)))]
	}
	return string(result)
}