import type { GlobalEvent } from '@inertiajs/core';
import { router } from '@inertiajs/vue3';
import { onBeforeUnmount, onMounted, ref } from 'vue';

/**
 * Garde « modifications non enregistrées » des pages de réglages.
 *
 * - Bloque une navigation Inertia (GET) et la fermeture de l’onglet tant
 *   que `isDirty()` est vrai, et propose Quitter / Rester via
 *   `UnsavedChangesDialog` (monté dans le layout).
 * - ⌘S / Ctrl+S déclenche `save()`.
 */
type PendingVisit = { url: string };

export const unsavedChangesState = {
    open: ref(false),
    pending: ref<PendingVisit | null>(null),
    bypass: false,
};

export function leavePendingVisit(): void {
    const pending = unsavedChangesState.pending.value;

    unsavedChangesState.open.value = false;
    unsavedChangesState.pending.value = null;

    if (!pending) {
        return;
    }

    unsavedChangesState.bypass = true;
    router.visit(pending.url);
}

export function stayOnPage(): void {
    unsavedChangesState.open.value = false;
    unsavedChangesState.pending.value = null;
}

export function useUnsavedChanges(
    isDirty: () => boolean,
    options: { save?: () => void } = {},
): void {
    const onBefore = (event: GlobalEvent<'before'>): void => {
        const visit = event.detail.visit;

        if (visit.method !== 'get' || !isDirty()) {
            return;
        }

        if (unsavedChangesState.bypass) {
            unsavedChangesState.bypass = false;

            return;
        }

        event.preventDefault();
        unsavedChangesState.pending.value = { url: visit.url.toString() };
        unsavedChangesState.open.value = true;
    };

    const onBeforeUnload = (event: BeforeUnloadEvent): void => {
        if (isDirty()) {
            event.preventDefault();
        }
    };

    const onKeydown = (event: KeyboardEvent): void => {
        if (
            options.save &&
            (event.metaKey || event.ctrlKey) &&
            !event.altKey &&
            event.key.toLowerCase() === 's'
        ) {
            event.preventDefault();

            if (isDirty()) {
                options.save();
            }
        }
    };

    let removeBefore: (() => void) | null = null;

    onMounted(() => {
        removeBefore = router.on('before', onBefore);
        window.addEventListener('beforeunload', onBeforeUnload);
        window.addEventListener('keydown', onKeydown);
    });

    onBeforeUnmount(() => {
        removeBefore?.();
        window.removeEventListener('beforeunload', onBeforeUnload);
        window.removeEventListener('keydown', onKeydown);
        stayOnPage();
    });
}
