// @vitest-environment jsdom
/**
 * Hook test for useLocalStorageState — restore-on-mount, synchronous write,
 * functional updater, corrupt-JSON fallback, and swallowed write errors.
 */
import '../test/dom-setup';
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { renderHook, act } from '@testing-library/react';
import { useLocalStorageState } from './useLocalStorageState';

beforeEach(() => {
  window.localStorage.clear();
  vi.restoreAllMocks();
});

describe('useLocalStorageState', () => {
  it('uses defaultValue when nothing stored', () => {
    const { result } = renderHook(() => useLocalStorageState('k1', { n: 1 }));
    expect(result.current[0]).toEqual({ n: 1 });
  });

  it('restores the stored value on mount', () => {
    window.localStorage.setItem('k2', JSON.stringify(['a', 'b']));
    const { result } = renderHook(() => useLocalStorageState<string[]>('k2', []));
    expect(result.current[0]).toEqual(['a', 'b']);
  });

  it('writes through to localStorage on set', () => {
    const { result } = renderHook(() => useLocalStorageState('k3', 0));
    act(() => result.current[1](42));
    expect(result.current[0]).toBe(42);
    expect(window.localStorage.getItem('k3')).toBe('42');
  });

  it('supports a functional updater', () => {
    const { result } = renderHook(() => useLocalStorageState('k4', 10));
    act(() => result.current[1]((prev) => prev + 5));
    expect(result.current[0]).toBe(15);
    expect(window.localStorage.getItem('k4')).toBe('15');
  });

  it('falls back to defaultValue when stored JSON is corrupt', () => {
    window.localStorage.setItem('k5', '{not valid json');
    const { result } = renderHook(() => useLocalStorageState('k5', 'fallback'));
    expect(result.current[0]).toBe('fallback');
  });

  it('swallows write errors (e.g. quota) but still updates state', () => {
    const spy = vi
      .spyOn(Storage.prototype, 'setItem')
      .mockImplementation(() => {
        throw new DOMException('quota', 'QuotaExceededError');
      });
    const { result } = renderHook(() => useLocalStorageState('k6', 'x'));
    expect(() => act(() => result.current[1]('y'))).not.toThrow();
    expect(result.current[0]).toBe('y');
    spy.mockRestore();
  });
});
