import { Processor, WorkerHost } from '@nestjs/bullmq';
import { Logger } from '@nestjs/common';
import type { Job } from 'bullmq';
import { existsSync, mkdirSync, writeFileSync } from 'fs';
import { join } from 'path';
import { NotaCreditoPayloadService } from 'src/nota-creditos/nota-credito-payload.service';
import { MiddlewareSifenService } from 'src/middleware-sifen/middleware-sifen.service';
import { PrismaService } from 'src/prisma/prisma.service';
import { AuditService } from 'src/audit/audit.service';
import type { SendNotaCreditoToSifenJob } from '../types/sifen-job.interface';

@Processor('sifen-nc-queue')
export class SifenNCProcessor extends WorkerHost {
  private readonly logger = new Logger(SifenNCProcessor.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly middlewareSifenService: MiddlewareSifenService,
    private readonly notaCreditoPayloadService: NotaCreditoPayloadService,
    private readonly auditService: AuditService,
  ) {
    super();
  }

  private savePayloadToLog(payload: Record<string, unknown>): void {
    try {
      const logsDir = join(process.cwd(), 'logs', 'sifen');
      if (!existsSync(logsDir)) {
        mkdirSync(logsDir, { recursive: true });
      }
      const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
      const filename = `payload_nc_${timestamp}.json`;
      const filepath = join(logsDir, filename);
      writeFileSync(filepath, JSON.stringify(payload, null, 2), 'utf-8');
      this.logger.log(`Payload NC guardado en: ${filepath}`);
    } catch (error) {
      this.logger.error(`Error guardando payload NC en log: ${error}`);
    }
  }

  private async buildSifenPayload(
    notaCreditoId: string,
    empresaId: string,
  ): Promise<Record<string, unknown>> {
    const payload = await this.notaCreditoPayloadService.buildNotaCreditoPayload(
      notaCreditoId,
      empresaId,
    );
    const payloadMiddleware = {
      nro_lote: String('ncvoice-' + Date.now()),
      tipOpe: '1',
      iTiDE: '5', // Nota de Crédito
      comprobantes: [payload],
    };
    return payloadMiddleware;
  }

  async process(job: Job<SendNotaCreditoToSifenJob>): Promise<void> {
    this.logger.log(
      `Processing SIFEN NC job ${job.id} notaCredito=${job.data.notaCreditoId}`,
    );

    try {
      await this.prisma.nota_credito_cab.update({
        where: { id: job.data.notaCreditoId },
        data: { estado: 'Enviando', estado_sifen: 'Enviando' },
      });

      const payload = await this.buildSifenPayload(
        job.data.notaCreditoId,
        job.data.empresaId,
      );
      this.savePayloadToLog(payload);

      // Guardar nro_lote ANTES de enviar (igual que facturas)
      const nroLote = payload.nro_lote as string;
      await this.prisma.nota_credito_cab.update({
        where: { id: job.data.notaCreditoId },
        data: { nro_lote: nroLote, fecha_envio_sifen: new Date() },
      });

      const middlewareResponse = await this.middlewareSifenService.sendDocumentToMiddlewareSifen(payload);
      this.logger.log(`Middleware SIFEN NC response: ${JSON.stringify(middlewareResponse)}`);

      await this.prisma.nota_credito_cab.update({
        where: { id: job.data.notaCreditoId },
        data: { estado: 'Enviado', estado_sifen: 'Enviado' },
      });

      this.logger.log(
        `Nota de crédito ${job.data.notaCreditoId} enviada a SIFEN correctamente con lote ${nroLote}`,
      );

      await this.auditService.log({
        empresa_id: job.data.empresaId,
        action: 'UPDATE',
        entity_type: 'nota_credito_sifen_envio',
        entity_id: job.data.notaCreditoId,
        descripcion: `[OK] NC enviada a SIFEN | lote ${nroLote}`,
        new_value: { resultado: 'OK', nro_lote: nroLote },
      }).catch(() => undefined);
    } catch (error) {
      const message =
        error instanceof Error ? error.message : 'Error desconocido';
      this.logger.error(
        `Error enviando nota de crédito ${job.data.notaCreditoId} a SIFEN: ${message}`,
      );

      await this.prisma.nota_credito_cab.update({
        where: { id: job.data.notaCreditoId },
        data: { estado: 'Pendiente', estado_sifen: 'Error', mensaje_sifen: message },
      });

      await this.auditService.log({
        empresa_id: job.data.empresaId,
        action: 'UPDATE',
        entity_type: 'nota_credito_sifen_envio',
        entity_id: job.data.notaCreditoId,
        descripcion: `[ERROR] NC no enviada a SIFEN: ${message}`,
        new_value: { resultado: 'ERROR', error: message },
      }).catch(() => undefined);

      throw error;
    }
  }
}
