// @vitest-environment jsdom
/**
 * Hook test for useUnsavedGuard + the module-level registry. Verifies dirty
 * registration/unregistration, confirmDiscardUnsaved short-circuit + confirm
 * gate, and that a beforeunload listener is armed only while dirty.
 */
import '../test/dom-setup';
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { renderHook } from '@testing-library/react';
import { useUnsavedGuard, hasUnsavedChanges, confirmDiscardUnsaved } from './unsavedGuard';

vi.mock('../i18n', () => ({
  default: { t: () => '破棄しますか？' },
}));

afterEach(() => vi.restoreAllMocks());

describe('useUnsavedGuard registry', () => {
  beforeEach(() => {
    // sanity: no leftover dirty checkers from a previous test
    expect(hasUnsavedChanges()).toBe(false);
  });

  it('reports clean when no view is dirty', () => {
    renderHook(() => useUnsavedGuard(false));
    expect(hasUnsavedChanges()).toBe(false);
  });

  it('reports dirty while a registered view is dirty', () => {
    renderHook(() => useUnsavedGuard(true));
    expect(hasUnsavedChanges()).toBe(true);
  });

  it('unregisters its checker on unmount', () => {
    const { unmount } = renderHook(() => useUnsavedGuard(true));
    expect(hasUnsavedChanges()).toBe(true);
    unmount();
    expect(hasUnsavedChanges()).toBe(false);
  });

  it('arms a beforeunload listener only while dirty', () => {
    const add = vi.spyOn(window, 'addEventListener');
    const remove = vi.spyOn(window, 'removeEventListener');
    const { rerender, unmount } = renderHook(({ d }) => useUnsavedGuard(d), {
      initialProps: { d: false },
    });
    expect(add.mock.calls.some(([t]) => t === 'beforeunload')).toBe(false);
    rerender({ d: true });
    expect(add.mock.calls.some(([t]) => t === 'beforeunload')).toBe(true);
    rerender({ d: false });
    expect(remove.mock.calls.some(([t]) => t === 'beforeunload')).toBe(true);
    unmount();
  });
});

describe('confirmDiscardUnsaved', () => {
  it('returns true without prompting when nothing is dirty', () => {
    const confirmSpy = vi.spyOn(window, 'confirm');
    expect(confirmDiscardUnsaved()).toBe(true);
    expect(confirmSpy).not.toHaveBeenCalled();
  });

  it('prompts when dirty and returns the user choice', () => {
    renderHook(() => useUnsavedGuard(true));
    const confirmSpy = vi.spyOn(window, 'confirm').mockReturnValue(false);
    expect(confirmDiscardUnsaved()).toBe(false);
    confirmSpy.mockReturnValue(true);
    expect(confirmDiscardUnsaved()).toBe(true);
  });
});
