package service

import (
	"context"

	"github.com/calendarapi/internal/models"
	"github.com/calendarapi/internal/repository"
	"github.com/calendarapi/internal/utils"
	"github.com/google/uuid"
	"github.com/jackc/pgx/v5"
)

type AttendeeService struct {
	queries  *repository.Queries
	calendar *CalendarService
}

func NewAttendeeService(queries *repository.Queries, calendar *CalendarService) *AttendeeService {
	return &AttendeeService{queries: queries, calendar: calendar}
}

func (s *AttendeeService) AddAttendees(ctx context.Context, userID uuid.UUID, eventID uuid.UUID, attendees []AddAttendeeRequest) (*models.Event, error) {
	ev, err := s.queries.GetEventByID(ctx, utils.ToPgUUID(eventID))
	if err != nil {
		if err == pgx.ErrNoRows {
			return nil, models.ErrNotFound
		}
		return nil, models.ErrInternal
	}

	calID := utils.FromPgUUID(ev.CalendarID)
	role, err := s.calendar.GetRole(ctx, calID, userID)
	if err != nil {
		return nil, err
	}
	if role != "owner" && role != "editor" {
		return nil, models.ErrForbidden
	}

	for _, a := range attendees {
		_, err := s.queries.CreateAttendee(ctx, repository.CreateAttendeeParams{
			ID:      utils.ToPgUUID(uuid.New()),
			EventID: utils.ToPgUUID(eventID),
			UserID:  optionalPgUUID(a.UserID),
			Email:   utils.ToPgTextPtr(a.Email),
		})
		if err != nil {
			return nil, models.ErrInternal
		}
	}

	reminders, _ := loadRemindersHelper(ctx, s.queries, eventID)
	atts, _ := loadAttendeesHelper(ctx, s.queries, eventID)
	attachments, _ := loadAttachmentsHelper(ctx, s.queries, eventID)
	return eventFromDB(ev, reminders, atts, attachments), nil
}

func (s *AttendeeService) UpdateStatus(ctx context.Context, userID uuid.UUID, eventID uuid.UUID, attendeeID uuid.UUID, status string) (*models.Event, error) {
	ev, err := s.queries.GetEventByID(ctx, utils.ToPgUUID(eventID))
	if err != nil {
		if err == pgx.ErrNoRows {
			return nil, models.ErrNotFound
		}
		return nil, models.ErrInternal
	}

	calID := utils.FromPgUUID(ev.CalendarID)
	role, err := s.calendar.GetRole(ctx, calID, userID)
	if err != nil {
		return nil, err
	}

	att, err := s.queries.GetAttendeeByID(ctx, utils.ToPgUUID(attendeeID))
	if err != nil {
		if err == pgx.ErrNoRows {
			return nil, models.ErrNotFound
		}
		return nil, models.ErrInternal
	}

	isOrganizer := role == "owner" || role == "editor"
	isOwnAttendee := att.UserID.Valid && utils.FromPgUUID(att.UserID) == userID
	if !isOrganizer && !isOwnAttendee {
		return nil, models.ErrForbidden
	}

	if status != "pending" && status != "accepted" && status != "declined" && status != "tentative" {
		return nil, models.NewValidationError("status must be pending, accepted, declined, or tentative")
	}

	_, err = s.queries.UpdateAttendeeStatus(ctx, repository.UpdateAttendeeStatusParams{
		ID:     utils.ToPgUUID(attendeeID),
		Status: status,
	})
	if err != nil {
		return nil, models.ErrInternal
	}

	reminders, _ := loadRemindersHelper(ctx, s.queries, eventID)
	atts, _ := loadAttendeesHelper(ctx, s.queries, eventID)
	attachments, _ := loadAttachmentsHelper(ctx, s.queries, eventID)
	return eventFromDB(ev, reminders, atts, attachments), nil
}

func (s *AttendeeService) DeleteAttendee(ctx context.Context, userID uuid.UUID, eventID uuid.UUID, attendeeID uuid.UUID) error {
	ev, err := s.queries.GetEventByID(ctx, utils.ToPgUUID(eventID))
	if err != nil {
		if err == pgx.ErrNoRows {
			return models.ErrNotFound
		}
		return models.ErrInternal
	}

	calID := utils.FromPgUUID(ev.CalendarID)
	role, err := s.calendar.GetRole(ctx, calID, userID)
	if err != nil {
		return err
	}
	if role != "owner" && role != "editor" {
		return models.ErrForbidden
	}

	return s.queries.DeleteAttendee(ctx, repository.DeleteAttendeeParams{
		ID:      utils.ToPgUUID(attendeeID),
		EventID: utils.ToPgUUID(eventID),
	})
}

type AddAttendeeRequest struct {
	UserID *uuid.UUID
	Email  *string
}
