package handlers

import (
	"net/http"
	"strconv"
	"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"
	"github.com/google/uuid"
)

type EventHandler struct {
	eventSvc *service.EventService
}

func NewEventHandler(eventSvc *service.EventService) *EventHandler {
	return &EventHandler{eventSvc: eventSvc}
}

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

	startStr := q.Get("start")
	endStr := q.Get("end")
	if startStr == "" || endStr == "" {
		utils.WriteError(w, models.NewValidationError("start and end query params 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
	}

	var calendarID *uuid.UUID
	if cid := q.Get("calendar_id"); cid != "" {
		id, err := utils.ValidateUUID(cid)
		if err != nil {
			utils.WriteError(w, err)
			return
		}
		calendarID = &id
	}

	var search *string
	if s := q.Get("search"); s != "" {
		search = &s
	}
	var tag *string
	if t := q.Get("tag"); t != "" {
		tag = &t
	}

	limit := 50
	if l := q.Get("limit"); l != "" {
		if v, err := strconv.Atoi(l); err == nil {
			limit = v
		}
	}

	events, cursor, err := h.eventSvc.List(r.Context(), userID, service.ListEventParams{
		RangeStart: start,
		RangeEnd:   end,
		CalendarID: calendarID,
		Search:     search,
		Tag:        tag,
		Limit:      limit,
		Cursor:     q.Get("cursor"),
	})
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	utils.WriteList(w, events, models.PageInfo{Limit: int(utils.ClampLimit(limit)), NextCursor: cursor})
}

func (h *EventHandler) Create(w http.ResponseWriter, r *http.Request) {
	userID, _ := middleware.GetUserID(r.Context())

	var req struct {
		CalendarID     uuid.UUID `json:"calendar_id"`
		Title          string    `json:"title"`
		Description    *string   `json:"description"`
		Location       *string   `json:"location"`
		StartTime      time.Time `json:"start_time"`
		EndTime        time.Time `json:"end_time"`
		Timezone       string    `json:"timezone"`
		AllDay         bool      `json:"all_day"`
		RecurrenceRule *string   `json:"recurrence_rule"`
		Reminders      []int32   `json:"reminders"`
		Tags           []string  `json:"tags"`
	}
	if err := utils.DecodeJSON(r, &req); err != nil {
		utils.WriteError(w, err)
		return
	}

	event, err := h.eventSvc.Create(r.Context(), userID, service.CreateEventRequest{
		CalendarID:     req.CalendarID,
		Title:          req.Title,
		Description:    req.Description,
		Location:       req.Location,
		StartTime:      req.StartTime,
		EndTime:        req.EndTime,
		Timezone:       req.Timezone,
		AllDay:         req.AllDay,
		RecurrenceRule: req.RecurrenceRule,
		Reminders:      req.Reminders,
		Tags:           req.Tags,
	})
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	utils.WriteJSON(w, http.StatusOK, map[string]interface{}{"event": event})
}

func (h *EventHandler) Get(w http.ResponseWriter, r *http.Request) {
	userID, _ := middleware.GetUserID(r.Context())
	eventID, err := utils.ValidateUUID(chi.URLParam(r, "id"))
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	event, err := h.eventSvc.Get(r.Context(), userID, eventID)
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	utils.WriteJSON(w, http.StatusOK, map[string]interface{}{"event": event})
}

func (h *EventHandler) Update(w http.ResponseWriter, r *http.Request) {
	userID, _ := middleware.GetUserID(r.Context())
	eventID, err := utils.ValidateUUID(chi.URLParam(r, "id"))
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	var req struct {
		Title          *string    `json:"title"`
		Description    *string    `json:"description"`
		Location       *string    `json:"location"`
		StartTime      *time.Time `json:"start_time"`
		EndTime        *time.Time `json:"end_time"`
		Timezone       *string    `json:"timezone"`
		AllDay         *bool      `json:"all_day"`
		RecurrenceRule *string    `json:"recurrence_rule"`
		Tags           []string   `json:"tags"`
	}
	if err := utils.DecodeJSON(r, &req); err != nil {
		utils.WriteError(w, err)
		return
	}

	event, err := h.eventSvc.Update(r.Context(), userID, eventID, service.UpdateEventRequest{
		Title:          req.Title,
		Description:    req.Description,
		Location:       req.Location,
		StartTime:      req.StartTime,
		EndTime:        req.EndTime,
		Timezone:       req.Timezone,
		AllDay:         req.AllDay,
		RecurrenceRule: req.RecurrenceRule,
		Tags:           req.Tags,
	})
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	utils.WriteJSON(w, http.StatusOK, map[string]interface{}{"event": event})
}

func (h *EventHandler) Delete(w http.ResponseWriter, r *http.Request) {
	userID, _ := middleware.GetUserID(r.Context())
	eventID, err := utils.ValidateUUID(chi.URLParam(r, "id"))
	if err != nil {
		utils.WriteError(w, err)
		return
	}

	if err := h.eventSvc.Delete(r.Context(), userID, eventID); err != nil {
		utils.WriteError(w, err)
		return
	}

	utils.WriteOK(w)
}
