import { prisma } from '../../config/database';
import { notificationService } from './notification.service';
import { friendshipService } from './friendship.service';

export const recommendationService = {
  /** Send a video recommendation to a friend */
  async sendRecommendation(fromUserId: string, toUserId: string, mediaId: number, message?: string) {
    if (fromUserId === toUserId) {
      throw Object.assign(new Error('Cannot recommend to yourself'), { statusCode: 400 });
    }

    // Must be accepted friends
    const friendIds = await friendshipService.getFriendIds(fromUserId);
    if (!friendIds.includes(toUserId)) {
      throw Object.assign(new Error('You can only recommend to friends'), { statusCode: 403 });
    }

    // Check block
    const blocked = await friendshipService.isBlocked(fromUserId, toUserId);
    if (blocked) {
      throw Object.assign(new Error('Cannot send recommendation to this user'), { statusCode: 403 });
    }

    // Verify media exists
    const video = await prisma.video.findUnique({
      where: { id: mediaId },
      select: { id: true, title: true, filename: true },
    });
    if (!video) {
      throw Object.assign(new Error('Video not found'), { statusCode: 404 });
    }

    // Check for duplicate recommendation (same video to same user)
    const existing = await prisma.videoRecommendation.findFirst({
      where: { fromUserId, toUserId, mediaId },
    });
    if (existing) {
      throw Object.assign(new Error('Already recommended this video to this person'), { statusCode: 409 });
    }

    const recommendation = await prisma.videoRecommendation.create({
      data: {
        fromUserId,
        toUserId,
        mediaId,
        message: message || null,
      },
      include: {
        from: { select: { id: true, name: true, email: true } },
        to: { select: { id: true, name: true, email: true } },
        media: { select: { id: true, title: true, filename: true } },
      },
    });

    // Send notification (fire-and-forget)
    const senderName = recommendation.from.name || recommendation.from.email;
    const videoTitle = video.title || video.filename;
    notificationService.createNotification(
      toUserId,
      'system', // closest existing type for recommendations
      'Video Recommendation',
      `${senderName} recommended "${videoTitle}"`,
      { recommendationId: recommendation.id, fromUserId, mediaId, videoTitle },
    ).catch(() => {});

    return recommendation;
  },

  /** List received recommendations (paginated) */
  async listReceivedRecommendations(userId: string, page: number, limit: number) {
    const skip = (page - 1) * limit;

    const [recommendations, total] = await Promise.all([
      prisma.videoRecommendation.findMany({
        where: { toUserId: userId },
        include: {
          from: { select: { id: true, name: true, email: true } },
          media: { select: { id: true, title: true, filename: true, path: true } },
        },
        orderBy: { createdAt: 'desc' },
        skip,
        take: limit,
      }),
      prisma.videoRecommendation.count({ where: { toUserId: userId } }),
    ]);

    return {
      recommendations,
      pagination: { page, limit, total, totalPages: Math.ceil(total / limit) },
    };
  },

  /** List sent recommendations (paginated) */
  async listSentRecommendations(userId: string, page: number, limit: number) {
    const skip = (page - 1) * limit;

    const [recommendations, total] = await Promise.all([
      prisma.videoRecommendation.findMany({
        where: { fromUserId: userId },
        include: {
          to: { select: { id: true, name: true, email: true } },
          media: { select: { id: true, title: true, filename: true, path: true } },
        },
        orderBy: { createdAt: 'desc' },
        skip,
        take: limit,
      }),
      prisma.videoRecommendation.count({ where: { fromUserId: userId } }),
    ]);

    return {
      recommendations,
      pagination: { page, limit, total, totalPages: Math.ceil(total / limit) },
    };
  },

  /** Mark a recommendation as read */
  async markRecommendationRead(userId: string, recommendationId: number) {
    const rec = await prisma.videoRecommendation.findFirst({
      where: { id: recommendationId, toUserId: userId },
    });
    if (!rec) {
      throw Object.assign(new Error('Recommendation not found'), { statusCode: 404 });
    }

    return prisma.videoRecommendation.update({
      where: { id: recommendationId },
      data: { isRead: true },
    });
  },

  /** Get unread recommendation count */
  async getUnreadCount(userId: string): Promise<number> {
    return prisma.videoRecommendation.count({
      where: { toUserId: userId, isRead: false },
    });
  },
};
