import { act } from 'react';
import { createRoot } from 'react-dom/client';
import { MemoryRouter, Route, Routes, useNavigate } from 'react-router';
import { afterEach, describe, expect, it } from 'vitest';
import { RouteKeeper } from './RouteKeeper';

let container: HTMLDivElement | null = null;
let root: ReturnType<typeof createRoot> | null = null;

afterEach(async () => {
  if (root) await act(async () => root?.unmount());
  container?.remove();
  root = null;
  container = null;
});

function PageA() {
  const navigate = useNavigate();
  return (
    <div>
      <input data-testid="input-a" aria-label="A 输入" />
      <button data-testid="go-b" onClick={() => navigate('/b')}>
        去B
      </button>
    </div>
  );
}

function PageB() {
  const navigate = useNavigate();
  return (
    <div>
      <input data-testid="input-b" aria-label="B 输入" />
      <button data-testid="go-a" onClick={() => navigate('/')}>
        去A
      </button>
    </div>
  );
}

function Harness() {
  return (
    <MemoryRouter initialEntries={['/']}>
      <Routes>
        <Route path="/" element={<RouteKeeper />}>
          <Route index element={<PageA />} />
          <Route path="b" element={<PageB />} />
        </Route>
      </Routes>
    </MemoryRouter>
  );
}

function type(target: HTMLInputElement, value: string) {
  const setter = Object.getOwnPropertyDescriptor(
    window.HTMLInputElement.prototype,
    'value',
  )?.set;
  setter?.call(target, value);
  target.dispatchEvent(new Event('input', { bubbles: true }));
}

describe('RouteKeeper', () => {
  it('keeps page instances and input values alive across navigation', async () => {
    container = document.createElement('div');
    document.body.appendChild(container);
    root = createRoot(container);
    await act(async () => root?.render(<Harness />));

    const inputA = document.querySelector('[data-testid="input-a"]') as HTMLInputElement;
    expect(inputA).not.toBeNull();
    await act(async () => type(inputA, '待保存的学生姓名'));

    await act(async () => {
      (document.querySelector('[data-testid="go-b"]') as HTMLButtonElement).click();
    });
    const inputB = document.querySelector('[data-testid="input-b"]') as HTMLInputElement;
    expect(inputB).not.toBeNull();
    await act(async () => type(inputB, '待保存的宿舍号'));

    await act(async () => {
      (document.querySelector('[data-testid="go-a"]') as HTMLButtonElement).click();
    });

    const keptA = document.querySelector('[data-testid="input-a"]') as HTMLInputElement;
    expect(keptA).not.toBeNull();
    expect(keptA.value).toBe('待保存的学生姓名');
    const keptB = document.querySelector('[data-testid="input-b"]') as HTMLInputElement;
    expect(keptB.value).toBe('待保存的宿舍号');

    const pages = document.querySelectorAll('.route-keeper-page');
    expect(pages.length).toBe(2);
    const hidden = pages[1] as HTMLElement;
    expect(hidden.style.display).toBe('none');
  });
});
