package handlers

import (
	"encoding/json"
	"log"
	"net/http"
)

// ErrorResponse represents a structured error response
type ErrorResponse struct {
	Error   string `json:"error"`
	Message string `json:"message,omitempty"`
	Code    int    `json:"code"`
}

// AppError represents an application error with context
type AppError struct {
	Err        error
	Message    string
	StatusCode int
	Internal   bool // If true, don't expose details to client
}

// Error implements the error interface
func (e *AppError) Error() string {
	if e.Err != nil {
		return e.Err.Error()
	}
	return e.Message
}

// NewAppError creates a new application error
func NewAppError(err error, message string, statusCode int, internal bool) *AppError {
	return &AppError{
		Err:        err,
		Message:    message,
		StatusCode: statusCode,
		Internal:   internal,
	}
}

// HandleError handles errors consistently across the application
func HandleError(w http.ResponseWriter, r *http.Request, err error) {
	var appErr *AppError

	// Check if it's an AppError
	switch e := err.(type) {
	case *AppError:
		appErr = e
	default:
		// Unknown error - treat as internal server error
		appErr = NewAppError(err, "Internal Server Error", http.StatusInternalServerError, true)
	}

	// Log the error
	if appErr.Internal {
		log.Printf("ERROR [%s %s]: %v", r.Method, r.URL.Path, appErr.Err)
	} else {
		log.Printf("CLIENT ERROR [%s %s]: %s (status: %d)", r.Method, r.URL.Path, appErr.Message, appErr.StatusCode)
	}

	// Determine response based on Accept header
	accept := r.Header.Get("Accept")
	isJSON := accept == "application/json"
	isHTMX := r.Header.Get("HX-Request") != ""

	if isJSON {
		// JSON response
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(appErr.StatusCode)

		response := ErrorResponse{
			Error: http.StatusText(appErr.StatusCode),
			Code:  appErr.StatusCode,
		}

		// Only include message if not internal
		if !appErr.Internal {
			response.Message = appErr.Message
		}

		if err := json.NewEncoder(w).Encode(response); err != nil {
			log.Printf("ERROR encoding JSON response: %v", err)
		}
		return
	}

	if isHTMX {
		// HTMX response - return simple HTML fragment
		w.Header().Set("Content-Type", "text/html")
		w.WriteHeader(appErr.StatusCode)

		message := appErr.Message
		if appErr.Internal {
			message = "An error occurred. Please try again later."
		}

		if _, err := w.Write([]byte("<div class='error'>" + message + "</div>")); err != nil {
			log.Printf("ERROR writing HTMX error response: %v", err)
		}
		return
	}

	// Standard HTTP error response
	message := appErr.Message
	if appErr.Internal {
		message = "Internal Server Error"
	}

	http.Error(w, message, appErr.StatusCode)
}

// Common error constructors

func NotFoundError(message string) *AppError {
	return NewAppError(nil, message, http.StatusNotFound, false)
}

func BadRequestError(message string) *AppError {
	return NewAppError(nil, message, http.StatusBadRequest, false)
}

func InternalError(err error) *AppError {
	return NewAppError(err, "Internal Server Error", http.StatusInternalServerError, true)
}

func TemplateError(err error, templateName string) *AppError {
	return NewAppError(
		err,
		"Error rendering template: "+templateName,
		http.StatusInternalServerError,
		true,
	)
}

func DataLoadError(err error, dataType string) *AppError {
	return NewAppError(
		err,
		"Error loading "+dataType+" data",
		http.StatusInternalServerError,
		true,
	)
}
