package service

import (
	"context"
	"time"

	"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 ReminderService struct {
	queries   *repository.Queries
	calendar  *CalendarService
	scheduler ReminderScheduler
}

func NewReminderService(queries *repository.Queries, calendar *CalendarService, scheduler ReminderScheduler) *ReminderService {
	return &ReminderService{queries: queries, calendar: calendar, scheduler: scheduler}
}

func (s *ReminderService) AddReminders(ctx context.Context, userID uuid.UUID, eventID uuid.UUID, minutesBefore []int32) (*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 _, mins := range minutesBefore {
		if err := utils.ValidateReminderMinutes(mins); err != nil {
			return nil, err
		}
		rID := uuid.New()
		_, err := s.queries.CreateReminder(ctx, repository.CreateReminderParams{
			ID:            utils.ToPgUUID(rID),
			EventID:       utils.ToPgUUID(eventID),
			MinutesBefore: mins,
		})
		if err != nil {
			return nil, models.ErrInternal
		}

		startTime := utils.FromPgTimestamptz(ev.StartTime)
		triggerAt := startTime.Add(-time.Duration(mins) * time.Minute)
		if triggerAt.After(time.Now()) && s.scheduler != nil {
			_ = s.scheduler.ScheduleReminder(ctx, eventID, rID, userID, triggerAt)
		}
	}

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

func (s *ReminderService) DeleteReminder(ctx context.Context, userID uuid.UUID, eventID uuid.UUID, reminderID 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.DeleteReminder(ctx, repository.DeleteReminderParams{
		ID:      utils.ToPgUUID(reminderID),
		EventID: utils.ToPgUUID(eventID),
	})
}

func loadRemindersHelper(ctx context.Context, q *repository.Queries, eventID uuid.UUID) ([]models.Reminder, error) {
	rows, err := q.ListRemindersByEvent(ctx, utils.ToPgUUID(eventID))
	if err != nil {
		return []models.Reminder{}, err
	}
	result := make([]models.Reminder, len(rows))
	for i, r := range rows {
		result[i] = models.Reminder{ID: utils.FromPgUUID(r.ID), MinutesBefore: r.MinutesBefore}
	}
	return result, nil
}

func loadAttendeesHelper(ctx context.Context, q *repository.Queries, eventID uuid.UUID) ([]models.Attendee, error) {
	rows, err := q.ListAttendeesByEvent(ctx, utils.ToPgUUID(eventID))
	if err != nil {
		return []models.Attendee{}, err
	}
	result := make([]models.Attendee, len(rows))
	for i, a := range rows {
		var uid *uuid.UUID
		if a.UserID.Valid {
			u := utils.FromPgUUID(a.UserID)
			uid = &u
		}
		result[i] = models.Attendee{ID: utils.FromPgUUID(a.ID), UserID: uid, Email: utils.FromPgText(a.Email), Status: a.Status}
	}
	return result, nil
}

func loadAttachmentsHelper(ctx context.Context, q *repository.Queries, eventID uuid.UUID) ([]models.Attachment, error) {
	rows, err := q.ListAttachmentsByEvent(ctx, utils.ToPgUUID(eventID))
	if err != nil {
		return []models.Attachment{}, err
	}
	result := make([]models.Attachment, len(rows))
	for i, a := range rows {
		result[i] = models.Attachment{ID: utils.FromPgUUID(a.ID), FileURL: a.FileUrl}
	}
	return result, nil
}
