import dayjs from "dayjs";
import { personaEmpresaService } from "./personaEmpresaService";
import { empresaService } from "./empresaService";
const STORAGE_KEY = "docMockServices_personas";
/**
 * Simula un delay de red para hacer más realista el mock
 */
const simulateNetworkDelay = (ms = 500) => {
    return new Promise((resolve) => setTimeout(resolve, ms));
};
/**
 * Obtiene todas las personas del almacenamiento (función helper interna)
 * Convierte las fechas de string ISO a dayjs
 */
const _obtenerTodas = () => {
    const data = localStorage.getItem(STORAGE_KEY);
    if (!data)
        return [];
    const personas = JSON.parse(data);
    // Convertir fechaNacimiento de string ISO a dayjs
    return personas.map((persona) => ({
        ...persona,
        fechaNacimiento: dayjs(persona.fechaNacimiento),
    }));
};
/**
 * Enriquece una persona con sus empresas relacionadas
 * Optimizado para obtener todas las empresas de una vez
 */
const _enriquecerConEmpresas = async (persona, todasLasEmpresas) => {
    const relaciones = await personaEmpresaService.buscarPorPersona(persona.id);
    const empresasIds = relaciones.map((rel) => rel.idEmpresa);
    let empresas = [];
    if (todasLasEmpresas) {
        // Si ya tenemos todas las empresas, filtrar por IDs
        empresas = todasLasEmpresas.filter((emp) => empresasIds.includes(emp.id));
    }
    else {
        // Si no, obtener cada empresa individualmente
        for (const idEmpresa of empresasIds) {
            const empresa = await empresaService.buscarPorId(idEmpresa.toString());
            if (empresa) {
                empresas.push(empresa);
            }
        }
    }
    return {
        ...persona,
        empresas,
    };
};
/**
 * Servicio mock para gestionar Personas en localStorage
 */
export const personaService = {
    /**
     * Obtiene personas opcionalmente filtradas por nombre, con sus empresas relacionadas
     */
    async listar(params) {
        await simulateNetworkDelay();
        const todas = _obtenerTodas();
        let personasFiltradas = todas;
        if (params?.filtro) {
            const filtroLower = params.filtro.toLowerCase();
            personasFiltradas = todas.filter((per) => per.nombre.toLowerCase().includes(filtroLower));
        }
        // Obtener todas las empresas de una vez para optimizar
        const todasLasEmpresas = await empresaService.listar();
        // Enriquecer cada persona con sus empresas
        const personasConEmpresas = await Promise.all(personasFiltradas.map((p) => _enriquecerConEmpresas(p, todasLasEmpresas)));
        return personasConEmpresas;
    },
    /**
     * Obtiene personas paginadas opcionalmente filtradas por nombre y/o idEmpresa, con sus empresas relacionadas
     */
    async listarPaginados(params) {
        await simulateNetworkDelay();
        const pagina = params?.pagina ?? 1;
        const limit = params?.limit ?? 20;
        const todas = _obtenerTodas();
        let todasFiltradas = todas;
        // Filtro por nombre
        if (params?.filtro) {
            const filtroLower = params.filtro.toLowerCase();
            todasFiltradas = todasFiltradas.filter((per) => per.nombre.toLowerCase().includes(filtroLower));
        }
        // Filtro por idEmpresa: obtener todas las relaciones de esa empresa
        // y filtrar las personas que tienen esa relación
        if (params?.idEmpresa !== undefined) {
            const relaciones = await personaEmpresaService.buscarPorEmpresa(Number(params.idEmpresa));
            const personasIdsConEmpresa = new Set(relaciones.map((rel) => rel.idPersona.toString()));
            todasFiltradas = todasFiltradas.filter((per) => personasIdsConEmpresa.has(per.id.toString()));
        }
        const total = todasFiltradas.length;
        // Obtener todas las empresas de una vez para optimizar
        const todasLasEmpresas = await empresaService.listar();
        // Enriquecer cada persona con sus empresas antes de paginar
        const personasConEmpresas = await Promise.all(todasFiltradas.map((p) => _enriquecerConEmpresas(p, todasLasEmpresas)));
        const limitNumber = parseInt(limit.toString(), 10);
        const paginaNumber = parseInt(pagina.toString(), 10);
        const totalNumber = parseInt(total.toString(), 10);
        // Si limit es 0, devolver todos los elementos sin paginar
        if (limitNumber === 0) {
            return {
                list: personasConEmpresas,
                limit: 0,
                page: 1,
                pages: 1,
                total,
            };
        }
        const pages = Math.ceil(totalNumber / limitNumber);
        const inicio = (paginaNumber - 1) * limitNumber;
        const fin = inicio + limitNumber;
        const list = personasConEmpresas.slice(inicio, fin);
        return {
            list,
            limit: limitNumber,
            page: paginaNumber,
            pages,
            total,
        };
    },
    /**
     * Busca una persona por ID
     */
    async buscarPorId(id) {
        await simulateNetworkDelay();
        const personas = _obtenerTodas();
        return personas.find((per) => per.id === id);
    },
    /**
     * Agrega una nueva persona
     */
    async agregar(persona) {
        await simulateNetworkDelay();
        const personas = _obtenerTodas();
        const nuevoId = personas.length > 0 ? Math.max(...personas.map((p) => p.id)) + 1 : 1;
        // Crear nueva persona: el id generado siempre sobrescribe cualquier id que venga
        const nuevaPersona = {
            ...persona,
            id: nuevoId, // El id siempre se asigna después para sobrescribir cualquier id existente
        };
        personas.push(nuevaPersona);
        // Guardar convirtiendo fechaNacimiento a string ISO
        const personasParaGuardar = personas.map((p) => ({
            ...p,
            fechaNacimiento: p.fechaNacimiento.toISOString(),
        }));
        localStorage.setItem(STORAGE_KEY, JSON.stringify(personasParaGuardar));
        return nuevaPersona;
    },
    /**
     * Edita una persona existente
     */
    async editar(id, datos) {
        await simulateNetworkDelay();
        const personas = _obtenerTodas();
        const index = personas.findIndex((per) => per.id === id);
        if (index === -1)
            return undefined;
        personas[index] = { ...personas[index], ...datos };
        // Guardar convirtiendo fechaNacimiento a string ISO
        const personasParaGuardar = personas.map((p) => ({
            ...p,
            fechaNacimiento: p.fechaNacimiento.toISOString(),
        }));
        localStorage.setItem(STORAGE_KEY, JSON.stringify(personasParaGuardar));
        return personas[index];
    },
    /**
     * Elimina una persona por ID y todas sus relaciones con empresas
     */
    async eliminar(persona) {
        await simulateNetworkDelay();
        const personas = _obtenerTodas();
        const index = personas.findIndex((per) => per.id === persona.id);
        if (index === -1)
            return;
        // Eliminar todas las relaciones de esta persona
        await personaEmpresaService.eliminarPorPersona(persona.id);
        personas.splice(index, 1);
        // Guardar convirtiendo fechaNacimiento a string ISO
        const personasParaGuardar = personas.map((p) => ({
            ...p,
            fechaNacimiento: p.fechaNacimiento.toISOString(),
        }));
        localStorage.setItem(STORAGE_KEY, JSON.stringify(personasParaGuardar));
    },
};
