package handlers

import (
	"net/http"
	"strings"
	"time"

	"github.com/calendarapi/internal/middleware"
	"github.com/calendarapi/internal/models"
	"github.com/calendarapi/internal/service"
	"github.com/calendarapi/internal/utils"
	"github.com/go-chi/chi/v5"
)

type AvailabilityHandler struct {
	availSvc *service.AvailabilityService
}

func NewAvailabilityHandler(availSvc *service.AvailabilityService) *AvailabilityHandler {
	return &AvailabilityHandler{availSvc: availSvc}
}

// GetByToken returns busy blocks for a calendar by its public token. No auth required.
func (h *AvailabilityHandler) GetByToken(w http.ResponseWriter, r *http.Request) {
	token := chi.URLParam(r, "token")
	if token == "" {
		utils.WriteError(w, models.ErrNotFound)
		return
	}

	startStr := r.URL.Query().Get("start")
	endStr := r.URL.Query().Get("end")
	if startStr == "" || endStr == "" {
		utils.WriteError(w, models.NewValidationError("start and end required"))
		return
	}
	start, err := time.Parse(time.RFC3339, startStr)
	if err != nil {
		utils.WriteError(w, models.NewValidationError("invalid start time"))
		return
	}
	end, err := time.Parse(time.RFC3339, endStr)
	if err != nil {
		utils.WriteError(w, models.NewValidationError("invalid end time"))
		return
	}

	result, err := h.availSvc.GetBusyBlocksByTokenPublic(r.Context(), token, start, end)
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	utils.WriteJSON(w, http.StatusOK, result)
}

// GetAggregate returns merged busy blocks across multiple calendars by their tokens. No auth required.
func (h *AvailabilityHandler) GetAggregate(w http.ResponseWriter, r *http.Request) {
	tokensStr := r.URL.Query().Get("tokens")
	if tokensStr == "" {
		utils.WriteError(w, models.NewValidationError("tokens required (comma-separated)"))
		return
	}
	tokens := strings.Split(tokensStr, ",")

	startStr := r.URL.Query().Get("start")
	endStr := r.URL.Query().Get("end")
	if startStr == "" || endStr == "" {
		utils.WriteError(w, models.NewValidationError("start and end required"))
		return
	}
	start, err := time.Parse(time.RFC3339, startStr)
	if err != nil {
		utils.WriteError(w, models.NewValidationError("invalid start time"))
		return
	}
	end, err := time.Parse(time.RFC3339, endStr)
	if err != nil {
		utils.WriteError(w, models.NewValidationError("invalid end time"))
		return
	}

	result, err := h.availSvc.GetBusyBlocksAggregate(r.Context(), tokens, start, end)
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	utils.WriteJSON(w, http.StatusOK, result)
}

func (h *AvailabilityHandler) Get(w http.ResponseWriter, r *http.Request) {
	userID, _ := middleware.GetUserID(r.Context())
	q := r.URL.Query()

	calIDStr := q.Get("calendar_id")
	if calIDStr == "" {
		utils.WriteError(w, models.NewValidationError("calendar_id required"))
		return
	}
	calID, err := utils.ValidateUUID(calIDStr)
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	startStr := q.Get("start")
	endStr := q.Get("end")
	if startStr == "" || endStr == "" {
		utils.WriteError(w, models.NewValidationError("start and end required"))
		return
	}
	start, err := time.Parse(time.RFC3339, startStr)
	if err != nil {
		utils.WriteError(w, models.NewValidationError("invalid start time"))
		return
	}
	end, err := time.Parse(time.RFC3339, endStr)
	if err != nil {
		utils.WriteError(w, models.NewValidationError("invalid end time"))
		return
	}

	result, err := h.availSvc.GetBusyBlocks(r.Context(), userID, calID, start, end)
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	utils.WriteJSON(w, http.StatusOK, result)
}
