import { jsx as _jsx } from "react/jsx-runtime";
/** @vitest-environment jsdom */
import React from 'react';
import { afterEach, describe, expect, it } from 'vitest';
import { act, cleanup, render } from '@testing-library/react';
import { StorageAdapterProvider } from '../../contexts/StorageAdapterContext';
import { useLocalStorageState } from '../useLocalStorage';
const createMemoryAdapter = () => {
    const store = new Map();
    const subscribers = new Map();
    const notify = (key, value) => {
        const listeners = subscribers.get(key);
        if (!listeners) {
            return;
        }
        listeners.forEach((listener) => listener(value));
    };
    return {
        getItem: (key) => store.get(key) ?? null,
        setItem: (key, value) => {
            store.set(key, value);
            notify(key, value);
        },
        removeItem: (key) => {
            store.delete(key);
            notify(key, null);
        },
        subscribe: (key, callback) => {
            const set = subscribers.get(key) ?? new Set();
            set.add(callback);
            subscribers.set(key, set);
            return () => {
                const listeners = subscribers.get(key);
                if (!listeners) {
                    return;
                }
                listeners.delete(callback);
                if (listeners.size === 0) {
                    subscribers.delete(key);
                }
            };
        }
    };
};
afterEach(() => {
    cleanup();
});
function createTestComponent() {
    return React.forwardRef(({ storageKey, initialValue, adapter }, ref) => {
        const state = useLocalStorageState(storageKey, initialValue, adapter);
        React.useImperativeHandle(ref, () => state, [state]);
        return null;
    });
}
describe('useLocalStorageState with StorageAdapterProvider', () => {
    it('hydrates from adapter and persists updates', () => {
        const adapter = createMemoryAdapter();
        const storedValue = { enabled: true, label: 'pre-seeded' };
        adapter.setItem('custom-key', JSON.stringify(storedValue));
        const TestComponent = createTestComponent();
        const ref = React.createRef();
        render(_jsx(StorageAdapterProvider, { adapter: adapter, children: _jsx(TestComponent, { storageKey: 'custom-key', initialValue: { enabled: false, label: 'default' }, ref: ref }) }));
        const getHandle = () => {
            const handle = ref.current;
            if (!handle) {
                throw new Error('Hook handle was not initialized');
            }
            return handle;
        };
        expect(getHandle().value).toEqual(storedValue);
        const nextValue = { enabled: false, label: 'updated' };
        act(() => {
            getHandle().setValue(nextValue);
        });
        expect(JSON.parse(adapter.getItem('custom-key') ?? 'null')).toEqual(nextValue);
        expect(getHandle().value).toEqual(nextValue);
        act(() => {
            getHandle().removeValue();
        });
        expect(adapter.getItem('custom-key')).toBeNull();
        expect(getHandle().value).toEqual({ enabled: false, label: 'default' });
    });
    it('reacts to external adapter changes via subscription', () => {
        const adapter = createMemoryAdapter();
        const TestComponent = createTestComponent();
        const ref = React.createRef();
        render(_jsx(StorageAdapterProvider, { adapter: adapter, children: _jsx(TestComponent, { storageKey: 'watch-key', initialValue: 'initial', ref: ref }) }));
        const getHandle = () => {
            const handle = ref.current;
            if (!handle) {
                throw new Error('Hook handle was not initialized');
            }
            return handle;
        };
        expect(getHandle().value).toBe('initial');
        act(() => {
            adapter.setItem('watch-key', JSON.stringify('external-update'));
        });
        expect(getHandle().value).toBe('external-update');
        act(() => {
            adapter.removeItem('watch-key');
        });
        expect(getHandle().value).toBe('initial');
    });
});
