import { buscarColaboradorPorId, listarColaboradores } from "./colaboradores.tsx";
import { listarFolhasPagamento } from "./folha-pagamento.tsx";
import { listarAusencias } from "./ausencias.tsx";
import { listarPresencas } from "./presencas.tsx";
import { obterParametrosFiscaisRH } from "./parametros-fiscais-rh.tsx";
import { listarGuiasPagamentoINSS, type EstadoGuiaPagamentoINSS } from "./guia-pagamento-inss.tsx";
import { listarCertificadosRetencaoIRPS, type EstadoCertificadoRetencaoIRPS } from "./certificado-retencao-irps.tsx";
import { calcularDescontoINSSTrabalhador, calcularDescontoIRPS } from "./calculo-salarial.tsx";

// ========== MODELO 19 (IRPS) — Guia de Pagamento ==========
//
// Confirmado por leitura directa do formulario oficial M/19 (Autoridade
// Tributaria de Moçambique, Arts. 83 e 87 do CIRPS): e uma guia de
// pagamento, NAO uma listagem por colaborador — so exige o total retido
// por categoria de rendimento no periodo. Para o nosso caso (folha de
// salarios), o valor a preencher e a linha "10 — Trabalho Dependente".
// Submissao continua a ser feita pelo contribuinte no e-Declaracao da AT;
// isto so calcula o total a que o utilizador deve fazer corresponder no
// formulario oficial.
export interface ResumoModelo19 {
  ano: number;
  mes: number;
  totalTrabalhoDependente: number; // MZN — linha 10 do Modelo 19
  numeroColaboradoresProcessados: number;
  colaboradoresSemProcessamento: string[]; // nomes de colaboradores activos sem folha processada neste periodo
}

export async function gerarResumoModelo19(
  empresaId: string,
  ano: number,
  mes: number,
): Promise<ResumoModelo19> {
  const folhas = await listarFolhasPagamento(empresaId, { ano, mes });

  const totalTrabalhoDependente = folhas.reduce((soma, folha) => soma + folha.descontoIRPS, 0);

  return {
    ano,
    mes,
    totalTrabalhoDependente: Math.round(totalTrabalhoDependente * 100) / 100,
    numeroColaboradoresProcessados: folhas.length,
    colaboradoresSemProcessamento: [],
  };
}

// ========== DECLARACAO DE REMUNERACOES (INSS / SISSMO) ==========
//
// Confirmado por leitura directa do "Guia do Contribuinte" do SISSMO
// (Sistema de Informacoes do INSS, Versao 4.2): formato exacto do
// ficheiro de importacao em massa da Declaracao de Remuneracoes.
//   - Ficheiro .txt, UTF-8, um registo por linha (colaborador), campos
//     separados por ";". Campo vazio = dois separadores seguidos.
//   - Nome do ficheiro: NNNNNNNNNMMAAAA.txt (nº de inscricao da empresa
//     no INSS + mes + ano).
//   - Campos: BENEFICIARIO (nº inscricao INSS do colaborador),
//     NUMERO_DIAS (0-30), VALOR_REMUNERACAO (em centavos, sem separador
//     decimal — ex: 4300,43 MZN -> "430043"), VALOR_COMIS_BONUS,
//     VALOR_SUB_FERIAS (mesma codificacao), TIPO_EVENTO (1=Admissao,
//     2=Demissao, 3=Retorno, 4=Licenca Maternidade, 5=Acidente de
//     Trabalho, 6=SMO, 7=Doenca Profissional, 8=Doenca Pessoal,
//     9=Falecimento, 10=Falta), DT_EVENTO (ddmmaaaa), OBSERVACAO.
//
// So preenchemos TIPO_EVENTO/DT_EVENTO para os casos que temos dados
// reais para sustentar (admissao/demissao no mes, licenca de
// maternidade, luto, falta injustificada) — Acidente de Trabalho,
// SMO, Retorno e Doenca Profissional NAO tem entidade correspondente
// no sistema, por isso nunca sao preenchidos (deliberado, para nao
// adivinhar um evento que nao temos como confirmar).
export interface LinhaDeclaracaoSissmo {
  colaboradorNome: string;
  numeroFuncionario: string;
  beneficiario: string; // numeroInss do colaborador
  numeroDias: number;
  valorRemuneracaoCentavos: number;
  valorComisBonusCentavos: number;
  valorSubFeriasCentavos: number;
  tipoEvento: number | null;
  dtEvento: string | null; // ddmmaaaa
  observacao: string;
}

export interface ResultadoDeclaracaoSissmo {
  linhas: LinhaDeclaracaoSissmo[];
  colaboradoresSemNumeroInss: string[]; // nomes — nao podem entrar na declaracao sem isto
  conteudoFicheiro: string;
}

const DIAS_PADRAO_MES = 30; // SISSMO trata todos os meses como tendo 30 dias, independentemente do calendario

function formatarValorCentavos(valor: number): number {
  return Math.round((valor || 0) * 100);
}

function formatarDataDDMMAAAA(dataIso: string): string {
  const [ano, mes, dia] = dataIso.split("T")[0].split("-");
  return `${dia}${mes}${ano}`;
}

function diaDoMes(dataIso: string): number {
  const [, , dia] = dataIso.split("T")[0].split("-");
  return Number(dia);
}

function dataDentroDoMes(dataIso: string | undefined, ano: number, mes: number): boolean {
  if (!dataIso) return false;
  const [anoData, mesData] = dataIso.split("T")[0].split("-").map(Number);
  return anoData === ano && mesData === mes;
}

function periodoIntersectaMes(dataInicio: string, dataFim: string, ano: number, mes: number): boolean {
  const inicioMes = `${ano}-${String(mes).padStart(2, "0")}-01`;
  const ultimoDiaMes = new Date(ano, mes, 0).getDate();
  const fimMes = `${ano}-${String(mes).padStart(2, "0")}-${String(ultimoDiaMes).padStart(2, "0")}`;
  return dataInicio <= fimMes && dataFim >= inicioMes;
}

export async function gerarDeclaracaoSissmoINSS(
  empresaId: string,
  ano: number,
  mes: number,
  numeroInscricaoEmpresa: string,
): Promise<{ success: boolean; data?: ResultadoDeclaracaoSissmo; error?: string }> {
  try {
    if (!numeroInscricaoEmpresa?.trim()) {
      return { success: false, error: "Número de inscrição da empresa no INSS é obrigatório" };
    }

    const folhas = await listarFolhasPagamento(empresaId, { ano, mes });
    if (folhas.length === 0) {
      return { success: false, error: `Não existem folhas de pagamento processadas para ${mes}/${ano}` };
    }

    const linhas: LinhaDeclaracaoSissmo[] = [];
    const colaboradoresSemNumeroInss: string[] = [];

    for (const folha of folhas) {
      const colaborador = await buscarColaboradorPorId(folha.colaboradorId);
      if (!colaborador) continue;

      if (!colaborador.numeroInss?.trim()) {
        colaboradoresSemNumeroInss.push(colaborador.nome);
        continue;
      }

      let numeroDias = DIAS_PADRAO_MES;
      let tipoEvento: number | null = null;
      let dtEvento: string | null = null;

      // Admissao ou demissao dentro do mes — reduz os dias proporcionalmente
      // e regista o evento (prioridade sobre falta/licenca, sao eventos mais
      // determinantes para o INSS).
      if (dataDentroDoMes(colaborador.dataAdmissao, ano, mes)) {
        const diaAdmissao = diaDoMes(colaborador.dataAdmissao);
        numeroDias = DIAS_PADRAO_MES - diaAdmissao + 1;
        tipoEvento = 1;
        dtEvento = formatarDataDDMMAAAA(colaborador.dataAdmissao);
      } else if (colaborador.dataCessacao && dataDentroDoMes(colaborador.dataCessacao, ano, mes)) {
        const diaCessacao = diaDoMes(colaborador.dataCessacao);
        numeroDias = Math.min(numeroDias, diaCessacao);
        tipoEvento = 2;
        dtEvento = formatarDataDDMMAAAA(colaborador.dataCessacao);
      } else {
        // Licenca de maternidade ou luto aprovados que intersectem o mes
        const ausenciasColaborador = await listarAusencias(empresaId, { colaboradorId: colaborador.id, estado: "aprovado" });
        const licencaMaternidade = ausenciasColaborador.find(
          (item) => item.tipo === "licenca_maternidade" && periodoIntersectaMes(item.dataInicio, item.dataFim, ano, mes),
        );
        const luto = ausenciasColaborador.find(
          (item) => item.tipo === "luto" && periodoIntersectaMes(item.dataInicio, item.dataFim, ano, mes),
        );

        if (licencaMaternidade) {
          tipoEvento = 4;
          dtEvento = formatarDataDDMMAAAA(licencaMaternidade.dataInicio);
        } else if (luto) {
          tipoEvento = 9;
          dtEvento = formatarDataDDMMAAAA(luto.dataInicio);
        } else {
          // Faltas injustificadas do mes reduzem os dias remunerados
          const presencasColaborador = await listarPresencas(empresaId, {
            colaboradorId: colaborador.id,
            tipo: "falta",
            dataInicio: `${ano}-${String(mes).padStart(2, "0")}-01`,
            dataFim: `${ano}-${String(mes).padStart(2, "0")}-${String(new Date(ano, mes, 0).getDate()).padStart(2, "0")}`,
          });
          const faltasInjustificadas = presencasColaborador.filter((item) => item.justificada === false);
          if (faltasInjustificadas.length > 0) {
            numeroDias = Math.max(0, DIAS_PADRAO_MES - faltasInjustificadas.length);
            tipoEvento = 10;
            dtEvento = formatarDataDDMMAAAA(faltasInjustificadas[0].data);
          }
        }
      }

      linhas.push({
        colaboradorNome: colaborador.nome,
        numeroFuncionario: colaborador.numeroFuncionario,
        beneficiario: colaborador.numeroInss.trim(),
        numeroDias,
        valorRemuneracaoCentavos: formatarValorCentavos(folha.salarioBase),
        valorComisBonusCentavos: 0,
        valorSubFeriasCentavos: 0,
        tipoEvento,
        dtEvento,
        observacao: "",
      });
    }

    const linhasFicheiro = linhas.map((linha) =>
      [
        linha.beneficiario,
        linha.numeroDias,
        linha.valorRemuneracaoCentavos,
        linha.valorComisBonusCentavos,
        linha.valorSubFeriasCentavos,
        linha.tipoEvento ?? "",
        linha.dtEvento ?? "",
        linha.observacao,
      ].join(";"),
    );

    return {
      success: true,
      data: {
        linhas,
        colaboradoresSemNumeroInss,
        conteudoFicheiro: linhasFicheiro.join("\r\n"),
      },
    };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

export function nomeFicheiroSissmo(numeroInscricaoEmpresa: string, ano: number, mes: number): string {
  return `${numeroInscricaoEmpresa.trim()}${String(mes).padStart(2, "0")}${ano}.txt`;
}

// ========== HISTORICO DE CONTRIBUICOES INSS ==========
//
// A base de calculo efectiva NAO fica persistida na FolhaPagamento (so os
// valores finais de desconto/encargo) — por isso e reconstituida aqui por
// engenharia inversa a partir da taxa confirmada NESSE ano (base = desconto
// / taxa), o que e exacto desde que os parametros nao tenham mudado depois
// do processamento (ver reprocessamento em lote em folha-pagamento.tsx
// para o caso em que mudaram).
export interface LinhaHistoricoContribuicaoINSS {
  ano: number;
  mes: number;
  numeroRecibo: string;
  baseCalculoAproximada: number;
  descontoINSSTrabalhador: number;
  encargoINSSEmpregador: number;
  contribuicaoTotal: number;
  guiaNumero?: string;
  guiaEstado?: EstadoGuiaPagamentoINSS;
}

export interface HistoricoContribuicoesINSS {
  colaboradorId: string;
  colaboradorNome: string;
  numeroFuncionario: string;
  linhas: LinhaHistoricoContribuicaoINSS[];
  totalContribuicaoTrabalhador: number;
  totalContribuicaoEmpregador: number;
}

export async function gerarHistoricoContribuicoesINSS(
  empresaId: string,
  colaboradorId: string,
): Promise<{ success: boolean; data?: HistoricoContribuicoesINSS; error?: string }> {
  try {
    const colaborador = await buscarColaboradorPorId(colaboradorId);
    if (!colaborador || colaborador.empresaId !== empresaId) {
      return { success: false, error: "Colaborador não encontrado nesta empresa" };
    }

    const folhas = await listarFolhasPagamento(empresaId, { colaboradorId });
    const anosEnvolvidos = Array.from(new Set(folhas.map((f) => f.ano)));
    const guiasPorAno = new Map<number, Awaited<ReturnType<typeof listarGuiasPagamentoINSS>>>();
    for (const ano of anosEnvolvidos) {
      guiasPorAno.set(ano, await listarGuiasPagamentoINSS(empresaId, { ano }));
    }

    const linhas: LinhaHistoricoContribuicaoINSS[] = [];
    for (const folha of folhas) {
      const parametros = await obterParametrosFiscaisRH(folha.ano);
      const baseCalculoAproximada = parametros.inssTaxaTrabalhadorPercentual
        ? Math.round((folha.descontoINSSTrabalhador / (parametros.inssTaxaTrabalhadorPercentual / 100)) * 100) / 100
        : 0;

      const guia = (guiasPorAno.get(folha.ano) || []).find((g) => g.mes === folha.mes && g.estado !== "anulada");

      linhas.push({
        ano: folha.ano,
        mes: folha.mes,
        numeroRecibo: folha.numeroRecibo,
        baseCalculoAproximada,
        descontoINSSTrabalhador: folha.descontoINSSTrabalhador,
        encargoINSSEmpregador: folha.encargoINSSEmpregador,
        contribuicaoTotal: Math.round((folha.descontoINSSTrabalhador + folha.encargoINSSEmpregador) * 100) / 100,
        guiaNumero: guia?.numeroGuia,
        guiaEstado: guia?.estado,
      });
    }

    linhas.sort((a, b) => (b.ano - a.ano) || (b.mes - a.mes));

    return {
      success: true,
      data: {
        colaboradorId,
        colaboradorNome: colaborador.nome,
        numeroFuncionario: colaborador.numeroFuncionario,
        linhas,
        totalContribuicaoTrabalhador: Math.round(linhas.reduce((s, l) => s + l.descontoINSSTrabalhador, 0) * 100) / 100,
        totalContribuicaoEmpregador: Math.round(linhas.reduce((s, l) => s + l.encargoINSSEmpregador, 0) * 100) / 100,
      },
    };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

// ========== MAPA DE ENCARGOS SOCIAIS ==========

export interface LinhaMapaEncargosSociais {
  colaboradorId: string;
  colaboradorNome: string;
  numeroFuncionario: string;
  salarioBase: number;
  descontoINSSTrabalhador: number;
  descontoIRPS: number;
  encargoINSSEmpregador: number;
  custoTotalEmpregador: number; // totalRemuneracoes + encargos patronais
  salarioLiquido: number;
}

export interface MapaEncargosSociais {
  ano: number;
  mes: number;
  linhas: LinhaMapaEncargosSociais[];
  totalDescontoINSSTrabalhador: number;
  totalDescontoIRPS: number;
  totalEncargoINSSEmpregador: number;
  totalCustoEmpregador: number;
}

export async function gerarMapaEncargosSociais(empresaId: string, ano: number, mes: number): Promise<MapaEncargosSociais> {
  const folhas = await listarFolhasPagamento(empresaId, { ano, mes });

  const linhas: LinhaMapaEncargosSociais[] = [];
  for (const folha of folhas) {
    const colaborador = await buscarColaboradorPorId(folha.colaboradorId);
    linhas.push({
      colaboradorId: folha.colaboradorId,
      colaboradorNome: colaborador?.nome || folha.colaboradorId,
      numeroFuncionario: colaborador?.numeroFuncionario || "",
      salarioBase: folha.salarioBase,
      descontoINSSTrabalhador: folha.descontoINSSTrabalhador,
      descontoIRPS: folha.descontoIRPS,
      encargoINSSEmpregador: folha.encargoINSSEmpregador,
      custoTotalEmpregador: Math.round((folha.totalRemuneracoes + folha.totalEncargosPatronais) * 100) / 100,
      salarioLiquido: folha.salarioLiquido,
    });
  }

  linhas.sort((a, b) => a.numeroFuncionario.localeCompare(b.numeroFuncionario));

  return {
    ano,
    mes,
    linhas,
    totalDescontoINSSTrabalhador: Math.round(linhas.reduce((s, l) => s + l.descontoINSSTrabalhador, 0) * 100) / 100,
    totalDescontoIRPS: Math.round(linhas.reduce((s, l) => s + l.descontoIRPS, 0) * 100) / 100,
    totalEncargoINSSEmpregador: Math.round(linhas.reduce((s, l) => s + l.encargoINSSEmpregador, 0) * 100) / 100,
    totalCustoEmpregador: Math.round(linhas.reduce((s, l) => s + l.custoTotalEmpregador, 0) * 100) / 100,
  };
}

// ========== EVOLUCAO DE CONTRIBUICOES INSS ==========

export interface PontoEvolucaoContribuicoesINSS {
  ano: number;
  mes: number;
  contribuicaoTrabalhador: number;
  contribuicaoEmpregador: number;
  contribuicaoTotal: number;
}

// Percorre os ultimos `numeroMeses` (incluindo o mes/ano indicados) e soma
// as contribuicoes de todas as folhas processadas em cada mes.
export async function gerarEvolucaoContribuicoesINSS(
  empresaId: string,
  anoReferencia: number,
  mesReferencia: number,
  numeroMeses: number,
): Promise<PontoEvolucaoContribuicoesINSS[]> {
  const todasFolhas = await listarFolhasPagamento(empresaId);
  const pontos: PontoEvolucaoContribuicoesINSS[] = [];

  let ano = anoReferencia;
  let mes = mesReferencia;

  for (let i = 0; i < numeroMeses; i += 1) {
    const folhasDoMes = todasFolhas.filter((f) => f.ano === ano && f.mes === mes);
    const contribuicaoTrabalhador = Math.round(folhasDoMes.reduce((s, f) => s + f.descontoINSSTrabalhador, 0) * 100) / 100;
    const contribuicaoEmpregador = Math.round(folhasDoMes.reduce((s, f) => s + f.encargoINSSEmpregador, 0) * 100) / 100;

    pontos.unshift({
      ano,
      mes,
      contribuicaoTrabalhador,
      contribuicaoEmpregador,
      contribuicaoTotal: Math.round((contribuicaoTrabalhador + contribuicaoEmpregador) * 100) / 100,
    });

    mes -= 1;
    if (mes < 1) {
      mes = 12;
      ano -= 1;
    }
  }

  return pontos;
}

// ========== PREVISAO DE CONTRIBUICOES INSS ==========
//
// Projeccao simples: aplica as taxas CONFIRMADAS do ano de referencia aos
// salarios base actuais de todos os colaboradores activos, assumindo sem
// alteracoes de quadro/salario nos proximos meses — nao e uma previsao
// estatistica, e um "e se nada mudar", util para planeamento de tesouraria
// de curto prazo.
export interface PontoPrevisaoContribuicoesINSS {
  ano: number;
  mes: number;
  contribuicaoTrabalhadorPrevista: number;
  contribuicaoEmpregadorPrevista: number;
}

export async function gerarPrevisaoContribuicoesINSS(
  empresaId: string,
  anoReferencia: number,
  mesReferencia: number,
  numeroMeses: number,
): Promise<{ success: boolean; data?: PontoPrevisaoContribuicoesINSS[]; error?: string }> {
  const parametros = await obterParametrosFiscaisRH(anoReferencia);
  if (parametros.inssTaxaTrabalhadorPercentual === null || parametros.inssTaxaEmpregadorPercentual === null) {
    return { success: false, error: "Taxas de INSS ainda não confirmadas para este ano — não é possível gerar previsão" };
  }

  const colaboradoresAtivos = await listarColaboradores(empresaId, { ativo: true, estado: "ativo" });
  const baseTotal = colaboradoresAtivos.reduce((soma, c) => {
    const base = parametros.inssTectoSalarialMzn !== null ? Math.min(c.salarioBase, parametros.inssTectoSalarialMzn) : c.salarioBase;
    return soma + base;
  }, 0);

  const contribuicaoTrabalhadorPrevista = Math.round(baseTotal * (parametros.inssTaxaTrabalhadorPercentual / 100) * 100) / 100;
  const contribuicaoEmpregadorPrevista = Math.round(baseTotal * (parametros.inssTaxaEmpregadorPercentual / 100) * 100) / 100;

  const pontos: PontoPrevisaoContribuicoesINSS[] = [];
  let ano = anoReferencia;
  let mes = mesReferencia;

  for (let i = 0; i < numeroMeses; i += 1) {
    pontos.push({ ano, mes, contribuicaoTrabalhadorPrevista, contribuicaoEmpregadorPrevista });
    mes += 1;
    if (mes > 12) {
      mes = 1;
      ano += 1;
    }
  }

  return { success: true, data: pontos };
}

// ========== HISTORICO DE RETENCOES IRPS ==========
//
// Analogo ao historico de contribuicoes INSS acima: o rendimento colectavel
// exacto de cada mes JA fica persistido na FolhaPagamento
// (rendimentoColectavelIRPS), ao contrario da base de INSS — por isso aqui
// nao ha engenharia inversa, e o valor real gravado no momento do
// processamento.
export interface LinhaHistoricoRetencaoIRPS {
  ano: number;
  mes: number;
  numeroRecibo: string;
  rendimentoColectavelIRPS: number;
  descontoIRPS: number;
  certificadoNumero?: string;
  certificadoEstado?: EstadoCertificadoRetencaoIRPS;
}

export interface HistoricoRetencoesIRPS {
  colaboradorId: string;
  colaboradorNome: string;
  numeroFuncionario: string;
  linhas: LinhaHistoricoRetencaoIRPS[];
  totalRetencaoIRPS: number;
}

export async function gerarHistoricoRetencoesIRPS(
  empresaId: string,
  colaboradorId: string,
): Promise<{ success: boolean; data?: HistoricoRetencoesIRPS; error?: string }> {
  try {
    const colaborador = await buscarColaboradorPorId(colaboradorId);
    if (!colaborador || colaborador.empresaId !== empresaId) {
      return { success: false, error: "Colaborador não encontrado nesta empresa" };
    }

    const folhas = await listarFolhasPagamento(empresaId, { colaboradorId });
    const certificados = await listarCertificadosRetencaoIRPS(empresaId, { colaboradorId });
    const certificadosPorAno = new Map(
      certificados.filter((c) => c.estado !== "anulado").map((c) => [c.ano, c]),
    );

    const linhas: LinhaHistoricoRetencaoIRPS[] = folhas.map((folha) => {
      const certificado = certificadosPorAno.get(folha.ano);
      return {
        ano: folha.ano,
        mes: folha.mes,
        numeroRecibo: folha.numeroRecibo,
        rendimentoColectavelIRPS: folha.rendimentoColectavelIRPS,
        descontoIRPS: folha.descontoIRPS,
        certificadoNumero: certificado?.numeroCertificado,
        certificadoEstado: certificado?.estado,
      };
    });

    linhas.sort((a, b) => (b.ano - a.ano) || (b.mes - a.mes));

    return {
      success: true,
      data: {
        colaboradorId,
        colaboradorNome: colaborador.nome,
        numeroFuncionario: colaborador.numeroFuncionario,
        linhas,
        totalRetencaoIRPS: Math.round(linhas.reduce((s, l) => s + l.descontoIRPS, 0) * 100) / 100,
      },
    };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

// ========== MAPA ANUAL DE IRPS ==========

export interface LinhaMapaAnualIRPS {
  colaboradorId: string;
  colaboradorNome: string;
  numeroFuncionario: string;
  retencoesMensais: Array<{ mes: number; descontoIRPS: number }>;
  totalAnual: number;
}

export interface MapaAnualIRPS {
  ano: number;
  linhas: LinhaMapaAnualIRPS[];
  totalGeral: number;
}

export async function gerarMapaAnualIRPS(empresaId: string, ano: number): Promise<MapaAnualIRPS> {
  const folhas = await listarFolhasPagamento(empresaId, { ano });
  const porColaborador = new Map<string, typeof folhas>();

  for (const folha of folhas) {
    const lista = porColaborador.get(folha.colaboradorId) || [];
    lista.push(folha);
    porColaborador.set(folha.colaboradorId, lista);
  }

  const linhas: LinhaMapaAnualIRPS[] = [];
  for (const [colaboradorId, folhasColaborador] of porColaborador.entries()) {
    const colaborador = await buscarColaboradorPorId(colaboradorId);
    const retencoesMensais = folhasColaborador
      .map((f) => ({ mes: f.mes, descontoIRPS: f.descontoIRPS }))
      .sort((a, b) => a.mes - b.mes);

    linhas.push({
      colaboradorId,
      colaboradorNome: colaborador?.nome || colaboradorId,
      numeroFuncionario: colaborador?.numeroFuncionario || "",
      retencoesMensais,
      totalAnual: Math.round(retencoesMensais.reduce((s, l) => s + l.descontoIRPS, 0) * 100) / 100,
    });
  }

  linhas.sort((a, b) => a.numeroFuncionario.localeCompare(b.numeroFuncionario));

  return {
    ano,
    linhas,
    totalGeral: Math.round(linhas.reduce((s, l) => s + l.totalAnual, 0) * 100) / 100,
  };
}

// ========== ANALISE DE PROGRESSIVIDADE IRPS ==========
//
// Distribui os colaboradores com folha processada no mes pelos escaloes de
// IRPS confirmados, com base no rendimentoColectavelIRPS ja gravado em cada
// folha (nao recalcula nada, so classifica).
export interface FaixaProgressividadeIRPS {
  limiteInferior: number;
  limiteSuperior: number | null;
  taxaPercentual: number;
  numeroColaboradores: number;
  totalRetencaoIRPS: number;
}

export interface AnaliseProgressividadeIRPS {
  ano: number;
  mes: number;
  faixas: FaixaProgressividadeIRPS[];
  numeroColaboradoresSemEscalao: number;
}

export async function gerarAnaliseProgressividadeIRPS(
  empresaId: string,
  ano: number,
  mes: number,
): Promise<{ success: boolean; data?: AnaliseProgressividadeIRPS; error?: string }> {
  const parametros = await obterParametrosFiscaisRH(ano);
  if (!parametros.irpsEscaloes || parametros.irpsEscaloes.length === 0) {
    return { success: false, error: "Escalões de IRPS ainda não confirmados para este ano — não é possível gerar a análise de progressividade" };
  }

  const folhas = await listarFolhasPagamento(empresaId, { ano, mes });

  const faixas: FaixaProgressividadeIRPS[] = parametros.irpsEscaloes.map((escalao) => ({
    limiteInferior: escalao.limiteInferior,
    limiteSuperior: escalao.limiteSuperior,
    taxaPercentual: escalao.taxaPercentual,
    numeroColaboradores: 0,
    totalRetencaoIRPS: 0,
  }));

  let numeroColaboradoresSemEscalao = 0;

  for (const folha of folhas) {
    const faixa = faixas.find(
      (f) => folha.rendimentoColectavelIRPS >= f.limiteInferior && (f.limiteSuperior === null || folha.rendimentoColectavelIRPS <= f.limiteSuperior),
    );
    if (!faixa) {
      numeroColaboradoresSemEscalao += 1;
      continue;
    }
    faixa.numeroColaboradores += 1;
    faixa.totalRetencaoIRPS = Math.round((faixa.totalRetencaoIRPS + folha.descontoIRPS) * 100) / 100;
  }

  return { success: true, data: { ano, mes, faixas, numeroColaboradoresSemEscalao } };
}

// ========== PREVISAO DE IRPS ==========
//
// Mesma logica "sem alteracoes" da previsao de INSS: aplica os escaloes
// CONFIRMADOS do ano de referencia ao rendimento colectavel actual dos
// colaboradores activos (aproximado por salarioBase, com a mesma
// metodologia bruto/liquido configurada), projectando para a frente sem
// assumir admissoes/cessacoes/aumentos.
export interface PontoPrevisaoIRPS {
  ano: number;
  mes: number;
  totalRetencaoIRPSPrevista: number;
}

export async function gerarPrevisaoIRPS(
  empresaId: string,
  anoReferencia: number,
  mesReferencia: number,
  numeroMeses: number,
): Promise<{ success: boolean; data?: PontoPrevisaoIRPS[]; error?: string }> {
  const parametros = await obterParametrosFiscaisRH(anoReferencia);
  if (!parametros.irpsEscaloes || parametros.irpsEscaloes.length === 0) {
    return { success: false, error: "Escalões de IRPS ainda não confirmados para este ano — não é possível gerar previsão" };
  }
  if (parametros.irpsIncideSobreRendimentoBruto === null) {
    return { success: false, error: "Metodologia do IRPS (bruto/líquido) ainda não confirmada para este ano — não é possível gerar previsão" };
  }

  const colaboradoresAtivos = await listarColaboradores(empresaId, { ativo: true, estado: "ativo" });
  let totalRetencaoIRPSPrevista = 0;

  for (const colaborador of colaboradoresAtivos) {
    try {
      const descontoINSS = parametros.inssTaxaTrabalhadorPercentual !== null
        ? calcularDescontoINSSTrabalhador(colaborador.salarioBase, parametros)
        : 0;
      const rendimentoColectavel = parametros.irpsIncideSobreRendimentoBruto
        ? colaborador.salarioBase
        : Math.round((colaborador.salarioBase - descontoINSS) * 100) / 100;
      totalRetencaoIRPSPrevista += calcularDescontoIRPS(rendimentoColectavel, parametros);
    } catch {
      // Colaborador cujo salario nao cai em nenhum escalao configurado —
      // excluido da previsao em vez de interromper o calculo de todos os
      // outros.
    }
  }

  totalRetencaoIRPSPrevista = Math.round(totalRetencaoIRPSPrevista * 100) / 100;

  const pontos: PontoPrevisaoIRPS[] = [];
  let ano = anoReferencia;
  let mes = mesReferencia;

  for (let i = 0; i < numeroMeses; i += 1) {
    pontos.push({ ano, mes, totalRetencaoIRPSPrevista });
    mes += 1;
    if (mes > 12) {
      mes = 1;
      ano += 1;
    }
  }

  return { success: true, data: pontos };
}
