import { listarColaboradores } from "./colaboradores.tsx";
import { listarPresencas } from "./presencas.tsx";
import { listarFeriados, type Feriado } from "./feriados-rh.tsx";
import { obterCalendarioTrabalhoAplicavel } from "./calendarios-trabalho.tsx";
import { listarAutorizacoesHoraExtra } from "./autorizacao-hora-extra.tsx";
import { obterParametrosFiscaisRH } from "./parametros-fiscais-rh.tsx";
import { apurarHorasColaboradorMes } from "./calculo-horas-trabalho.tsx";
import { gerarMapaPresencasMensal } from "./mapa-presencas.tsx";

// ========== RELATORIOS DE CONFORMIDADE (Presencas) ==========
//
// Dois documentos de auditoria/conformidade pedidos na especificacao do
// modulo, ambos so de LEITURA (nao criam nem alteram nenhum registo):
//   - Livro de Trabalho Excepcional (Art. 98 n.3 da Lei n.º 13/2023):
//     regista todo o trabalho prestado em dia de descanso/feriado/
//     tolerancia de ponto, com fundamento e horario, pronto para
//     apresentacao a Inspeccao do Trabalho.
//   - Relatorio de Assiduidade: resumo mensal por colaborador (dias
//     presentes/faltas/atrasos/horas extra por tipo), tambem pensado para
//     inspeccao — reaproveita o Mapa de Presencas (contagens diarias) e o
//     motor de calculo de horas (minutos por categoria).

// ========== LIVRO DE TRABALHO EXCEPCIONAL ==========

export interface LinhaLivroTrabalhoExcepcional {
  colaboradorId: string;
  colaboradorNome: string;
  numeroFuncionario: string;
  data: string;
  horaEntrada: string;
  horaSaida: string;
  fundamento: string;
}

export interface LivroTrabalhoExcepcional {
  empresaId: string;
  dataInicio: string;
  dataFim: string;
  linhas: LinhaLivroTrabalhoExcepcional[];
}

export async function gerarLivroTrabalhoExcepcional(
  empresaId: string,
  dataInicio: string,
  dataFim: string,
): Promise<LivroTrabalhoExcepcional> {
  const colaboradoresAtivos = await listarColaboradores(empresaId, { ativo: true, estado: "ativo" });
  const anoInicio = Number(dataInicio.slice(0, 4));
  const anoFim = Number(dataFim.slice(0, 4));

  const feriadosPorAno = new Map<number, Feriado[]>();
  const linhas: LinhaLivroTrabalhoExcepcional[] = [];

  for (const colaborador of colaboradoresAtivos) {
    const calendario = await obterCalendarioTrabalhoAplicavel(empresaId, colaborador.calendarioTrabalhoId);
    if (!calendario) continue;

    for (let anoCorrente = anoInicio; anoCorrente <= anoFim; anoCorrente += 1) {
      if (!feriadosPorAno.has(anoCorrente)) {
        feriadosPorAno.set(anoCorrente, await listarFeriados(anoCorrente, { provincia: colaborador.provincia }));
      }
    }

    const [presencas, autorizacoes] = await Promise.all([
      listarPresencas(empresaId, { colaboradorId: colaborador.id, dataInicio, dataFim }),
      listarAutorizacoesHoraExtra(empresaId, { colaboradorId: colaborador.id, estado: "aprovado", dataInicio, dataFim }),
    ]);
    const autorizacoesPorData = new Map(autorizacoes.map((a) => [a.data, a]));

    for (const presenca of presencas) {
      if (presenca.tipo !== "presente" || !presenca.horaEntrada || !presenca.horaSaida) continue;

      const diaSemana = new Date(`${presenca.data}T00:00:00Z`).getUTCDay();
      const eDiaTrabalhoNormal = calendario.diasTrabalho.includes(diaSemana);
      const feriado = (feriadosPorAno.get(Number(presenca.data.slice(0, 4))) || []).find(
        (f) => f.data === presenca.data && (!f.provincia || f.provincia === colaborador.provincia),
      );
      const feriadoSuspende = feriado !== undefined && !colaborador.regimeContinuidade;
      const eExcepcional = !eDiaTrabalhoNormal || feriadoSuspende;
      if (!eExcepcional) continue;

      const autorizacao = autorizacoesPorData.get(presenca.data);

      linhas.push({
        colaboradorId: colaborador.id,
        colaboradorNome: colaborador.nome,
        numeroFuncionario: colaborador.numeroFuncionario,
        data: presenca.data,
        horaEntrada: presenca.horaEntrada,
        horaSaida: presenca.horaSaida,
        fundamento: autorizacao?.motivo || presenca.observacoes || "Não especificado",
      });
    }
  }

  linhas.sort((a, b) => a.data.localeCompare(b.data) || a.numeroFuncionario.localeCompare(b.numeroFuncionario));

  return { empresaId, dataInicio, dataFim, linhas };
}

// ========== RELATORIO DE ASSIDUIDADE ==========

export interface LinhaRelatorioAssiduidade {
  colaboradorId: string;
  colaboradorNome: string;
  numeroFuncionario: string;
  cargo: string;
  diasPresentes: number;
  diasFaltaJustificada: number;
  diasFaltaInjustificada: number;
  minutosAtraso: number;
  minutosSaidaAntecipada: number;
  minutosHorasExtraUteis: number;
  minutosHorasExtraSabado: number;
  minutosHorasExtraDomingo: number;
  minutosHorasExtraFeriadoNacional: number;
  minutosHorasExtraFeriadoLocal: number;
  minutosHorasExtraTolerancia: number;
}

export interface RelatorioAssiduidade {
  empresaId: string;
  ano: number;
  mes: number;
  linhas: LinhaRelatorioAssiduidade[];
}

export async function gerarRelatorioAssiduidade(empresaId: string, ano: number, mes: number): Promise<RelatorioAssiduidade> {
  const [colaboradoresAtivos, mapa, parametros] = await Promise.all([
    listarColaboradores(empresaId, { ativo: true, estado: "ativo" }),
    gerarMapaPresencasMensal(empresaId, ano, mes),
    obterParametrosFiscaisRH(ano),
  ]);

  const mapaPorColaborador = new Map(mapa.colaboradores.map((linha) => [linha.colaboradorId, linha]));
  const linhas: LinhaRelatorioAssiduidade[] = [];

  for (const colaborador of colaboradoresAtivos) {
    const linhaMapa = mapaPorColaborador.get(colaborador.id);
    const apuramento = await apurarHorasColaboradorMes(empresaId, colaborador, ano, mes, parametros);

    linhas.push({
      colaboradorId: colaborador.id,
      colaboradorNome: colaborador.nome,
      numeroFuncionario: colaborador.numeroFuncionario,
      cargo: colaborador.cargo,
      diasPresentes: linhaMapa?.totalPresencas || 0,
      diasFaltaJustificada: linhaMapa?.totalFaltasJustificadas || 0,
      diasFaltaInjustificada: linhaMapa?.totalFaltasInjustificadas || 0,
      minutosAtraso: apuramento.minutosAtraso,
      minutosSaidaAntecipada: apuramento.minutosSaidaAntecipada,
      minutosHorasExtraUteis: apuramento.minutosHorasExtraUteis,
      minutosHorasExtraSabado: apuramento.minutosHorasExtraSabado,
      minutosHorasExtraDomingo: apuramento.minutosHorasExtraDomingo,
      minutosHorasExtraFeriadoNacional: apuramento.minutosHorasExtraFeriadoNacional,
      minutosHorasExtraFeriadoLocal: apuramento.minutosHorasExtraFeriadoLocal,
      minutosHorasExtraTolerancia: apuramento.minutosHorasExtraTolerancia,
    });
  }

  linhas.sort((a, b) => a.numeroFuncionario.localeCompare(b.numeroFuncionario));

  return { empresaId, ano, mes, linhas };
}
