import { Injectable } from '@nestjs/common';
import { Prisma } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';
import { ReportDefinition } from '../../../domain/aggregates/report-definition';
import { IReportDefinitionRepository } from '../../../domain/repositories';
import { ReportType } from '../../../domain/value-objects';
import { ReportDefinitionMapper } from '../mappers/report-definition.mapper';

@Injectable()
export class ReportDefinitionRepository implements IReportDefinitionRepository {
  constructor(private readonly prisma: PrismaService) {}

  async save(definition: ReportDefinition): Promise<ReportDefinition> {
    const data = ReportDefinitionMapper.toPersistence(definition);

    if (definition.id) {
      const updated = await this.prisma.reportDefinition.update({
        where: { id: definition.id },
        data: {
          reportName: data.reportName,
          description: data.description,
          parameters: data.parameters as Prisma.InputJsonValue,
          scheduleCron: data.scheduleCron,
          scheduleTimezone: data.scheduleTimezone,
          scheduleEnabled: data.scheduleEnabled,
          outputFormats: data.outputFormats,
          isActive: data.isActive,
          lastGeneratedAt: data.lastGeneratedAt,
        },
      });
      return ReportDefinitionMapper.toDomain(updated);
    }

    const created = await this.prisma.reportDefinition.create({
      data: {
        reportType: data.reportType,
        reportName: data.reportName,
        reportCode: data.reportCode,
        description: data.description,
        parameters: data.parameters as Prisma.InputJsonValue,
        scheduleCron: data.scheduleCron,
        scheduleTimezone: data.scheduleTimezone,
        scheduleEnabled: data.scheduleEnabled,
        outputFormats: data.outputFormats,
        isActive: data.isActive,
      },
    });
    return ReportDefinitionMapper.toDomain(created);
  }

  async findById(id: bigint): Promise<ReportDefinition | null> {
    const found = await this.prisma.reportDefinition.findUnique({
      where: { id },
    });
    return found ? ReportDefinitionMapper.toDomain(found) : null;
  }

  async findByCode(code: string): Promise<ReportDefinition | null> {
    const found = await this.prisma.reportDefinition.findUnique({
      where: { reportCode: code },
    });
    return found ? ReportDefinitionMapper.toDomain(found) : null;
  }

  async findByType(type: ReportType): Promise<ReportDefinition[]> {
    const found = await this.prisma.reportDefinition.findMany({
      where: { reportType: type },
    });
    return found.map(ReportDefinitionMapper.toDomain);
  }

  async findActive(): Promise<ReportDefinition[]> {
    const found = await this.prisma.reportDefinition.findMany({
      where: { isActive: true },
    });
    return found.map(ReportDefinitionMapper.toDomain);
  }

  async findScheduled(): Promise<ReportDefinition[]> {
    const found = await this.prisma.reportDefinition.findMany({
      where: {
        isActive: true,
        scheduleEnabled: true,
      },
    });
    return found.map(ReportDefinitionMapper.toDomain);
  }

  async findAll(): Promise<ReportDefinition[]> {
    const found = await this.prisma.reportDefinition.findMany();
    return found.map(ReportDefinitionMapper.toDomain);
  }

  async delete(id: bigint): Promise<void> {
    await this.prisma.reportDefinition.delete({
      where: { id },
    });
  }
}
