import {Presence} from "@mescius/js-collaboration-presence-client";

export interface IUser {
    id: string;
    color: string;
    name: string;
}
export interface IPresence {
    point: { x: number, y: number };
    user: IUser;
}
interface IDom extends HTMLElement {
    _mouseoverHandler: () => void;
    _mouseoutHandler: () => void;
}

const removeFun = {};

export function bindPresence(presence: Presence<IPresence>, user: IUser, userHostId: string, hostId: string) {
    const DEFAULT_COLOR_SCHEME = ['#0000ff', '#008000', '#9900cc', '#800000', '#00cc33', '#cc6600', '#cc0099'];
    const colorScheme = DEFAULT_COLOR_SCHEME;
    const div = document.getElementById(hostId) as HTMLDivElement;
    if (!user.color) {
        user.color = getUnusedColorFromCurrentPresences(colorScheme, presence) || colorScheme[Math.floor(Math.random() * DEFAULT_COLOR_SCHEME.length)];
    }
    const updatePresences = () => {
        const presences: IPresence[] = Object.values(presence.otherStates);
        onPresencesUpdate(presences, userHostId);
        const ps = [];
        for (const id in presence.otherStates) {
            const item = presence.otherStates[id];
            ps.push({ x: item.point.x, y: item.point.y, color: item.user.color });
        }
        drawCursor(document.getElementById(hostId) as HTMLDivElement, ps);
    };

    presence.subscribe().then(() => {
        updatePresences();
    });
    presence.on('add', updatePresences);
    presence.on('update', updatePresences);
    presence.on('remove', updatePresences);
    presence.submitLocalState({ point: { x: -1, y: -1 }, user });

    const submitLocalPresence = (e: PointerEvent) => {
        let x = -1, y = -1;
        if (e.type === 'pointermove') {
            x = e.offsetX;
            y = e.offsetY;
        }
        presence.submitLocalState({ point: { x, y }, user });
    };

    div.addEventListener('pointermove', submitLocalPresence);
    div.addEventListener('pointerleave', submitLocalPresence);

    const removeFunctions = removeFun[hostId] || [];
    removeFunctions.push(() => {
        div.removeEventListener('pointermove', submitLocalPresence);
        div.removeEventListener('pointerleave', submitLocalPresence);
    });
    removeFun[hostId] = removeFunctions;
}

function onPresencesUpdate(presences: IPresence[], userHostId: string) {
    const presenceDiv = document.getElementById(userHostId);
    // Clear the current content
    clearUserPresence(userHostId);

    // Iterate over presences and create a circle for each user
    presences.forEach(presence => {
        const user = presence.user;
        const circle = document.createElement('div') as unknown as IDom;
        circle.className = 'presence-item';
        circle.style.backgroundColor = user.color || '#007bff';
        circle.textContent = user.name.charAt(0).toUpperCase();

        // Define event handlers
        const mouseoverHandler = () => {
            circle.style.width = '97px';
            circle.style.padding = "0px 5px";
            circle.textContent = user.name.charAt(0).toUpperCase() + user.name.slice(1);
        };

        const mouseoutHandler = () => {
            circle.style.width = '24px';
            circle.style.padding = "0px";
            circle.textContent = user.name.charAt(0).toUpperCase();
        };

        // Store references to the handlers
        circle._mouseoverHandler = mouseoverHandler;
        circle._mouseoutHandler = mouseoutHandler;

        // Add event listeners
        circle.addEventListener('mouseover', mouseoverHandler);
        circle.addEventListener('mouseout', mouseoutHandler);

        presenceDiv.appendChild(circle);
    });
}

function getUnusedColorFromCurrentPresences(colors: string[], presence: Presence<IPresence>) {
    const usedColors = Object.values(presence.otherStates).map(presence => presence?.user?.color);
    return colors.find(color => !usedColors.includes(color));
}
function drawCursor(container: HTMLDivElement, datas: { x: number, y: number, color: string }[]) {
    const oldCursors = container.querySelectorAll('.custom-cursor');
    oldCursors.forEach(cursor => cursor.remove());

    datas.filter(item => item.x > 0 && item.y > 0).forEach(data => {
        const cursor = document.createElement('div');

        cursor.style.position = 'absolute';
        cursor.style.left = `${data.x}px`;
        cursor.style.top = `${data.y}px`;
        cursor.style.borderRadius = '50%';
        cursor.style.backgroundColor = data.color;
        cursor.style.width = '20px';
        cursor.style.height = '20px';
        cursor.style.pointerEvents = 'none';
        cursor.style.zIndex = '999';

        cursor.className = 'custom-cursor';

        container.appendChild(cursor);
    });
}

export function clearUserPresence (userHostId: string) {
    const presenceDiv = document.getElementById(userHostId);
    // Clear the current content
    while (presenceDiv.firstChild) {
        const child = presenceDiv.firstChild as IDom;
        child.removeEventListener('mouseover', child._mouseoverHandler);
        child.removeEventListener('mouseout', child._mouseoutHandler);
        presenceDiv.removeChild(child);
    }
    removeFun[userHostId]?.forEach(fun => fun());
    removeFun[userHostId] = [];
}
