import * as kv from "./kv_store.tsx";
import { createLogger } from "./logger.tsx";
import { buscarColaboradorPorId } from "./colaboradores.tsx";

const logger = createLogger('Ferias');

// ========== TIPOS ==========

// Fluxo de PEDIDO e APROVACAO de ferias apenas. Nao calcula dias
// acumulados/saldo disponivel. Confirmado por leitura directa do texto
// oficial da Lei n.º 13/2023 (Boletim da Republica, extraido via
// pdftotext): Artigo 108 (12 dias no 1º ano de servico efectivo, 30 dias
// nos anos seguintes; 1 dia por mes para contrato a prazo certo entre 3 e
// 12 meses); Artigo 109 n.6 (fraccionamento nunca inferior a 6 dias);
// Artigo 110 (acumulacao maxima de 15 dias por cada 12 meses, ate 60 dias
// no mesmo ano; antecipacao maxima de 30 dias). Mesmo assim NAO calculamos
// nada disto aqui: a Lei do Trabalho define os LIMITES, mas nao substitui
// a confirmacao de um contabilista/advogado laboral sobre como aplicar
// estas regras ao caso real da empresa (ver bloqueio no plano do modulo).
// Este ecra so regista QUE periodo foi pedido/aprovado, nao QUANTO o
// colaborador ainda tem direito a gozar.
export type EstadoPedidoFerias = "pendente" | "aprovado" | "rejeitado" | "cancelado";

export interface PedidoFerias {
  id: string;
  empresaId: string;
  colaboradorId: string;
  dataInicio: string; // YYYY-MM-DD
  dataFim: string; // YYYY-MM-DD
  estado: EstadoPedidoFerias;
  observacoes?: string;
  motivoRejeicao?: string;
  aprovadoPor?: string;
  dataAprovacao?: string;
  dataCriacao: string;
  dataAtualizacao?: string;
}

const FERIAS_PREFIX = "pedido_ferias:";

// ========== VALIDACAO ==========

function validarDatas(dataInicio?: string, dataFim?: string): string | null {
  if (!dataInicio || !/^\d{4}-\d{2}-\d{2}$/.test(dataInicio)) return "Data de início inválida (formato esperado: AAAA-MM-DD)";
  if (!dataFim || !/^\d{4}-\d{2}-\d{2}$/.test(dataFim)) return "Data de fim inválida (formato esperado: AAAA-MM-DD)";
  if (dataFim < dataInicio) return "A data de fim não pode ser anterior à data de início";
  return null;
}

function periodosSobrepoem(inicioA: string, fimA: string, inicioB: string, fimB: string): boolean {
  return inicioA <= fimB && inicioB <= fimA;
}

// ========== FUNCOES DE GESTAO DE PEDIDOS DE FERIAS ==========

export async function criarPedidoFerias(
  dados: Pick<PedidoFerias, "empresaId" | "colaboradorId" | "dataInicio" | "dataFim" | "observacoes">,
): Promise<{ success: boolean; data?: PedidoFerias; error?: string }> {
  try {
    if (!dados.empresaId || !dados.colaboradorId) {
      return { success: false, error: "Empresa e colaborador são obrigatórios" };
    }

    const erroDatas = validarDatas(dados.dataInicio, dados.dataFim);
    if (erroDatas) return { success: false, error: erroDatas };

    const colaborador = await buscarColaboradorPorId(dados.colaboradorId);
    if (!colaborador || colaborador.empresaId !== dados.empresaId) {
      return { success: false, error: "Colaborador não encontrado nesta empresa" };
    }

    const existentes = await listarPedidosFerias(dados.empresaId, { colaboradorId: dados.colaboradorId });
    const conflito = existentes.find(
      (item) =>
        (item.estado === "pendente" || item.estado === "aprovado") &&
        periodosSobrepoem(item.dataInicio, item.dataFim, dados.dataInicio, dados.dataFim),
    );
    if (conflito) {
      return { success: false, error: `Já existe um pedido de férias (${conflito.estado}) que se sobrepõe a este período` };
    }

    const id = `pedido_ferias_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;

    const pedido: PedidoFerias = {
      id,
      empresaId: dados.empresaId,
      colaboradorId: dados.colaboradorId,
      dataInicio: dados.dataInicio,
      dataFim: dados.dataFim,
      observacoes: dados.observacoes,
      estado: "pendente",
      dataCriacao: new Date().toISOString(),
    };

    await kv.set(`${FERIAS_PREFIX}${id}`, pedido);

    logger.info(`Pedido de férias criado: ${colaborador.nome} - ${dados.dataInicio} a ${dados.dataFim}`);

    return { success: true, data: pedido };
  } catch (error) {
    logger.error("Erro ao criar pedido de férias:", error);
    return { success: false, error: error.message };
  }
}

export async function buscarPedidoFeriasPorId(id: string): Promise<PedidoFerias | null> {
  try {
    const pedido = await kv.get(`${FERIAS_PREFIX}${id}`);
    return pedido as PedidoFerias | null;
  } catch (error) {
    logger.error("Erro ao buscar pedido de férias:", error);
    return null;
  }
}

export async function listarPedidosFerias(
  empresaId: string,
  filtros?: { colaboradorId?: string; estado?: EstadoPedidoFerias; dataInicio?: string; dataFim?: string },
): Promise<PedidoFerias[]> {
  try {
    const todosPedidos = await kv.getByPrefix<PedidoFerias>(FERIAS_PREFIX);

    let pedidos = todosPedidos.filter((item) => item && item.empresaId === empresaId);

    if (filtros?.colaboradorId) {
      pedidos = pedidos.filter((item) => item.colaboradorId === filtros.colaboradorId);
    }

    if (filtros?.estado) {
      pedidos = pedidos.filter((item) => item.estado === filtros.estado);
    }

    // Intervalo de filtro representa uma janela de consulta — qualquer pedido
    // que toque a janela (nao so os totalmente contidos) e devolvido.
    if (filtros?.dataInicio) {
      pedidos = pedidos.filter((item) => item.dataFim >= filtros.dataInicio!);
    }

    if (filtros?.dataFim) {
      pedidos = pedidos.filter((item) => item.dataInicio <= filtros.dataFim!);
    }

    pedidos.sort((a, b) => b.dataInicio.localeCompare(a.dataInicio));

    return pedidos;
  } catch (error) {
    logger.error("Erro ao listar pedidos de férias:", error);
    return [];
  }
}

export async function atualizarPedidoFerias(
  id: string,
  dados: Partial<Pick<PedidoFerias, "dataInicio" | "dataFim" | "observacoes">>,
): Promise<{ success: boolean; data?: PedidoFerias; error?: string }> {
  try {
    const pedido = await buscarPedidoFeriasPorId(id);
    if (!pedido) {
      return { success: false, error: "Pedido de férias não encontrado" };
    }

    if (pedido.estado !== "pendente") {
      return { success: false, error: "Só é possível editar pedidos ainda pendentes. Cancele e crie um novo pedido." };
    }

    const dataInicio = dados.dataInicio ?? pedido.dataInicio;
    const dataFim = dados.dataFim ?? pedido.dataFim;
    const erroDatas = validarDatas(dataInicio, dataFim);
    if (erroDatas) return { success: false, error: erroDatas };

    if (dados.dataInicio || dados.dataFim) {
      const existentes = await listarPedidosFerias(pedido.empresaId, { colaboradorId: pedido.colaboradorId });
      const conflito = existentes.find(
        (item) =>
          item.id !== id &&
          (item.estado === "pendente" || item.estado === "aprovado") &&
          periodosSobrepoem(item.dataInicio, item.dataFim, dataInicio, dataFim),
      );
      if (conflito) {
        return { success: false, error: `Já existe um pedido de férias (${conflito.estado}) que se sobrepõe a este período` };
      }
    }

    const pedidoAtualizado: PedidoFerias = {
      ...pedido,
      dataInicio,
      dataFim,
      observacoes: dados.observacoes !== undefined ? dados.observacoes : pedido.observacoes,
      dataAtualizacao: new Date().toISOString(),
    };

    await kv.set(`${FERIAS_PREFIX}${id}`, pedidoAtualizado);

    return { success: true, data: pedidoAtualizado };
  } catch (error) {
    logger.error("Erro ao atualizar pedido de férias:", error);
    return { success: false, error: error.message };
  }
}

export async function aprovarPedidoFerias(
  id: string,
  aprovadoPor: string,
): Promise<{ success: boolean; data?: PedidoFerias; error?: string }> {
  try {
    const pedido = await buscarPedidoFeriasPorId(id);
    if (!pedido) {
      return { success: false, error: "Pedido de férias não encontrado" };
    }

    if (pedido.estado !== "pendente") {
      return { success: false, error: `Este pedido já foi ${pedido.estado === 'aprovado' ? 'aprovado' : pedido.estado}` };
    }

    const pedidoAtualizado: PedidoFerias = {
      ...pedido,
      estado: "aprovado",
      aprovadoPor,
      dataAprovacao: new Date().toISOString(),
      dataAtualizacao: new Date().toISOString(),
    };

    await kv.set(`${FERIAS_PREFIX}${id}`, pedidoAtualizado);

    logger.info(`Pedido de férias aprovado: ${id} por ${aprovadoPor}`);

    return { success: true, data: pedidoAtualizado };
  } catch (error) {
    logger.error("Erro ao aprovar pedido de férias:", error);
    return { success: false, error: error.message };
  }
}

export async function rejeitarPedidoFerias(
  id: string,
  aprovadoPor: string,
  motivoRejeicao: string,
): Promise<{ success: boolean; data?: PedidoFerias; error?: string }> {
  try {
    if (!motivoRejeicao?.trim()) {
      return { success: false, error: "Motivo da rejeição é obrigatório" };
    }

    const pedido = await buscarPedidoFeriasPorId(id);
    if (!pedido) {
      return { success: false, error: "Pedido de férias não encontrado" };
    }

    if (pedido.estado !== "pendente") {
      return { success: false, error: `Este pedido já foi ${pedido.estado === 'aprovado' ? 'aprovado' : pedido.estado}` };
    }

    const pedidoAtualizado: PedidoFerias = {
      ...pedido,
      estado: "rejeitado",
      motivoRejeicao: motivoRejeicao.trim(),
      aprovadoPor,
      dataAprovacao: new Date().toISOString(),
      dataAtualizacao: new Date().toISOString(),
    };

    await kv.set(`${FERIAS_PREFIX}${id}`, pedidoAtualizado);

    logger.info(`Pedido de férias rejeitado: ${id} por ${aprovadoPor}`);

    return { success: true, data: pedidoAtualizado };
  } catch (error) {
    logger.error("Erro ao rejeitar pedido de férias:", error);
    return { success: false, error: error.message };
  }
}

export async function cancelarPedidoFerias(
  id: string,
): Promise<{ success: boolean; data?: PedidoFerias; error?: string }> {
  try {
    const pedido = await buscarPedidoFeriasPorId(id);
    if (!pedido) {
      return { success: false, error: "Pedido de férias não encontrado" };
    }

    if (pedido.estado === "cancelado" || pedido.estado === "rejeitado") {
      return { success: false, error: `Este pedido já está ${pedido.estado}` };
    }

    const pedidoAtualizado: PedidoFerias = {
      ...pedido,
      estado: "cancelado",
      dataAtualizacao: new Date().toISOString(),
    };

    await kv.set(`${FERIAS_PREFIX}${id}`, pedidoAtualizado);

    return { success: true, data: pedidoAtualizado };
  } catch (error) {
    logger.error("Erro ao cancelar pedido de férias:", error);
    return { success: false, error: error.message };
  }
}

export async function deletarPedidoFerias(id: string): Promise<{ success: boolean; error?: string }> {
  try {
    const pedido = await buscarPedidoFeriasPorId(id);
    if (!pedido) {
      return { success: false, error: "Pedido de férias não encontrado" };
    }

    await kv.del(`${FERIAS_PREFIX}${id}`);

    logger.info(`Pedido de férias deletado: ${id}`);

    return { success: true };
  } catch (error) {
    logger.error("Erro ao deletar pedido de férias:", error);
    return { success: false, error: error.message };
  }
}
