import { describe, test, expect } from 'vitest';
import React from 'react';
import { renderEditorHarness } from '../../test-utils/editorHarness';
import { PageProvider, usePages } from '../../state/PageContext';
import { PagesPanel } from './PagesPanel';

function clickByLabel(container: HTMLElement, label: string): HTMLButtonElement {
  const btn = container.querySelector(`[aria-label="${label}"]`) as HTMLButtonElement | null;
  if (!btn) throw new Error(`No button found with aria-label "${label}"`);
  return btn;
}

function clickByText(container: HTMLElement, text: string): HTMLButtonElement {
  const btn = Array.from(container.querySelectorAll('button')).find(
    (b) => b.textContent === text,
  ) as HTMLButtonElement | undefined;
  if (!btn) throw new Error(`No button found with text "${text}"`);
  return btn;
}

/**
 * I3 (review): `deleteConfirmId`, `resetConfirmId` and `editingId` are three
 * independent bits of local state, but the row rendering treats them as
 * mutually exclusive (edit -> delete -> reset -> normal, first match wins).
 * Before this fix, none of the three setters cleared the other two, so if
 * both `resetConfirmId` and `deleteConfirmId` were ever set to the same page
 * id, the delete-confirm view would win (it's checked first) and cancelling
 * it would fall through to reveal the reset-confirm view "unbidden" -- a
 * destructive prompt the user never asked for.
 *
 * This is reachable any time two arm-clicks land in the same render pass
 * (e.g. a fast double click / synthetic dual dispatch before React commits
 * the first click's re-render) -- reproduced below by issuing both clicks
 * inside a single `act()` batch, which is exactly what removes the re-render
 * that would otherwise make the second button disappear before it can be
 * clicked.
 */
describe('PagesPanel confirmation-state isolation (I3 review finding)', () => {
  async function setupTwoPages() {
    let ctx: ReturnType<typeof usePages> | null = null;
    const Probe: React.FC = () => { ctx = usePages(); return null; };
    const harness = renderEditorHarness();
    harness.mountChild(
      <PageProvider>
        <Probe />
        <PagesPanel />
      </PageProvider>,
    );
    harness.act(() => { ctx!.addPage('About', 'about'); });
    await harness.act(async () => { await new Promise((resolve) => setTimeout(resolve, 10)); });
    return harness;
  }

  test('arming Reset then Delete for the same page in one batch shows Delete (render precedence), and cancelling Delete does NOT reveal a leftover Reset prompt', async () => {
    const harness = await setupTwoPages();

    // Both arm-clicks land before any re-render commits.
    harness.act(() => {
      clickByLabel(harness.container, 'Reset About to blank').click();
      clickByLabel(harness.container, 'Delete About').click();
    });
    expect(harness.container.textContent).toContain('Delete "About"?');
    expect(harness.container.textContent).not.toContain('Clear every element from "About"?');

    harness.act(() => {
      clickByText(harness.container, 'Cancel').click();
    });

    // The fix: arming Delete clears any pending Reset confirmation for the
    // same page, so cancelling Delete returns to the normal row, not a
    // surprise Reset prompt.
    expect(harness.container.textContent).not.toContain('Clear every element from "About"?');
    expect(harness.container.textContent).not.toContain('Delete "About"?');

    harness.unmount();
  });

  test('arming Delete then Reset for the same page in one batch shows Reset, and cancelling Reset does NOT reveal a leftover Delete prompt', async () => {
    const harness = await setupTwoPages();

    harness.act(() => {
      clickByLabel(harness.container, 'Delete About').click();
      clickByLabel(harness.container, 'Reset About to blank').click();
    });
    expect(harness.container.textContent).toContain('Clear every element from "About"?');

    harness.act(() => {
      clickByText(harness.container, 'Cancel').click();
    });

    expect(harness.container.textContent).not.toContain('Delete "About"?');
    expect(harness.container.textContent).not.toContain('Clear every element from "About"?');

    harness.unmount();
  });

  test('starting a Rename while a Reset confirmation is pending for the same page clears the pending Reset', async () => {
    const harness = await setupTwoPages();

    // Arm Reset, then (same batch) start editing the same row -- edit wins
    // in render precedence, but the fix also clears resetConfirmId so
    // cancelling the rename doesn't fall through to a stale Reset prompt.
    harness.act(() => {
      clickByLabel(harness.container, 'Reset About to blank').click();
      clickByLabel(harness.container, 'Rename About').click();
    });
    const nameInput = harness.container.querySelector('input.control-input') as HTMLInputElement | null;
    expect(nameInput).toBeTruthy();
    expect(nameInput!.value).toBe('About');

    harness.act(() => {
      clickByText(harness.container, 'Cancel').click();
    });

    expect(harness.container.textContent).not.toContain('Clear every element from "About"?');

    harness.unmount();
  });
});
