export interface DocumentoCronologia {
  id?: string;
  numero?: string;
  numeroDocumento?: string;
  dataEmissao?: string;
  dataDocumento?: string;
  dataTransferencia?: string;
  tipo?: string;
  tipoDocumento?: string;
}

interface OpcoesValidacaoCronologia {
  rotuloDocumento: string;
  dataField?: 'dataEmissao' | 'dataDocumento' | 'dataTransferencia';
  numeroField?: 'numero' | 'numeroDocumento';
  tipo?: string;
  ignorarId?: string;
}

export function normalizarDataDocumentoCronologia(data?: string): string {
  if (!data) return '';

  const match = String(data).trim().match(/^(\d{4})-(\d{2})-(\d{2})/);
  if (!match) return '';

  const [, ano, mes, dia] = match;
  const parsed = new Date(Number(ano), Number(mes) - 1, Number(dia));
  if (
    parsed.getFullYear() !== Number(ano) ||
    parsed.getMonth() !== Number(mes) - 1 ||
    parsed.getDate() !== Number(dia)
  ) {
    return '';
  }

  return `${ano}-${mes}-${dia}`;
}

export function formatarDataDocumentoCronologia(data?: string): string {
  const normalizada = normalizarDataDocumentoCronologia(data);
  if (!normalizada) return data || '';

  const [ano, mes, dia] = normalizada.split('-');
  return `${dia}/${mes}/${ano}`;
}

function obterDataDocumento(documento: DocumentoCronologia, dataField: NonNullable<OpcoesValidacaoCronologia['dataField']>): string {
  return normalizarDataDocumentoCronologia(documento[dataField]);
}

function obterTipoDocumento(documento: DocumentoCronologia): string {
  return documento.tipo || documento.tipoDocumento || '';
}

function obterNumeroDocumento(
  documento: DocumentoCronologia,
  numeroField: NonNullable<OpcoesValidacaoCronologia['numeroField']>,
): string {
  return String(documento[numeroField] || documento.numero || documento.numeroDocumento || '');
}

export function obterUltimoDocumentoEmitido(
  documentos: DocumentoCronologia[],
  opcoes: Omit<OpcoesValidacaoCronologia, 'rotuloDocumento'> = {},
): DocumentoCronologia | null {
  const dataField = opcoes.dataField || 'dataEmissao';

  return documentos
    .filter((documento) => {
      if (opcoes.ignorarId && documento.id === opcoes.ignorarId) return false;
      if (opcoes.tipo && obterTipoDocumento(documento) !== opcoes.tipo) return false;
      return Boolean(obterDataDocumento(documento, dataField));
    })
    .sort((a, b) => obterDataDocumento(b, dataField).localeCompare(obterDataDocumento(a, dataField)))[0] || null;
}

export function validarDataEmissaoCronologica(
  documentoNovo: DocumentoCronologia,
  documentosExistentes: DocumentoCronologia[],
  opcoes: OpcoesValidacaoCronologia,
): void {
  const dataField = opcoes.dataField || 'dataEmissao';
  const numeroField = opcoes.numeroField || 'numeroDocumento';
  const dataEmissao = normalizarDataDocumentoCronologia(documentoNovo[dataField]);

  if (!dataEmissao) {
    throw new Error(`Informe uma data de emissão válida para ${opcoes.rotuloDocumento.toLowerCase()}`);
  }

  const ultimoDocumento = obterUltimoDocumentoEmitido(documentosExistentes, {
    dataField,
    numeroField,
    tipo: opcoes.tipo,
    ignorarId: opcoes.ignorarId,
  });
  const ultimaData = normalizarDataDocumentoCronologia(ultimoDocumento?.[dataField]);

  if (ultimoDocumento && ultimaData && dataEmissao < ultimaData) {
    const numeroUltimo = obterNumeroDocumento(ultimoDocumento, numeroField);
    throw new Error(
      `A data de emissão (${formatarDataDocumentoCronologia(dataEmissao)}) não pode ser anterior à última ${opcoes.rotuloDocumento.toLowerCase()} emitida (${numeroUltimo}, ${formatarDataDocumentoCronologia(ultimaData)}). Use ${formatarDataDocumentoCronologia(ultimaData)} ou uma data posterior.`
    );
  }
}

