import { prisma } from "../database";
import type { EventFeedback, Prisma } from "@/prisma/generated/prisma/client";
import { ValidationError, NotFoundError } from "../errors";
import { eventService } from "./event.service";

export interface CreateOrUpdateFeedbackInput {
  rating: number;
  comment?: string | null;
}

export interface FeedbackStatistics {
  eventId: string;
  eventName: string;
  eventDate: Date | null;
  eventType: string | null;
  averageRating: number;
  feedbackCount: number;
}

/**
 * Service de gestion des feedbacks sur les événements
 */
export class EventFeedbackService {
  /**
   * Crée ou met à jour un feedback
   */
  async createOrUpdateFeedback(
    userId: string,
    eventId: string,
    data: CreateOrUpdateFeedbackInput
  ): Promise<EventFeedback> {
    return prisma.eventFeedback.upsert({
      where: {
        userId_eventId: {
          userId,
          eventId,
        },
      },
      update: {
        rating: data.rating,
        comment: data.comment || null,
      },
      create: {
        userId,
        eventId,
        rating: data.rating,
        comment: data.comment || null,
      },
    });
  }

  /**
   * Récupère le feedback d'un utilisateur pour un événement
   */
  async getUserFeedback(
    userId: string,
    eventId: string
  ): Promise<EventFeedback | null> {
    return prisma.eventFeedback.findUnique({
      where: {
        userId_eventId: {
          userId,
          eventId,
        },
      },
      include: {
        event: {
          select: {
            id: true,
            name: true,
            date: true,
          },
        },
      },
    });
  }

  /**
   * Récupère tous les feedbacks (pour admin)
   */
  async getAllFeedbacks(options?: {
    include?: Prisma.EventFeedbackInclude;
    orderBy?: Prisma.EventFeedbackOrderByWithRelationInput;
  }): Promise<EventFeedback[]> {
    return prisma.eventFeedback.findMany({
      include: options?.include || {
        event: {
          select: {
            id: true,
            name: true,
            date: true,
            type: true,
          },
        },
        user: {
          select: {
            id: true,
            username: true,
            email: true,
          },
        },
      },
      orderBy: options?.orderBy || { createdAt: "desc" },
    });
  }

  /**
   * Récupère les statistiques de feedback par événement
   */
  async getFeedbackStatistics(): Promise<FeedbackStatistics[]> {
    // Calculer les statistiques par événement
    const eventStats = await prisma.eventFeedback.groupBy({
      by: ["eventId"],
      _avg: {
        rating: true,
      },
      _count: {
        id: true,
      },
    });

    // Récupérer les détails des événements pour les stats
    const eventIds = eventStats.map((stat) => stat.eventId);
    const events = await prisma.event.findMany({
      where: {
        id: {
          in: eventIds,
        },
      },
      select: {
        id: true,
        name: true,
        date: true,
        type: true,
      },
    });

    // Combiner les stats avec les détails des événements
    return eventStats.map((stat) => {
      const event = events.find((e) => e.id === stat.eventId);
      return {
        eventId: stat.eventId,
        eventName: event?.name || "Événement supprimé",
        eventDate: event?.date || null,
        eventType: event?.type || null,
        averageRating: stat._avg.rating || 0,
        feedbackCount: stat._count.id,
      };
    });
  }

  /**
   * Valide et crée/met à jour un feedback avec toutes les règles métier
   */
  async validateAndCreateFeedback(
    userId: string,
    eventId: string,
    data: { rating: number; comment?: string | null }
  ): Promise<EventFeedback> {
    // Valider la note (1-5)
    if (!data.rating || data.rating < 1 || data.rating > 5) {
      throw new ValidationError("La note doit être entre 1 et 5", "rating");
    }

    // Vérifier que l'événement existe
    const event = await eventService.getEventById(eventId);
    if (!event) {
      throw new NotFoundError("Événement");
    }

    // Créer ou mettre à jour le feedback
    return this.createOrUpdateFeedback(userId, eventId, {
      rating: data.rating,
      comment: data.comment || null,
    });
  }
}

export const eventFeedbackService = new EventFeedbackService();
