import { Injectable } from '@nestjs/common';
import { Prisma } from '@prisma/client';
// eslint-disable-next-line @typescript-eslint/consistent-type-imports -- NestJS DI requires value imports for emitDecoratorMetadata
import { ConflictException, NotFoundException, PrismaService } from '@modules/shared';
import {
  type FavoriteItem,
  type ISavedListingRepository,
  type ListFavoritesParams,
  type ListFavoritesResult,
} from '../../domain/repositories/saved-listing.repository';

@Injectable()
export class PrismaSavedListingRepository implements ISavedListingRepository {
  constructor(private readonly prisma: PrismaService) {}

  async add(
    userId: string,
    listingId: string,
  ): Promise<{ id: string; createdAt: Date }> {
    try {
      const saved = await this.prisma.savedListing.create({
        data: { userId, listingId },
        select: { id: true, createdAt: true },
      });
      return saved;
    } catch (error) {
      if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2002') {
        throw new ConflictException('Đã yêu thích tin đăng này');
      }
      throw error;
    }
  }

  async remove(userId: string, listingId: string): Promise<void> {
    const result = await this.prisma.savedListing.deleteMany({
      where: { userId, listingId },
    });
    if (result.count === 0) {
      throw new NotFoundException('SavedListing');
    }
  }

  async exists(userId: string, listingId: string): Promise<boolean> {
    const count = await this.prisma.savedListing.count({
      where: { userId, listingId },
    });
    return count > 0;
  }

  async listByUser(
    userId: string,
    params: ListFavoritesParams,
  ): Promise<ListFavoritesResult> {
    const take = Math.min(Math.max(params.limit, 1), 100);
    const page = Math.max(params.page, 1);
    const skip = (page - 1) * take;

    const [rows, total] = await Promise.all([
      this.prisma.savedListing.findMany({
        where: { userId },
        skip,
        take,
        orderBy: { createdAt: 'desc' },
        include: {
          listing: {
            include: {
              property: {
                include: {
                  media: { take: 1, orderBy: { order: 'asc' } },
                },
              },
            },
          },
        },
      }),
      this.prisma.savedListing.count({ where: { userId } }),
    ]);

    const data: FavoriteItem[] = rows.map((row) => ({
      id: row.id,
      listingId: row.listingId,
      createdAt: row.createdAt,
      listing: {
        id: row.listing.id,
        title: row.listing.property.title,
        priceVND: row.listing.priceVND.toString(),
        city: row.listing.property.city,
        district: row.listing.property.district,
        thumbnailUrl: row.listing.property.media[0]?.url ?? null,
        status: row.listing.status,
        transactionType: row.listing.transactionType,
      },
    }));

    return { data, total };
  }
}
