/**
 * Qué le pasó a un evento SIFEN (ECAN / EINU / EINO) que sigue en Pendiente.
 * Ver docs/plan-alertas-empresa.md.
 *
 * Función pura: recibe el documento, lo que respondió el middleware (o `null` si
 * no se consultó) y la hora actual. El sync de eventos decide con el resultado
 * si actualiza el documento, registra una alerta o la resuelve.
 */

export type CasoEventoPendiente =
  | 'incoherente'
  | 'respondido'
  | 'sin_respuesta'
  | 'no_registrado'
  | 'middleware_falla'
  | 'en_espera';

export interface DocEventoPendiente {
  evento_aplicado: string | null;
  estado_sifen: string | null;
  fecha_evento: Date | null;
}

/**
 * `registro: null` = el middleware respondió bien pero no tiene ese evento
 * (nunca le llegó). `ok: false` = no se pudo consultar.
 */
export type RespuestaConsultaEvento =
  | {
      ok: true;
      registro: {
        // `codrespuesta` se usa para detectar el 4003 de SIFEN ("el CDC ya tiene
        // ese evento"), que vale como confirmación y no como rechazo.
        retorno_sifen?: { estado?: string | null; mensaje?: string | null; codrespuesta?: string | null } | null;
      } | null;
    }
  | { ok: false; error: string };

/** Antes de esto, "sin respuesta" o "no se pudo consultar" es demora normal. */
export const UMBRAL_EVENTO_MS = 60 * 60 * 1000;

/**
 * Datos del documento que no pueden convivir con el evento pendiente, sin
 * necesidad de preguntarle nada al middleware. Devuelve el motivo o null.
 */
export function incoherenciaEvento(doc: DocEventoPendiente): string | null {
  if (!doc.fecha_evento) {
    return 'El evento no tiene fecha de envío: no se puede saber cuándo se mandó ni si llegó a SIFEN.';
  }
  if (doc.evento_aplicado === 'EINU' && doc.estado_sifen === 'Aprobado') {
    return 'Hay una inutilización pendiente sobre un documento aprobado: sólo se inutilizan documentos rechazados.';
  }
  if ((doc.evento_aplicado === 'ECAN' || doc.evento_aplicado === 'EINO') && doc.estado_sifen !== 'Aprobado') {
    const evento = doc.evento_aplicado === 'ECAN' ? 'cancelación' : 'nominación';
    return `Hay una ${evento} pendiente sobre un documento no aprobado (estado SIFEN: ${doc.estado_sifen ?? 'sin estado'}).`;
  }
  return null;
}

export function clasificarEventoPendiente(
  doc: DocEventoPendiente,
  respuesta: RespuestaConsultaEvento | null,
  ahora: Date,
): { caso: CasoEventoPendiente; detalle: string } {
  // Una respuesta definitiva de SIFEN manda: resuelve el pendiente con el dato
  // oficial aunque el documento tuviera algo raro.
  if (respuesta?.ok && respuesta.registro?.retorno_sifen?.estado) {
    return { caso: 'respondido', detalle: `SIFEN respondió: ${respuesta.registro.retorno_sifen.estado}.` };
  }

  const incoherencia = incoherenciaEvento(doc);
  if (incoherencia) return { caso: 'incoherente', detalle: incoherencia };

  // La fecha está garantizada por la validación de incoherencias de arriba.
  const antiguedad = ahora.getTime() - (doc.fecha_evento ?? ahora).getTime();
  const vencido = antiguedad > UMBRAL_EVENTO_MS;

  if (!respuesta) return { caso: 'en_espera', detalle: 'Sin consultar.' };

  if (respuesta.ok === false) {
    return vencido
      ? { caso: 'middleware_falla', detalle: `No se pudo consultar el evento en el middleware: ${respuesta.error}` }
      : { caso: 'en_espera', detalle: `Consulta fallida, se reintenta: ${respuesta.error}` };
  }

  if (!respuesta.registro) {
    return { caso: 'no_registrado', detalle: 'El middleware no tiene registrado este evento: no llegó a SIFEN.' };
  }

  return vencido
    ? { caso: 'sin_respuesta', detalle: 'El evento está en el middleware pero SIFEN no respondió en más de una hora.' }
    : { caso: 'en_espera', detalle: 'Esperando respuesta de SIFEN.' };
}
