import { useContext, useEffect, useRef } from 'react';
import { useFormState, Control } from 'react-hook-form';
import { UNSAFE_NavigationContext, useLocation } from 'react-router-dom';
import { History, Transition } from 'history';
import { useTranslate } from '../i18n';

/**
 * Display a confirmation dialog if the form has unsaved changes.
 * - If the user confirms, the navigation continues and the changes are lost.
 * - If the user cancels, the navigation is cancelled and the changes are kept.
 */
export const useWarnWhenUnsavedChanges = (
    enable: boolean,
    formRootPathname?: string,
    control?: Control
) => {
    // react-router v6 does not yet provide a way to block navigation
    // This is planned for a future release
    // See https://github.com/remix-run/react-router/issues/8139
    const navigator = useContext(UNSAFE_NavigationContext).navigator as History;
    const location = useLocation();
    const translate = useTranslate();
    const { isSubmitSuccessful, isSubmitting, dirtyFields } = useFormState(
        control ? { control } : undefined
    );
    const isDirty = Object.keys(dirtyFields).length > 0;
    const initialLocation = useRef(formRootPathname || location.pathname);

    useEffect(() => {
        if (!enable || !isDirty) return;
        if (!navigator.block) {
            if (process.env.NODE_ENV !== 'production') {
                console.warn(
                    'warnWhenUnsavedChanged is not compatible with react-router >= 6.4. If you need this feature, please downgrade react-router to 6.3.0'
                );
            }
            return;
        }

        let unblock = navigator.block((tx: Transition) => {
            const newLocationIsInsideCurrentLocation = tx.location.pathname.startsWith(
                initialLocation.current
            );
            const newLocationIsShowView = tx.location.pathname.startsWith(
                `${initialLocation.current}/show`
            );
            const newLocationIsInsideForm =
                newLocationIsInsideCurrentLocation && !newLocationIsShowView;

            if (
                !isSubmitting &&
                (newLocationIsInsideForm ||
                    isSubmitSuccessful ||
                    window.confirm(translate('ra.message.unsaved_changes')))
            ) {
                unblock();
                tx.retry();
            }
        });

        return unblock;
    }, [
        enable,
        location,
        navigator,
        isDirty,
        isSubmitting,
        isSubmitSuccessful,
        translate,
    ]);
};
