import { prisma } from "../database";
import type { EventRegistration } from "@/prisma/generated/prisma/client";
import { ValidationError, NotFoundError, ConflictError } from "../errors";
import { eventService } from "./event.service";
import { calculateEventStatus } from "@/lib/eventStatus";

/**
 * Service de gestion des inscriptions aux événements
 */
export class EventRegistrationService {
  /**
   * Inscrit un utilisateur à un événement
   */
  async registerUserToEvent(
    userId: string,
    eventId: string
  ): Promise<EventRegistration> {
    return prisma.eventRegistration.create({
      data: {
        userId,
        eventId,
      },
    });
  }

  /**
   * Désinscrit un utilisateur d'un événement
   */
  async unregisterUserFromEvent(
    userId: string,
    eventId: string
  ): Promise<void> {
    await prisma.eventRegistration.deleteMany({
      where: {
        userId,
        eventId,
      },
    });
  }

  /**
   * Vérifie si un utilisateur est inscrit à un événement
   */
  async checkUserRegistration(
    userId: string,
    eventId: string
  ): Promise<boolean> {
    const registration = await prisma.eventRegistration.findUnique({
      where: {
        userId_eventId: {
          userId,
          eventId,
        },
      },
    });
    return !!registration;
  }

  /**
   * Récupère l'inscription d'un utilisateur à un événement
   */
  async getUserRegistration(
    userId: string,
    eventId: string
  ): Promise<EventRegistration | null> {
    return prisma.eventRegistration.findUnique({
      where: {
        userId_eventId: {
          userId,
          eventId,
        },
      },
    });
  }

  /**
   * Récupère toutes les inscriptions d'un utilisateur
   */
  async getUserRegistrations(userId: string): Promise<EventRegistration[]> {
    return prisma.eventRegistration.findMany({
      where: {
        userId,
      },
      select: {
        eventId: true,
      },
    });
  }

  /**
   * Récupère le nombre d'inscriptions pour un événement
   */
  async getEventRegistrationsCount(eventId: string): Promise<number> {
    const count = await prisma.eventRegistration.count({
      where: {
        eventId,
      },
    });
    return count;
  }

  /**
   * Valide et inscrit un utilisateur à un événement avec toutes les règles métier
   */
  async validateAndRegisterUser(
    userId: string,
    eventId: string
  ): Promise<EventRegistration> {
    // Vérifier que l'événement existe
    const event = await eventService.getEventById(eventId);
    if (!event) {
      throw new NotFoundError("Événement");
    }

    // Vérifier que l'événement est à venir
    const eventStatus = calculateEventStatus(event.date);
    if (eventStatus !== "UPCOMING") {
      throw new ValidationError(
        "Vous ne pouvez vous inscrire qu'aux événements à venir"
      );
    }

    // Vérifier si l'utilisateur est déjà inscrit
    const isRegistered = await this.checkUserRegistration(userId, eventId);
    if (isRegistered) {
      throw new ConflictError("Vous êtes déjà inscrit à cet événement");
    }

    // Créer l'inscription
    return this.registerUserToEvent(userId, eventId);
  }
}

export const eventRegistrationService = new EventRegistrationService();
