/**
 * Utilidades para el "Registro de Comprobantes de Ventas, Compras, Ingresos y/o
 * Egresos" de Marangatu (SET Paraguay, especificación 06/2021).
 *
 * Formato del archivo importable:
 *  - CSV delimitado por ';' o TXT por tabulaciones, UTF-8, SIN fila de cabecera.
 *  - Montos enteros positivos sin decimales, con IVA incluido.
 *  - RUC sin dígito verificador.
 *  - Nombre del archivo: <RUC>_REG_MMAAAA_XXXXX (dentro de un ZIP homónimo).
 *
 * Ver docs/docs-pdf/especificaciones-libros-compra-venta-marangatu.md
 */

export const DELIM_CSV = ';';

/** Persona (cliente/proveedor) con los campos mínimos para identificar. */
export interface PersonaMarangatu {
  razon_social?: string | null;
  ruc?: string | null; // sin DV (persona.ruc ya es VarChar(8))
  nro_documento?: string | null;
}

/** Tabla 3: tipos de identificación. */
export const TIPO_ID = {
  RUC: 11,
  CEDULA: 12,
  PASAPORTE: 13,
  CEDULA_EXTRANJERO: 14,
  SIN_NOMBRE: 15,
  DIPLOMATICO: 16,
  IDENTIFICACION_TRIBUTARIA: 17,
} as const;

/** Tabla 4 (subconjunto usado). */
export const TIPO_COMPROBANTE = {
  AUTOFACTURA: 101,
  FACTURA: 109,
  NOTA_CREDITO: 110,
  NOTA_DEBITO: 111,
  TICKET_MAQUINA: 112,
  DESPACHO_IMPORTACION: 107,
} as const;

/** Tabla 2: condición de la operación. */
export const CONDICION = { CONTADO: 1, CREDITO: 2 } as const;

/** Tabla 1: tipos de registro. */
export const TIPO_REGISTRO = { VENTAS: 1, COMPRAS: 2, INGRESOS: 3, EGRESOS: 4 } as const;

/**
 * Fecha → 'dd/mm/aaaa'. Usa los componentes UTC a propósito: las fechas de emisión
 * se guardan como la fecha-calendario a medianoche UTC (o con hora real UTC), y el
 * resto del ERP las lee así (formatDateResponse = toISOString). Usar la hora LOCAL
 * correría la fecha un día en servidores fuera de UTC (Paraguay es UTC-3/-4).
 */
export function fmtFecha(d: Date | string | null | undefined): string {
  if (!d) return '';
  const date = d instanceof Date ? d : new Date(d);
  if (Number.isNaN(date.getTime())) return '';
  const dd = String(date.getUTCDate()).padStart(2, '0');
  const mm = String(date.getUTCMonth() + 1).padStart(2, '0');
  const aaaa = String(date.getUTCFullYear());
  return `${dd}/${mm}/${aaaa}`;
}

/** Monto → entero positivo sin decimales (string). Negativos se llevan a 0. */
export function montoEntero(v: number | string | null | undefined): string {
  const n = Math.round(Number(v ?? 0));
  return String(n > 0 ? n : 0);
}

/** Número de comprobante 'est-punto-numero' → '001-001-0000123'. */
export function numeroComprobante(
  est?: string | null,
  punto?: string | null,
  numero?: string | null,
): string {
  const e = String(est ?? '').replace(/\D/g, '').padStart(3, '0').slice(-3);
  const p = String(punto ?? '').replace(/\D/g, '').padStart(3, '0').slice(-3);
  const n = String(numero ?? '').replace(/\D/g, '').padStart(7, '0').slice(-7);
  if (!numero) return '';
  return `${e}-${p}-${n}`;
}

/** Timbrado → solo dígitos (NUM 8). */
export function timbrado(v?: string | null): string {
  return String(v ?? '').replace(/\D/g, '');
}

/** Código de tipo de identificación según los datos de la persona. */
export function tipoIdentificacion(p?: PersonaMarangatu | null): number {
  if (p?.ruc && p.ruc.trim()) return TIPO_ID.RUC;
  if (p?.nro_documento && p.nro_documento.trim()) return TIPO_ID.CEDULA;
  return TIPO_ID.SIN_NOMBRE;
}

/** Número de identificación (RUC sin DV, o cédula, o '0' para sin nombre). */
export function numeroIdentificacion(p?: PersonaMarangatu | null): string {
  if (p?.ruc && p.ruc.trim()) return p.ruc.trim();
  if (p?.nro_documento && p.nro_documento.trim()) return p.nro_documento.trim();
  return '0';
}

/**
 * Nombre o razón social del comprador/proveedor. Para RUC/Cédula/Sin Nombre no es
 * requerido (Marangatu lo obtiene de sus registros oficiales), pero enviarlo es
 * inofensivo y reproduce el ejemplo oficial de la SET, así que se incluye siempre
 * que exista.
 */
export function nombreRazonSocial(razonSocial?: string | null): string {
  return (razonSocial ?? '').trim();
}

/** Descripción de condición ('Contado'/'Crédito') → código 1/2. */
export function condicionCodigo(descripcion?: string | null): number {
  const d = (descripcion ?? '').toLowerCase();
  return d.includes('cr') /* credito/crédito */ ? CONDICION.CREDITO : CONDICION.CONTADO;
}

/** Booleano → 'S'/'N' (Tabla 5). */
export function boolSN(v: boolean): string {
  return v ? 'S' : 'N';
}

/** ¿Moneda extranjera? (código != 'PYG'). */
export function monedaExtranjera(codigo?: string | null): string {
  return boolSN(!!codigo && codigo.toUpperCase() !== 'PYG');
}

/**
 * Escapa un campo para CSV con ';'. Si contiene ';', '"' o salto de línea,
 * se envuelve en comillas dobles duplicando las internas.
 */
export function csvCampo(valor: string | number): string {
  const s = String(valor ?? '');
  if (/[;"\n\r]/.test(s)) {
    return `"${s.replace(/"/g, '""')}"`;
  }
  return s;
}

/** Une una fila de campos con el delimitador CSV, escapando cada uno. */
export function filaCsv(campos: (string | number)[]): string {
  return campos.map(csvCampo).join(DELIM_CSV);
}

/**
 * Nombre de archivo reglamentario: <RUC sin DV>_REG_MMAAAA_XXXXX
 * @param secuencia identificador alfanumérico del contribuyente (<=5), p.ej. 'V0001'.
 */
export function nombreArchivo(rucSinDv: string, mes: number, anio: number, secuencia: string): string {
  const mm = String(mes).padStart(2, '0');
  const seq = (secuencia || '00001').replace(/[^A-Za-z0-9]/g, '').slice(0, 5) || '00001';
  return `${rucSinDv}_REG_${mm}${anio}_${seq}`;
}
