import { Injectable } from '@nestjs/common';
import { PrismaService } from 'src/prisma/prisma.service';

@Injectable()
export class NotaCreditoPayloadService {
  constructor(private readonly prisma: PrismaService) {}

  formatDateTimeSifen(date: Date): string {
    return date.toISOString().slice(0, 19);
  }

  toNumberOrNull(value: unknown): number | null {
    if (value === null || value === undefined) return null;
    const n = typeof value === 'number' ? value : Number(value);
    return Number.isFinite(n) ? n : null;
  }

  async buildNotaCreditoPayload(notaCreditoId: string, empresaId: string): Promise<Record<string, unknown>> {
    const notaCredito = await this.prisma.nota_credito_cab.findFirst({
      where: { id: notaCreditoId, empresa_id: empresaId },
      include: {
        cliente_direccion: {
          include: {
            ciudades: true,
            distritos: true,
            departamentos: true,
          },
        },
        clientes: {
          include: {
            personas: {
              include: {
                naturaleza_receptor: true,
                tipo_contribuyente: true,
                tipo_documento_identidad: true,
                ciudades: {
                  include: {
                    distritos: {
                      include: {
                        departamentos: true,
                      },
                    },
                  },
                },
              },
            },
            tipo_operacion: true,
          },
        },
        moneda: true,
        tipo_impuesto: true,
        motivo_emision_nota_credito_y_debito: true,
        nota_credito_subtotal: true,
        nota_credito_det: {
          include: {
            productos: {
              include: {
                unidades_de_medida: true,
                afectacion_iva: true,
              },
            },
          },
        },
      },
    });

    if (!notaCredito) throw new Error('Nota de crédito no encontrada');
    if (!notaCredito.clientes) throw new Error('Cliente no encontrado en la nota de crédito');

    const persona = notaCredito.clientes.personas;
    const dirSeleccionada = (notaCredito as any).cliente_direccion ?? null;
    const personaCiudad = persona?.ciudades;
    const ciudad = dirSeleccionada?.ciudades ?? personaCiudad;
    const distrito = dirSeleccionada?.distritos ?? personaCiudad?.distritos;
    const departamento = dirSeleccionada?.departamentos ?? personaCiudad?.distritos?.departamentos;
    const subtotales = notaCredito.nota_credito_subtotal[0];

    const sucursal =
      notaCredito.empresa_id && notaCredito.dest
        ? await this.prisma.empresas_sucursales.findFirst({
            where: {
              empresa_id: notaCredito.empresa_id,
              punto_establecimiento: notaCredito.dest,
              active: true,
            },
            select: { id: true },
          })
        : null;

    const payload: Record<string, unknown> = {
      empresa_id: notaCredito.empresa_id ?? undefined,
      sucursal_id: sucursal?.id,
      iTiDE: 5,
      cdc: notaCredito.cdc,
      dInfoEmi: notaCredito.dinfoemi ?? null,
      dInfoFisc: notaCredito.dinfofisc ?? null,
      dInfAdic: notaCredito.dinfadic ?? null,
      dEst: notaCredito.dest,
      dPunExp: notaCredito.dpunexp,
      dNumDoc: notaCredito.dnumdoc,
      dSerieNum: notaCredito.dserienum ?? null,
      dFeEmiDE: notaCredito.dfeemide
        ? this.formatDateTimeSifen(notaCredito.dfeemide)
        : this.formatDateTimeSifen(new Date()),
      iTImp: this.toNumberOrNull(notaCredito.tipo_impuesto?.codigo) ?? 1,
      cMoneOpe: notaCredito.moneda?.codigo ?? 'PYG',
      dCondTiCam: notaCredito.dcondticam ?? null,
      dTiCam: this.toNumberOrNull(notaCredito.dticam) ?? null,
      iTipCont: this.toNumberOrNull(persona?.tipo_contribuyente?.codigo) ?? null,
      iNatRec: this.toNumberOrNull(persona?.naturaleza_receptor?.codigo) ?? null,
      iTiOpe: this.toNumberOrNull(notaCredito.clientes.tipo_operacion?.codigo) ?? null,
      cPaisRec: 'PRY',
      iTiContRec: this.toNumberOrNull(persona?.tipo_contribuyente?.codigo) ?? null,
      dRucRec: persona?.ruc ?? null,
      dDVRec: persona?.dv ? this.toNumberOrNull(persona.dv) : null,
      iTipIDRec: persona?.tipo_documento_identidad?.codigo ?? null,
      dDTipIDRec: persona?.tipo_documento_identidad?.descripcion ?? null,
      dNumIDRec: persona?.nro_documento ?? null,
      dNomRec: persona?.razon_social,
      dNomFanRec: notaCredito.clientes.nombre_fantasia ?? null,
      dDirRec: (notaCredito as any).ddirrec ?? dirSeleccionada?.direccion ?? persona?.direccion ?? null,
      dNumCasRec: dirSeleccionada?.nro
        ? this.toNumberOrNull(dirSeleccionada.nro)
        : persona?.nro_casa
          ? this.toNumberOrNull(persona.nro_casa)
          : 0,
      cDepRec: departamento?.codigo ?? null,
      cDisRec: distrito?.codigo ?? null,
      cCiuRec: ciudad?.codigo ?? null,
      dTelRec: (() => {
        const t = persona?.telefono ? persona.telefono.replace(/\s+/g, '') : null;
        return t && t.length >= 6 && t.length <= 15 ? t : null;
      })(),
      dCelRec: (() => {
        const c = persona?.celular ? persona.celular.replace(/\s+/g, '') : null;
        return c && c.length >= 10 && c.length <= 20 ? c : null;
      })(),
      dEmailRec: persona?.email ?? null,
      dCodCliente: notaCredito.clientes.cod_cliente ?? null,
      iMotEmi: this.toNumberOrNull(notaCredito.motivo_emision_nota_credito_y_debito?.codigo) ?? null,
      dDesMotEmi: notaCredito.motivo_emision_nota_credito_y_debito?.descripcion ?? null,
    };

    if (notaCredito.documentos_asociados) {
      const docAsoc = notaCredito.documentos_asociados as Record<string, unknown>;
      payload.DocumentosAsociados = [
        {
          iTipDocAso: 1,
          dCdCDERef: docAsoc.dcdcderef ?? null,
          dNTimDI: docAsoc.dntimdi ?? null,
          dEstDocAso: docAsoc.destdocaso ?? null,
          dPExpDocAso: docAsoc.dpexpdocaso ?? null,
          dNumDocAso: docAsoc.dnumdocaso ?? null,
          iTipoDocAso: docAsoc.itipdocaso != 1 ? 1 : null,
          dFecEmiDI: docAsoc.dfecemidi ?? null,
          dNumComRet: docAsoc.dnumcomret ?? null,
          dResCF: docAsoc.dnumrescf ?? null,
          dNumCons: docAsoc.dnumcons ?? null,
          dNumControl: docAsoc.dnumcontrol ?? null,
        },
      ];
    }

    if (subtotales) {
      payload.Subtotales = [
        {
          dSubExe: this.toNumberOrNull(subtotales.dsubexe) ?? 0,
          dSubExo: this.toNumberOrNull(subtotales.dsubexo) ?? 0,
          dSub5: this.toNumberOrNull(subtotales.dsub5) ?? 0,
          dSub10: this.toNumberOrNull(subtotales.dsub10) ?? 0,
          dTotOpe: this.toNumberOrNull(subtotales.dtotope) ?? 0,
          dTotDesc: this.toNumberOrNull(subtotales.dtotdesc) ?? 0,
          dTotDescGlotem: this.toNumberOrNull(subtotales.dtotdescglotem) ?? 0,
          dTotAntItem: this.toNumberOrNull(subtotales.dtotantitem) ?? 0,
          dTotAnt: this.toNumberOrNull(subtotales.dtotant) ?? 0,
          dPorcDescTotal: this.toNumberOrNull(subtotales.dporcdesctotal) ?? 0,
          dDescTotal: 0,
          dAnticipo: this.toNumberOrNull(subtotales.danticipo) ?? 0,
          dRedon: this.toNumberOrNull(subtotales.dredon) ?? 0,
          dComi: this.toNumberOrNull(subtotales.dcomi) ?? 0,
          dTotGralOpe: this.toNumberOrNull(subtotales.dtotgralope) ?? 0,
          dIVA5: this.toNumberOrNull(subtotales.diva5) ?? 0,
          dIVA10: this.toNumberOrNull(subtotales.diva10) ?? 0,
          dLiqTotIVA5: this.toNumberOrNull(subtotales.dliqtotiva5) ?? 0,
          dLiqTotIVA10: this.toNumberOrNull(subtotales.dliqtotiva10) ?? 0,
          dIVAComi: this.toNumberOrNull(subtotales.divacomi) ?? 0,
          dTotIVA: this.toNumberOrNull(subtotales.dtotiva) ?? 0,
          dBaseGrav5: this.toNumberOrNull(subtotales.dbasegrav5) ?? 0,
          dBaseGrav10: this.toNumberOrNull(subtotales.dbasegrav10) ?? 0,
          dTBasGraIVA: this.toNumberOrNull(subtotales.dtbasgraiva) ?? 0,
          dTotalGs: this.toNumberOrNull(subtotales.dtotalgs) ?? 0,
        },
      ];
    }

    if (notaCredito.nota_credito_det.length > 0) {
      payload.Detalles = notaCredito.nota_credito_det.map((item) => {
        const prod = item.productos;
        return {
          dCodInt: prod.cod_producto ?? prod.id?.replace(/-/g, '').slice(0, 5) ?? null,
          dDncpG: prod.ddncpg ?? null,
          dDncpE: prod.ddncpe ?? null,
          dDesProSer: item.ddesproser,
          cUniMed: prod.unidades_de_medida?.codigo ?? item.cunimed,
          dCantProSer: this.toNumberOrNull(item.dcantproser) ?? 0,
          cPaisOrig: item.cpaisorig ?? null,
          dInfItem: item.dinfitem ?? null,
          dPUniProSer: this.toNumberOrNull(item.duniproser) ?? 0,
          dTiCamIt: this.toNumberOrNull(item.dticamit) ?? null,
          dTotBruOpeItem: this.toNumberOrNull(item.dtotbruopeitem) ?? 0,
          dDescItem: this.toNumberOrNull(item.ddescitem) ?? 0,
          dPorcDesIt: this.toNumberOrNull(item.dporcdesit) ?? 0,
          dTotOpeItem: this.toNumberOrNull(item.dtotopeitem) ?? 0,
          dTotOpeGs: null,
          iAfecIVA: this.toNumberOrNull(prod.afectacion_iva?.codigo) ?? this.toNumberOrNull(item.iafeciva) ?? null,
          dPropIVA: this.toNumberOrNull(item.dpropiva) ?? null,
          dTasaIVA: this.toNumberOrNull(item.dtasiva) ?? null,
          dBasGravIVA: this.toNumberOrNull(item.dbasgraviva) ?? null,
          dLiqIVAItem: this.toNumberOrNull(item.dliqivaitem) ?? null,
          dBasExe: this.toNumberOrNull(item.dbasexe) ?? null,
        };
      });
    }

    return payload;
  }
}
