import React, { createContext, useContext, useCallback, useRef, useState } from 'react'

interface NavigationGuard {
    hasUnsavedChanges: () => boolean
    onSave?: () => Promise<void>
    onDiscard?: () => void
}

interface NavigationGuardContextValue {
    registerGuard: (guard: NavigationGuard) => void
    unregisterGuard: () => void
    isBlocked: () => boolean
    checkGuard: (callback: () => void) => void
    proceedNavigation: () => void
    cancelNavigation: () => void
    saveAndProceed: () => Promise<void>
    discardAndProceed: () => void
    saveAlwaysAndProceed: () => void
    /** True while an intentional navigation is in progress (suppresses re-entrant guards) */
    isNavigatingRef: React.RefObject<boolean>
    isModalOpen: boolean
    saveError: string | null
}

const NavigationGuardContext = createContext<NavigationGuardContextValue | null>(null)

export function useNavigationGuard() {
    const ctx = useContext(NavigationGuardContext)
    if (!ctx) throw new Error('useNavigationGuard must be used within NavigationGuardProvider')
    return ctx
}

/** Same as useNavigationGuard but returns null when outside the provider (safe for optional usage) */
export function useOptionalNavigationGuard() {
    return useContext(NavigationGuardContext)
}

const AUTO_SAVE_KEY = 'boostbot_auto_save_on_navigate'
const getAutoSave = () => localStorage.getItem(AUTO_SAVE_KEY) === 'true'
const setAutoSave = (value: boolean) => localStorage.setItem(AUTO_SAVE_KEY, String(value))

export function NavigationGuardProvider({ children }: { children: React.ReactNode }) {
    const guardRef = useRef<NavigationGuard | null>(null)
    const pendingCallbackRef = useRef<(() => void) | null>(null)
    const isNavigatingRef = useRef(false)
    const [isModalOpen, setIsModalOpen] = useState(false)
    const [saveError, setSaveError] = useState<string | null>(null)

    const registerGuard = useCallback((guard: NavigationGuard) => {
        guardRef.current = guard
    }, [])

    const unregisterGuard = useCallback(() => {
        guardRef.current = null
        pendingCallbackRef.current = null
        setIsModalOpen(false)
        setSaveError(null)
    }, [])

    const isBlocked = useCallback(() => {
        return guardRef.current?.hasUnsavedChanges() ?? false
    }, [])

    const checkGuard = useCallback((callback: () => void) => {
        if (!guardRef.current || !guardRef.current.hasUnsavedChanges()) {
            callback()
            return
        }

        if (getAutoSave() && guardRef.current.onSave) {
            const saveFn = guardRef.current.onSave
            pendingCallbackRef.current = callback
            saveFn()
                .then(() => {
                    setIsModalOpen(false)
                    setSaveError(null)
                    const cb = pendingCallbackRef.current
                    pendingCallbackRef.current = null
                    isNavigatingRef.current = true
                    cb?.()
                    setTimeout(() => { isNavigatingRef.current = false }, 0)
                })
                .catch(() => {
                    setSaveError(null)
                    setIsModalOpen(true)
                })
            return
        }

        pendingCallbackRef.current = callback
        setSaveError(null)
        setIsModalOpen(true)
    }, [])

    const proceedNavigation = useCallback(() => {
        setIsModalOpen(false)
        setSaveError(null)
        const cb = pendingCallbackRef.current
        pendingCallbackRef.current = null
        isNavigatingRef.current = true
        cb?.()
        setTimeout(() => { isNavigatingRef.current = false }, 0)
    }, [])

    const cancelNavigation = useCallback(() => {
        setIsModalOpen(false)
        setSaveError(null)
        pendingCallbackRef.current = null
    }, [])

    const saveAndProceed = useCallback(async () => {
        if (guardRef.current?.onSave) {
            try {
                setSaveError(null)
                await guardRef.current.onSave()
                proceedNavigation()
            } catch (err: unknown) {
                const msg = (err as { message?: string })?.message || 'Save failed'
                setSaveError(msg)
            }
        }
    }, [proceedNavigation])

    const discardAndProceed = useCallback(() => {
        guardRef.current?.onDiscard?.()
        proceedNavigation()
    }, [proceedNavigation])

    const saveAlwaysAndProceed = useCallback(() => {
        setAutoSave(true)
        if (guardRef.current?.onSave) {
            setSaveError(null)
            guardRef.current.onSave()
                .then(() => proceedNavigation())
                .catch((err: unknown) => {
                    const msg = (err as { message?: string })?.message || 'Save failed'
                    setSaveError(msg)
                })
        }
    }, [proceedNavigation])

    return (
        <NavigationGuardContext.Provider value={{
            registerGuard,
            unregisterGuard,
            isBlocked,
            checkGuard,
            proceedNavigation,
            cancelNavigation,
            saveAndProceed,
            discardAndProceed,
            saveAlwaysAndProceed,
            isNavigatingRef,
            isModalOpen,
            saveError,
        }}>
            {children}
        </NavigationGuardContext.Provider>
    )
}
