/**
 * @copyright 2026 NHCarrigan
 * @license Naomi's Public License
 * @author Naomi Carrigan
 */

import type { FastifyRequest } from 'fastify';
import { prisma } from '../lib/prisma';
import { AuditService } from './audit.service';
import { AchievementService } from './achievement.service';
import type { Like, LikeCountDto, LikedItemDto, LikeResponse } from '@library/shared-types';
import { AuditAction, AuditCategory, AchievementCategory } from '@library/shared-types';

export class LikeService {
  async toggleLike(userId: string, entityType: Like['entityType'], entityId: string, req: FastifyRequest): Promise<LikeResponse> {
    // Check if like exists
    const existingLike = await prisma.like.findUnique({
      where: {
        userId_entityType_entityId: {
          userId,
          entityType,
          entityId
        }
      }
    });

    if (existingLike) {
      // Unlike
      await prisma.like.delete({
        where: {
          id: existingLike.id
        }
      });

      await AuditService.logFromRequest(req, {
        action: AuditAction.unlike,
        category: AuditCategory.content,
        resourceType: entityType,
        resourceId: entityId,
        details: `Unliked ${entityType}`
      });

      const count = await this.getLikeCount(entityType, entityId);
      return { liked: false, count };
    } else {
      // Like
      await prisma.like.create({
        data: {
          userId,
          entityType,
          entityId
        }
      });

      await AuditService.logFromRequest(req, {
        action: AuditAction.like,
        category: AuditCategory.content,
        resourceType: entityType,
        resourceId: entityId,
        details: `Liked ${entityType}`
      });

      // Check for like achievements
      const achievementService = new AchievementService();
      await achievementService.checkAchievements(
        userId,
        AchievementCategory.Like,
        req
      );

      const count = await this.getLikeCount(entityType, entityId);
      return { liked: true, count };
    }
  }

  async getLikeCount(entityType: Like['entityType'], entityId: string): Promise<number> {
    return await prisma.like.count({
      where: {
        entityType,
        entityId
      }
    });
  }

  async getUserLikeStatus(userId: string, entityType: Like['entityType'], entityId: string): Promise<boolean> {
    const like = await prisma.like.findUnique({
      where: {
        userId_entityType_entityId: {
          userId,
          entityType,
          entityId
        }
      }
    });

    return !!like;
  }

  async getLikeCounts(entityType: Like['entityType'], entityIds: string[]): Promise<LikeCountDto[]> {
    const likes = await prisma.like.groupBy({
      by: ['entityId'],
      where: {
        entityType,
        entityId: { in: entityIds }
      },
      _count: true
    });

    return likes.map(like => ({
      entityId: like.entityId,
      entityType,
      count: like._count
    }));
  }

  async getUserLikeStatuses(userId: string, entityType: Like['entityType'], entityIds: string[]): Promise<Record<string, boolean>> {
    const likes = await prisma.like.findMany({
      where: {
        userId,
        entityType,
        entityId: { in: entityIds }
      },
      select: {
        entityId: true
      }
    });

    const likeMap: Record<string, boolean> = {};
    entityIds.forEach(id => {
      likeMap[id] = false;
    });
    likes.forEach(like => {
      likeMap[like.entityId] = true;
    });

    return likeMap;
  }

  async getUserLikedItems(userId: string, entityType?: Like['entityType']): Promise<LikedItemDto[]> {
    const likes = await prisma.like.findMany({
      where: {
        userId,
        ...(entityType ? { entityType } : {})
      },
      orderBy: {
        createdAt: 'desc'
      }
    });

    // Fetch the actual items for each like
    const likedItems: LikedItemDto[] = [];

    for (const like of likes) {
      let item: any = null;

      switch (like.entityType) {
        case 'book':
          item = await prisma.book.findUnique({ where: { id: like.entityId } });
          break;
        case 'game':
          item = await prisma.game.findUnique({ where: { id: like.entityId } });
          break;
        case 'show':
          item = await prisma.show.findUnique({ where: { id: like.entityId } });
          break;
        case 'manga':
          item = await prisma.manga.findUnique({ where: { id: like.entityId } });
          break;
        case 'music':
          item = await prisma.music.findUnique({ where: { id: like.entityId } });
          break;
        case 'art':
          item = await prisma.art.findUnique({ where: { id: like.entityId } });
          break;
      }

      if (item) {
        likedItems.push({
          like: {
            ...like,
            entityType: like.entityType as Like['entityType']
          },
          item
        });
      }
    }

    return likedItems;
  }
}