package handlers

import (
	"errors"
	"net/http"
	"time"

	"github.com/go-chi/chi/v5"
	"github.com/google/uuid"

	"git.threesix.ai/jordan/slack5-1770606136/pkg/app"
	"git.threesix.ai/jordan/slack5-1770606136/pkg/httperror"
	"git.threesix.ai/jordan/slack5-1770606136/pkg/httpresponse"
	"git.threesix.ai/jordan/slack5-1770606136/pkg/logging"
	"git.threesix.ai/jordan/slack5-1770606136/services/preferences-api/internal/domain"
	"git.threesix.ai/jordan/slack5-1770606136/services/preferences-api/internal/service"
)

// Preference handles HTTP requests for user preference resources.
type Preference struct {
	svc    *service.PreferenceService
	logger *logging.Logger
}

// NewPreference creates a new Preference handler with injected dependencies.
func NewPreference(svc *service.PreferenceService, logger *logging.Logger) *Preference {
	return &Preference{
		svc:    svc,
		logger: logger.WithComponent("PreferenceHandler"),
	}
}

// UpdatePreferencesRequest is the request body for updating preferences.
type UpdatePreferencesRequest struct {
	Preferences map[string]any `json:"preferences"`
}

// PreferenceResponse is the response for a preference resource.
type PreferenceResponse struct {
	UserID      string         `json:"user_id"`
	Preferences map[string]any `json:"preferences"`
	UpdatedAt   string         `json:"updated_at"`
}

// Get returns preferences for a user.
func (h *Preference) Get(w http.ResponseWriter, r *http.Request) error {
	userID := chi.URLParam(r, "user_id")

	if _, err := uuid.Parse(userID); err != nil {
		return httperror.BadRequest("invalid user_id format")
	}

	prefs, err := h.svc.Get(r.Context(), userID)
	if err != nil {
		return err
	}

	if prefs == nil {
		httpresponse.OK(w, r, PreferenceResponse{
			UserID:      userID,
			Preferences: map[string]any{},
			UpdatedAt:   time.Now().UTC().Format(time.RFC3339),
		})
		return nil
	}

	httpresponse.OK(w, r, toPreferenceResponse(prefs))
	return nil
}

// Upsert creates or updates preferences for a user.
func (h *Preference) Upsert(w http.ResponseWriter, r *http.Request) error {
	userID := chi.URLParam(r, "user_id")

	if _, err := uuid.Parse(userID); err != nil {
		return httperror.BadRequest("invalid user_id format")
	}

	var req UpdatePreferencesRequest
	if err := app.Bind(r, &req); err != nil {
		return err
	}

	if req.Preferences == nil {
		return httperror.BadRequest("preferences field is required")
	}

	result, err := h.svc.Upsert(r.Context(), service.UpsertInput{
		UserID:      userID,
		Preferences: req.Preferences,
	})
	if err != nil {
		return mapPreferenceDomainError(err)
	}

	httpresponse.OK(w, r, toPreferenceResponse(result))
	return nil
}

// toPreferenceResponse converts a domain UserPreferences to an API response.
func toPreferenceResponse(p *domain.UserPreferences) PreferenceResponse {
	return PreferenceResponse{
		UserID:      p.UserID,
		Preferences: p.Preferences,
		UpdatedAt:   p.UpdatedAt.Format(time.RFC3339),
	}
}

// mapPreferenceDomainError converts domain errors to HTTP errors.
func mapPreferenceDomainError(err error) error {
	if errors.Is(err, domain.ErrInvalidPreferenceValue) {
		var valErr *service.ValidationError
		if errors.As(err, &valErr) {
			return httperror.WithDetails(
				httperror.Validation("Invalid preference values"),
				valErr.Details,
			)
		}
		return httperror.BadRequest("invalid preference value")
	}
	return err
}
