import { useState, useEffect, useCallback, useMemo, useRef } from 'react';
import { browserStorageAdapter } from '../lib/storageAdapter';
import { useStorageAdapter } from '../contexts/StorageAdapterContext';
/**
 * A typesafe generic hook for using browser's localStorage with JSON objects.
 *
 * @template T The type of the value to store/retrieve
 * @param key The localStorage key
 * @param initialValue The initial value if nothing is stored
 * @returns [value, setValue, removeValue] tuple
 */
export function useLocalStorage(key, initialValue, adapter) {
    const inheritedAdapter = useStorageAdapter();
    const storage = useMemo(() => adapter ?? inheritedAdapter ?? browserStorageAdapter, [adapter, inheritedAdapter]);
    const initialValueRef = useRef(initialValue);
    useEffect(() => {
        initialValueRef.current = initialValue;
    }, [initialValue]);
    // State to store our value
    const [storedValue, setStoredValue] = useState(() => {
        try {
            const item = storage.getItem(key);
            if (item === null) {
                return initialValue;
            }
            return JSON.parse(item);
        }
        catch (error) {
            console.error(`Error reading storage key "${key}":`, error);
            return initialValue;
        }
    });
    useEffect(() => {
        try {
            const item = storage.getItem(key);
            if (item === null) {
                setStoredValue(initialValueRef.current);
                return;
            }
            const parsed = JSON.parse(item);
            setStoredValue(parsed);
        }
        catch (error) {
            console.error(`Error refreshing storage key "${key}":`, error);
            setStoredValue(initialValueRef.current);
        }
    }, [key, storage]);
    // Return a wrapped version of useState's setter function that persists the new value to localStorage
    const setValue = useCallback((value) => {
        setStoredValue((prevStoredValue) => {
            try {
                const valueToStore = value instanceof Function ? value(prevStoredValue) : value;
                storage.setItem(key, JSON.stringify(valueToStore));
                return valueToStore;
            }
            catch (error) {
                console.error(`Error setting storage key "${key}":`, error);
                return prevStoredValue;
            }
        });
    }, [key, storage]);
    // Function to remove the value from localStorage
    const removeValue = useCallback(() => {
        try {
            setStoredValue(initialValueRef.current);
            storage.removeItem(key);
        }
        catch (error) {
            console.error(`Error removing storage key "${key}":`, error);
        }
    }, [key, storage]);
    // Listen for changes in localStorage from other tabs/windows or adapter notifications
    useEffect(() => {
        if (typeof storage.subscribe !== 'function') {
            return undefined;
        }
        let unsubscribe;
        try {
            unsubscribe = storage.subscribe(key, (value) => {
                if (value === null) {
                    setStoredValue(initialValueRef.current);
                    return;
                }
                try {
                    const parsed = JSON.parse(value);
                    setStoredValue(parsed);
                }
                catch (error) {
                    console.error(`Error parsing storage value for key "${key}":`, error);
                }
            });
        }
        catch (error) {
            console.error(`Error subscribing to storage key "${key}":`, error);
        }
        return () => {
            if (typeof unsubscribe === 'function') {
                try {
                    unsubscribe();
                }
                catch (error) {
                    console.error(`Error unsubscribing from storage key "${key}":`, error);
                }
            }
        };
    }, [key, storage]);
    return [storedValue, setValue, removeValue];
}
// Alternative hook that returns an object interface (similar to useState but with additional methods)
export function useLocalStorageState(key, initialValue, adapter) {
    const [value, setValue, removeValue] = useLocalStorage(key, initialValue, adapter);
    return {
        value,
        setValue,
        removeValue,
        // Additional utility methods
        reset: () => setValue(initialValue),
        update: (updater) => setValue(updater)
    };
}
export default useLocalStorage;
