import { Injectable } from '@nestjs/common';
import { type Prisma, type Report as PrismaReport } from '@prisma/client';
import { PrismaService } from '@modules/shared';
import { ReportEntity } from '../../domain/entities/report.entity';
import { type ReportStatus } from '../../domain/enums/report-status.enum';
import { type ReportType } from '../../domain/enums/report-type.enum';
import { type IReportRepository, type ListReportsFilter } from '../../domain/repositories/report.repository';

@Injectable()
export class PrismaReportRepository implements IReportRepository {
  constructor(private readonly prisma: PrismaService) {}

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

  async findByUserId(filter: ListReportsFilter): Promise<{ reports: ReportEntity[]; total: number }> {
    const where: Record<string, unknown> = { userId: filter.userId };
    if (filter.type) where['type'] = filter.type;
    if (filter.status) where['status'] = filter.status;

    const [rows, total] = await Promise.all([
      this.prisma.report.findMany({
        where,
        orderBy: { createdAt: 'desc' },
        take: filter.limit ?? 20,
        skip: filter.offset ?? 0,
      }),
      this.prisma.report.count({ where }),
    ]);

    return { reports: rows.map((r) => this.toDomain(r)), total };
  }

  async save(entity: ReportEntity): Promise<void> {
    await this.prisma.report.create({
      data: {
        id: entity.id,
        userId: entity.userId,
        type: entity.type as string as PrismaReport['type'],
        title: entity.title,
        params: entity.params as Prisma.InputJsonValue,
        content: entity.content as Prisma.InputJsonValue ?? undefined,
        pdfUrl: entity.pdfUrl,
        status: entity.status as string as PrismaReport['status'],
        errorMsg: entity.errorMsg,
      },
    });
  }

  async update(entity: ReportEntity): Promise<void> {
    await this.prisma.report.update({
      where: { id: entity.id },
      data: {
        content: entity.content as Prisma.InputJsonValue ?? undefined,
        pdfUrl: entity.pdfUrl,
        status: entity.status as string as PrismaReport['status'],
        errorMsg: entity.errorMsg,
      },
    });
  }

  async delete(id: string): Promise<void> {
    await this.prisma.report.delete({ where: { id } });
  }

  async countByUserInPeriod(userId: string, periodStart: Date, periodEnd: Date): Promise<number> {
    return this.prisma.report.count({
      where: {
        userId,
        createdAt: { gte: periodStart, lt: periodEnd },
      },
    });
  }

  private toDomain(row: PrismaReport): ReportEntity {
    return new ReportEntity(
      row.id,
      {
        userId: row.userId,
        type: row.type as string as ReportType,
        title: row.title,
        params: row.params as Record<string, unknown>,
        content: row.content as Record<string, unknown> | null,
        pdfUrl: row.pdfUrl,
        status: row.status as string as ReportStatus,
        errorMsg: row.errorMsg,
      },
      row.createdAt,
      row.updatedAt,
    );
  }
}
