package middleware

import (
	"errors"

	"github.com/gin-gonic/gin"
	"github.com/nexuscrm/backend/pkg/apierr"
	"github.com/nexuscrm/backend/pkg/logging"
)

// httpStatuser is implemented by pkg/errors types that carry an HTTP status code.
type httpStatuser interface {
	HTTPStatus() int
	Code() string
}

// GlobalErrorHandler is a middleware that handles errors from the context
func GlobalErrorHandler(logger *logging.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		c.Next() // Execute handlers

		// Check if there are any errors in the context
		if len(c.Errors) > 0 {
			// Get the last error
			err := c.Errors.Last().Err

			var apiErr *apierr.Error

			// Check if it's already an API Error
			if errors.As(err, &apiErr) {
				// Log internal cause if present
				if apiErr.Cause != nil {
					logger.WithField("code", apiErr.Code).Error("API Error with cause", apiErr.Cause)
				}
				c.JSON(apiErr.Status, apiErr)
				return
			}

			var sfErr *apierr.SalesforceAPIError
			if errors.As(err, &sfErr) {
				if sfErr.Cause != nil {
					logger.WithField("sf_error_code", sfErr.Err.ErrorCode).Error("Salesforce API Error with cause", sfErr.Cause)
				}
				c.JSON(sfErr.Status, []apierr.SFError{sfErr.Err})
				return
			}

			// Check if it's a pkg/errors domain error (NotFoundError, PermissionError, etc.)
			var statuser httpStatuser
			if errors.As(err, &statuser) {
				mapped := apierr.New(statuser.HTTPStatus(), statuser.Code(), err.Error())
				c.JSON(mapped.Status, mapped)
				return
			}

			// Prepare generic internal error
			logger.WithField("path", c.Request.URL.Path).Error("Unhandled error", err)
			internalErr := apierr.Internal(err)
			c.JSON(internalErr.Status, internalErr)
		}
	}
}
