import { Injectable } from '@nestjs/common';
import { type Inquiry as PrismaInquiry } from '@prisma/client';
import { PrismaService } from '@modules/shared';
import { InquiryEntity } from '../../domain/entities/inquiry.entity';
import { type InquiryReadDto } from '../../domain/repositories/inquiry-read.dto';
import { type IInquiryRepository, type PaginatedResult } from '../../domain/repositories/inquiry.repository';

@Injectable()
export class PrismaInquiryRepository implements IInquiryRepository {
  constructor(private readonly prisma: PrismaService) {}

  async findById(id: string): Promise<InquiryEntity | null> {
    const inquiry = await this.prisma.inquiry.findUnique({ where: { id } });
    return inquiry ? this.toDomain(inquiry) : null;
  }

  async save(entity: InquiryEntity): Promise<void> {
    await this.prisma.inquiry.create({
      data: {
        id: entity.id,
        listingId: entity.listingId,
        userId: entity.userId,
        message: entity.message,
        phone: entity.phone,
        isRead: entity.isRead,
      },
    });
  }

  async markAsRead(id: string): Promise<void> {
    await this.prisma.inquiry.update({
      where: { id },
      data: { isRead: true },
    });
  }

  async findByListing(
    listingId: string,
    page: number,
    limit: number,
  ): Promise<PaginatedResult<InquiryReadDto>> {
    const take = Math.min(limit, 100);
    const skip = (page - 1) * take;
    const where = { listingId };

    const [data, total] = await Promise.all([
      this.prisma.inquiry.findMany({
        where,
        skip,
        take,
        orderBy: { createdAt: 'desc' },
        include: {
          listing: { select: { id: true, property: { select: { title: true } } } },
          user: { select: { id: true, fullName: true, phone: true } },
        },
      }),
      this.prisma.inquiry.count({ where }),
    ]);

    return {
      data: data.map((r) => ({
        id: r.id,
        listingId: r.listingId,
        listingTitle: r.listing.property.title,
        userId: r.userId,
        userName: r.user.fullName,
        userPhone: r.user.phone,
        message: r.message,
        phone: r.phone,
        isRead: r.isRead,
        createdAt: r.createdAt.toISOString(),
      })),
      total,
      page,
      limit: take,
      totalPages: Math.ceil(total / take),
    };
  }

  async findByAgent(
    agentId: string,
    page: number,
    limit: number,
  ): Promise<PaginatedResult<InquiryReadDto>> {
    const take = Math.min(limit, 100);
    const skip = (page - 1) * take;
    const where = { listing: { agentId } };

    const [data, total] = await Promise.all([
      this.prisma.inquiry.findMany({
        where,
        skip,
        take,
        orderBy: { createdAt: 'desc' },
        include: {
          listing: { select: { id: true, property: { select: { title: true } } } },
          user: { select: { id: true, fullName: true, phone: true } },
        },
      }),
      this.prisma.inquiry.count({ where }),
    ]);

    return {
      data: data.map((r) => ({
        id: r.id,
        listingId: r.listingId,
        listingTitle: r.listing.property.title,
        userId: r.userId,
        userName: r.user.fullName,
        userPhone: r.user.phone,
        message: r.message,
        phone: r.phone,
        isRead: r.isRead,
        createdAt: r.createdAt.toISOString(),
      })),
      total,
      page,
      limit: take,
      totalPages: Math.ceil(total / take),
    };
  }

  async countUnreadByAgent(agentId: string): Promise<number> {
    return this.prisma.inquiry.count({
      where: {
        isRead: false,
        listing: { agentId },
      },
    });
  }

  private toDomain(raw: PrismaInquiry): InquiryEntity {
    return new InquiryEntity(
      raw.id,
      {
        listingId: raw.listingId,
        userId: raw.userId,
        message: raw.message,
        phone: raw.phone,
        isRead: raw.isRead,
      },
      raw.createdAt,
    );
  }
}
