import * as kv from "./kv_store.tsx";
import { createLogger } from "./logger.tsx";

const logger = createLogger('ConfiguracaoPresencas');

// Parametrizacao de Presencas — por empresa (nao versionado por ano: ajustar
// tolerancias/arredondamento e operacao corrente, ao contrario dos
// Parametros Fiscais que sao uma revisao legal anual). Ver
// calculo-horas-trabalho.tsx (tolerancia/arredondamento aplicados ao
// apurar atrasos/saidas antecipadas/horas extra) e presencas.tsx (fecho de
// presencas).
export type RegraArredondamento = "nenhum" | "cima" | "baixo" | "proximo";

export interface ConfiguracaoPresencas {
  id: string;
  empresaId: string;

  // Minutos de atraso/saida antecipada que NAO contam (ex.: 5 minutos de
  // tolerancia antes de gerar desconto).
  toleranciaAtrasoMinutos: number;
  toleranciaSaidaAntecipadaMinutos: number;

  // Arredondamento aplicado aos minutos de atraso/saida antecipada/hora
  // extra, ja liquidos de tolerancia.
  regraArredondamento: RegraArredondamento;
  arredondamentoIntervaloMinutos: number; // 1, 5 ou 15

  // Politica INTERNA da empresa (mais restritiva que o limite legal do
  // Art. 99 n.3, nunca menos restritiva) — null = usar apenas o limite
  // legal, ja verificado em parametros-fiscais-rh.tsx.
  limiteHorasExtraUteisPorMesMinutos: number | null;

  // Limite de registos manuais por colaborador/mes — modelado conforme a
  // especificacao, mas AINDA NAO APLICADO: sem uma origem "automatica"
  // (biometrico/app) para contrastar, todo registo neste sistema e
  // necessariamente manual, por isso nao ha ainda sinal para distinguir
  // "excesso de manuais" de "uso normal do sistema". Fica pronto para o
  // dia em que existir uma origem automatica.
  limiteRegistosManuaisPorMes: number | null;

  // Fecho de presencas: ate que dia do mes seguinte um registo de Presenca
  // pode ser criado/corrigido/eliminado. null = sem fecho (sempre editavel
  // por quem tiver permissao). Depois do fecho, so super-admin/admin da
  // empresa pode alterar — ver presencas.tsx.
  diaFechoPresencasMesSeguinte: number | null;

  dataCriacao: string;
  dataAtualizacao?: string;
}

const CONFIG_PREFIX = "configuracao_presencas:";

function valoresPadrao(empresaId: string): Omit<ConfiguracaoPresencas, "id" | "dataCriacao"> {
  return {
    empresaId,
    toleranciaAtrasoMinutos: 0,
    toleranciaSaidaAntecipadaMinutos: 0,
    regraArredondamento: "nenhum",
    arredondamentoIntervaloMinutos: 1,
    limiteHorasExtraUteisPorMesMinutos: null,
    limiteRegistosManuaisPorMes: null,
    diaFechoPresencasMesSeguinte: null,
  };
}

export async function obterConfiguracaoPresencas(empresaId: string): Promise<ConfiguracaoPresencas> {
  try {
    const guardada = await kv.get<ConfiguracaoPresencas>(`${CONFIG_PREFIX}${empresaId}`);
    if (guardada) return guardada;

    return {
      id: `configuracao_presencas_${empresaId}`,
      ...valoresPadrao(empresaId),
      dataCriacao: new Date().toISOString(),
    };
  } catch (error) {
    logger.error("Erro ao obter configuração de presenças:", error);
    throw error;
  }
}

export async function atualizarConfiguracaoPresencas(
  empresaId: string,
  dados: Partial<Omit<ConfiguracaoPresencas, "id" | "empresaId" | "dataCriacao">>,
): Promise<{ success: boolean; data?: ConfiguracaoPresencas; error?: string }> {
  try {
    if (dados.toleranciaAtrasoMinutos !== undefined && dados.toleranciaAtrasoMinutos < 0) {
      return { success: false, error: "A tolerância de atraso não pode ser negativa" };
    }
    if (dados.toleranciaSaidaAntecipadaMinutos !== undefined && dados.toleranciaSaidaAntecipadaMinutos < 0) {
      return { success: false, error: "A tolerância de saída antecipada não pode ser negativa" };
    }
    if (dados.arredondamentoIntervaloMinutos !== undefined && ![1, 5, 15].includes(dados.arredondamentoIntervaloMinutos)) {
      return { success: false, error: "O intervalo de arredondamento deve ser 1, 5 ou 15 minutos" };
    }
    if (dados.diaFechoPresencasMesSeguinte !== undefined && dados.diaFechoPresencasMesSeguinte !== null) {
      if (dados.diaFechoPresencasMesSeguinte < 1 || dados.diaFechoPresencasMesSeguinte > 28) {
        return { success: false, error: "O dia de fecho deve estar entre 1 e 28" };
      }
    }

    const actual = await obterConfiguracaoPresencas(empresaId);
    const actualizada: ConfiguracaoPresencas = {
      ...actual,
      ...dados,
      id: actual.id,
      empresaId,
      dataCriacao: actual.dataCriacao,
      dataAtualizacao: new Date().toISOString(),
    };

    await kv.set(`${CONFIG_PREFIX}${empresaId}`, actualizada);
    logger.info(`Configuração de presenças atualizada para empresa ${empresaId}`);

    return { success: true, data: actualizada };
  } catch (error) {
    logger.error("Erro ao atualizar configuração de presenças:", error);
    return { success: false, error: error.message };
  }
}

// Aplica a regra de arredondamento configurada a uma quantidade de minutos
// (ja liquida de tolerancia). Usado por calculo-horas-trabalho.tsx para
// atrasos, saidas antecipadas e horas extra.
export function arredondarMinutos(minutos: number, configuracao: ConfiguracaoPresencas): number {
  if (minutos <= 0) return 0;

  const intervalo = configuracao.arredondamentoIntervaloMinutos || 1;

  switch (configuracao.regraArredondamento) {
    case "cima":
      return Math.ceil(minutos / intervalo) * intervalo;
    case "baixo":
      return Math.floor(minutos / intervalo) * intervalo;
    case "proximo":
      return Math.round(minutos / intervalo) * intervalo;
    case "nenhum":
    default:
      return minutos;
  }
}

// Desconta a tolerancia configurada, nunca devolvendo um valor negativo.
export function aplicarTolerancia(minutos: number, toleranciaMinutos: number): number {
  return Math.max(0, minutos - Math.max(0, toleranciaMinutos));
}

// Verifica se uma data de Presenca ja esta fechada para edicao, segundo o
// dia de fecho configurado (ex.: diaFechoPresencasMesSeguinte=5 e hoje e
// 2026-08-07 -> presencas de Junho/2026 e anteriores estao fechadas, Julho
// ainda esta aberto ate 5/Agosto).
export function dataPresencaFechada(dataPresenca: string, configuracao: ConfiguracaoPresencas, hoje: Date = new Date()): boolean {
  if (configuracao.diaFechoPresencasMesSeguinte === null) return false;

  const [anoPresenca, mesPresenca] = dataPresenca.split("-").map(Number);
  const dataLimite = new Date(Date.UTC(anoPresenca, mesPresenca, configuracao.diaFechoPresencasMesSeguinte));
  const agora = new Date(Date.UTC(hoje.getUTCFullYear(), hoje.getUTCMonth(), hoje.getUTCDate()));

  return agora > dataLimite;
}
