import { act } from 'react';
import { createRoot } from 'react-dom/client';
import { afterEach, describe, expect, it } from 'vitest';
import { useSubmissionState, useXCardSurface } from './useSubmissionState';

// 项目未安装 @testing-library/react，用 createRoot + harness 组件暴露 hook API
let container: HTMLDivElement | null = null;
let root: ReturnType<typeof createRoot> | null = null;
let api: ReturnType<typeof useSubmissionState> | null = null;
let surface: ReturnType<typeof useXCardSurface> | null = null;
let surfaceId = 'surface-test';

function Harness() {
  api = useSubmissionState();
  surface = useXCardSurface(surfaceId);
  return null;
}

function renderHarness(): void {
  container = document.createElement('div');
  document.body.appendChild(container);
  root = createRoot(container);
  act(() => {
    root?.render(<Harness />);
  });
}

afterEach(async () => {
  if (root) await act(async () => root?.unmount());
  container?.remove();
  root = null;
  container = null;
  api = null;
  surface = null;
  surfaceId = 'surface-test';
});

describe('useSubmissionState', () => {
  it('tracks submitting during the task and succeeds afterwards', async () => {
    renderHarness();
    let resolveTask: () => void = () => undefined;
    const task = () =>
      new Promise<void>((resolve) => {
        resolveTask = resolve;
      });

    let promise: Promise<void> | undefined;
    act(() => {
      promise = api?.run(task);
    });
    expect(api?.submitting).toBe(true);
    expect(api?.error).toBeNull();

    await act(async () => {
      resolveTask();
      await promise;
    });
    expect(api?.submitting).toBe(false);
    expect(api?.submitted).toBe(true);
    expect(api?.error).toBeNull();
  });

  it('captures the error message and keeps submitted false on failure', async () => {
    renderHarness();
    const failing = () => {
      throw new Error('接口 500');
    };

    await act(async () => {
      await api?.run(failing);
    });
    expect(api?.submitting).toBe(false);
    expect(api?.submitted).toBe(false);
    expect(api?.error).toBe('接口 500');
  });

  it('normalizes non-Error rejections to a generic message', async () => {
    renderHarness();
    const failing = () => Promise.reject('raw string');

    await act(async () => {
      await api?.run(failing);
    });
    expect(api?.error).toBe('提交失败，请稍后重试');
  });

  it('ignores re-entrant calls while a task is in flight', async () => {
    renderHarness();
    let resolveTask: () => void = () => undefined;
    const task = () =>
      new Promise<void>((resolve) => {
        resolveTask = resolve;
      });
    let secondRan = false;

    act(() => {
      void api?.run(task);
      void api?.run(() => {
        secondRan = true;
      });
    });
    expect(secondRan).toBe(false);

    await act(async () => {
      resolveTask();
    });
    expect(api?.submitted).toBe(true);
  });

  it('reset clears submitted and error states', async () => {
    renderHarness();
    await act(async () => {
      await api?.run(() => undefined);
    });
    expect(api?.submitted).toBe(true);

    act(() => {
      api?.reset();
    });
    expect(api?.submitted).toBe(false);
    expect(api?.error).toBeNull();
  });
});

describe('useXCardSurface', () => {
  it('deduplicates createSurface commands for the same surface id', () => {
    renderHarness();
    act(() => {
      surface?.pushCommands([
        { version: 'v0.9', createSurface: { surfaceId: 'surface-test', catalogId: 'catalog' } },
        { version: 'v0.9', updateDataModel: { surfaceId: 'surface-test', path: '/x', value: 1 } },
      ]);
      surface?.pushCommands([
        { version: 'v0.9', createSurface: { surfaceId: 'surface-test', catalogId: 'catalog' } },
        { version: 'v0.9', updateDataModel: { surfaceId: 'surface-test', path: '/x', value: 2 } },
      ]);
    });
    const createCommands = surface?.commands.filter((command) => 'createSurface' in command);
    expect(createCommands).toHaveLength(1);
    expect(surface?.commands).toHaveLength(3);
  });

  it('resets the command stream when the surface id changes', () => {
    renderHarness();
    act(() => {
      surface?.pushCommands([
        { version: 'v0.9', createSurface: { surfaceId: 'surface-test', catalogId: 'c' } },
      ]);
    });
    expect(surface?.commands).toHaveLength(1);

    surfaceId = 'surface-other';
    act(() => {
      root?.render(<Harness />);
      surface?.pushCommands([
        { version: 'v0.9', createSurface: { surfaceId: 'surface-other', catalogId: 'c' } },
      ]);
    });
    expect(surface?.commands).toHaveLength(1);
  });
});
