import * as kv from "./kv_store.tsx";
import { createLogger } from "./logger.tsx";

const logger = createLogger('CalendariosTrabalho');

// Calendario de Trabalho — define o horario normal contra o qual os
// registos de presenca sao comparados (base do motor de calculo
// automatico de horas, Grupo B — ainda por construir). Por empresa, sem
// versionamento por ano (ajustar horarios e operacao corrente).
//
// Ambito desta iteracao (deliberadamente reduzido — ver mensagem ao
// utilizador): sem turnos rotativos (precisaria de um sub-modelo de
// rotacao + o alerta de descanso minimo entre turnos, Art. 101 n.2 da Lei
// 13/2023, ainda por verificar na fonte primaria antes de construir).
export interface CalendarioTrabalho {
  id: string;
  empresaId: string;
  codigo: string;
  descricao: string;
  horaEntrada: string; // HH:mm
  horaSaida: string; // HH:mm
  inicioIntervalo?: string; // HH:mm
  fimIntervalo?: string; // HH:mm
  diasTrabalho: number[]; // 0=domingo .. 6=sabado
  ativo: boolean;
  sistema: boolean; // calendario "Padrão" semeado automaticamente
  dataCriacao: string;
  dataAtualizacao?: string;
}

const CALENDARIO_PREFIX = "calendario_trabalho:";

async function garantirCalendarioPadrao(empresaId: string): Promise<void> {
  const existentes = await kv.getByPrefix<CalendarioTrabalho>(CALENDARIO_PREFIX);
  const jaTem = existentes.some((item) => item && item.empresaId === empresaId);
  if (jaTem) return;

  const id = `calendario_${empresaId}_padrao`;
  const calendario: CalendarioTrabalho = {
    id,
    empresaId,
    codigo: "PADRAO",
    descricao: "Horário Padrão (Segunda a Sexta)",
    horaEntrada: "08:00",
    horaSaida: "17:00",
    inicioIntervalo: "12:00",
    fimIntervalo: "13:00",
    diasTrabalho: [1, 2, 3, 4, 5],
    ativo: true,
    sistema: true,
    dataCriacao: new Date().toISOString(),
  };

  await kv.set(`${CALENDARIO_PREFIX}${id}`, calendario);
  logger.info(`Calendário de trabalho padrão semeado para empresa ${empresaId}`);
}

export async function listarCalendariosTrabalho(
  empresaId: string,
  filtros?: { ativo?: boolean },
): Promise<CalendarioTrabalho[]> {
  try {
    await garantirCalendarioPadrao(empresaId);

    const todos = await kv.getByPrefix<CalendarioTrabalho>(CALENDARIO_PREFIX);
    let calendarios = todos.filter((item) => item && item.empresaId === empresaId);

    if (filtros?.ativo !== undefined) {
      calendarios = calendarios.filter((item) => item.ativo === filtros.ativo);
    }

    calendarios.sort((a, b) => a.codigo.localeCompare(b.codigo));
    return calendarios;
  } catch (error) {
    logger.error("Erro ao listar calendários de trabalho:", error);
    return [];
  }
}

export async function buscarCalendarioTrabalhoPorId(id: string): Promise<CalendarioTrabalho | null> {
  try {
    return (await kv.get(`${CALENDARIO_PREFIX}${id}`)) as CalendarioTrabalho | null;
  } catch (error) {
    logger.error("Erro ao buscar calendário de trabalho:", error);
    return null;
  }
}

// Devolve o calendario que se aplica a um colaborador: o seu proprio
// (Colaborador.calendarioTrabalhoId), ou o "PADRAO" da empresa se nao tiver
// um atribuido explicitamente. Usado pelo motor de calculo de horas
// (calculo-horas-trabalho.tsx) para saber o horario normal contra o qual
// comparar as Presencas.
export async function obterCalendarioTrabalhoAplicavel(
  empresaId: string,
  calendarioTrabalhoId?: string,
): Promise<CalendarioTrabalho | null> {
  if (calendarioTrabalhoId) {
    const calendario = await buscarCalendarioTrabalhoPorId(calendarioTrabalhoId);
    if (calendario && calendario.empresaId === empresaId) return calendario;
  }

  const calendarios = await listarCalendariosTrabalho(empresaId);
  return calendarios.find((item) => item.sistema && item.codigo === "PADRAO") || calendarios[0] || null;
}

export async function criarCalendarioTrabalho(
  dados: Omit<CalendarioTrabalho, "id" | "dataCriacao" | "sistema">,
): Promise<{ success: boolean; data?: CalendarioTrabalho; error?: string }> {
  try {
    if (!dados.empresaId || !dados.codigo?.trim() || !dados.descricao?.trim()) {
      return { success: false, error: "Empresa, código e descrição são obrigatórios" };
    }

    if (!dados.horaEntrada || !dados.horaSaida) {
      return { success: false, error: "Hora de entrada e hora de saída são obrigatórias" };
    }

    if (!Array.isArray(dados.diasTrabalho) || dados.diasTrabalho.length === 0) {
      return { success: false, error: "Indique pelo menos um dia de trabalho" };
    }

    const existentes = await listarCalendariosTrabalho(dados.empresaId);
    if (existentes.some((item) => item.codigo.toUpperCase() === dados.codigo.trim().toUpperCase())) {
      return { success: false, error: "Já existe um calendário com este código nesta empresa" };
    }

    const id = `calendario_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
    const calendario: CalendarioTrabalho = {
      id,
      ...dados,
      codigo: dados.codigo.trim().toUpperCase(),
      sistema: false,
      dataCriacao: new Date().toISOString(),
    };

    await kv.set(`${CALENDARIO_PREFIX}${id}`, calendario);
    logger.info(`Calendário de trabalho criado: ${calendario.codigo}`);

    return { success: true, data: calendario };
  } catch (error) {
    logger.error("Erro ao criar calendário de trabalho:", error);
    return { success: false, error: error.message };
  }
}

export async function atualizarCalendarioTrabalho(
  id: string,
  dados: Partial<CalendarioTrabalho>,
): Promise<{ success: boolean; data?: CalendarioTrabalho; error?: string }> {
  try {
    const calendario = await buscarCalendarioTrabalhoPorId(id);
    if (!calendario) {
      return { success: false, error: "Calendário não encontrado" };
    }

    const calendarioAtualizado: CalendarioTrabalho = {
      ...calendario,
      ...dados,
      id: calendario.id,
      empresaId: calendario.empresaId,
      codigo: calendario.sistema ? calendario.codigo : (dados.codigo?.trim().toUpperCase() ?? calendario.codigo),
      sistema: calendario.sistema,
      dataCriacao: calendario.dataCriacao,
      dataAtualizacao: new Date().toISOString(),
    };

    await kv.set(`${CALENDARIO_PREFIX}${id}`, calendarioAtualizado);
    logger.info(`Calendário de trabalho atualizado: ${id}`);

    return { success: true, data: calendarioAtualizado };
  } catch (error) {
    logger.error("Erro ao atualizar calendário de trabalho:", error);
    return { success: false, error: error.message };
  }
}

export async function deletarCalendarioTrabalho(id: string): Promise<{ success: boolean; error?: string }> {
  try {
    const calendario = await buscarCalendarioTrabalhoPorId(id);
    if (!calendario) {
      return { success: false, error: "Calendário não encontrado" };
    }

    if (calendario.sistema) {
      return { success: false, error: "O calendário padrão não pode ser eliminado — desactive-o em vez disso" };
    }

    await kv.del(`${CALENDARIO_PREFIX}${id}`);
    logger.info(`Calendário de trabalho eliminado: ${id}`);

    return { success: true };
  } catch (error) {
    logger.error("Erro ao eliminar calendário de trabalho:", error);
    return { success: false, error: error.message };
  }
}
