// LA SALIDA HACIA LA IMPRENTA DIGITAL.
//
// El modulo habla UN idioma propio y cada imprenta se enchufa por su adaptador.
// Asi, si un dia hay que cambiar de proveedor (o usar el respaldo), se cambia
// esta pieza y no se rehace el sistema.
//
// El numero de control lo asigna LA IMPRENTA (asi funciona en Venezuela: la
// autorizada valida el documento y devuelve el numero). Nuestro libro lleva su
// propio correlativo interno y guarda el numero de control que ella responde.
import type { Asiento } from './tipos.js';
import type { ConfigImprenta } from './config.js';
import type { ModeloFactura } from './factura.js';

/** Lo que responde una imprenta cuando acepta el documento. */
export interface Acuse {
  numeroControl: string;
  numeroDocumento: string;
  fechaAsignacion: string;
  /** Direccion del sello para el QR de la factura, si la imprenta la devuelve. */
  sello?: string;
  /**
   * Rango de numeros de control del que salio este numero (art. 7 numeral 5 de
   * la 000102: la factura debe decir "desde el N... hasta el N..."). Vacio si
   * la imprenta no lo informa o el emisor trabaja con numeracion libre.
   */
  rango?: { desde: string; hasta: string } | null;
  /**
   * Identidad fiscal de la imprenta que numero (art. 7 numeral 14: razon
   * social y RIF de la imprenta digital autorizada, con su providencia de
   * autorizacion). Vacia si la imprenta no la informa.
   */
  imprentaFiscal?: {
    rif: string;
    razon_social: string;
    providencia?: string | null;
    providencia_fecha?: string | null;
  } | null;
  /** Respuesta cruda, para guardarla tal cual junto al asiento. */
  crudo?: unknown;
}

export interface Imprenta {
  readonly nombre: string;
  /** ¿Emite de verdad? El adaptador de practica responde que no. */
  readonly real: boolean;
  emitir(asiento: Asiento): Promise<Acuse>;
  /**
   * Toca la puerta de la imprenta SIN emitir nada: sirve para que el negocio
   * compruebe las credenciales al configurarlas, en vez de enterarse de que
   * estaban malas cuando el cliente esta esperando su factura.
   */
  probar?(): Promise<{ ok: boolean; detalle: string }>;
}

/**
 * IMPRENTA DE PRACTICA: responde igual que una real pero no emite nada.
 * Existe para poder probar el circuito completo (sellar, transmitir, entregar
 * al cliente, reintentar tras una caida) sin gastar documentos reales ni
 * necesitar contrato. Deja bien claro que no es valida.
 */
export class ImprentaPractica implements Imprenta {
  readonly nombre = 'Practica (no emite documentos validos)';
  readonly real = false;
  private n = 0;

  async emitir(asiento: Asiento): Promise<Acuse> {
    this.n += 1;
    return {
      numeroControl: `PRACTICA-${String(asiento.control).padStart(8, '0')}`,
      numeroDocumento: String(asiento.numero),
      fechaAsignacion: new Date().toISOString(),
      // Sin rango: la practica no tiene numeracion autorizada que declarar.
      rango: null,
      // Identidad marcada a proposito: si estas lineas llegan a un papel, que
      // se lea de lejos que el documento no vale.
      imprentaFiscal: {
        rif: 'J-00000000-0',
        razon_social: 'IMPRENTA DE PRACTICA (documento sin valor fiscal)',
        providencia: null,
        providencia_fecha: null,
      },
      crudo: { practica: true, asiento: asiento.seq },
    };
  }

  async probar(): Promise<{ ok: boolean; detalle: string }> {
    return { ok: true, detalle: 'Modo practica: no se conecta con ninguna imprenta y no emite documentos validos.' };
  }
}

/**
 * Arma el adaptador que diga la configuracion. La marca (el modelo de factura
 * del negocio) viaja aparte de la config de la imprenta: es del negocio, no
 * del proveedor, y solo la imprenta propia sabe recibirla.
 */
export async function crearImprenta(cfg: ConfigImprenta, marca?: ModeloFactura | null): Promise<Imprenta> {
  if (cfg.adaptador === 'practica') return new ImprentaPractica();
  if (cfg.adaptador === 'gustito') {
    const { ImprentaGustito } = await import('./imprenta_gustito.js');
    return new ImprentaGustito(cfg, marca);
  }
  if (cfg.adaptador === 'hka') {
    const { ImprentaHKA } = await import('./imprenta_hka.js');
    return new ImprentaHKA(cfg);
  }
  throw new Error(`No conozco la imprenta "${cfg.adaptador}"`);
}
