/* @vitest-environment jsdom */

import { fireEvent, render, screen, waitFor } from '@testing-library/react';
import { beforeEach, expect, test, vi } from 'vitest';

import type {
  DropSquareHoleShapeRequest,
  SquareHoleRunSnapshot,
} from '../../../packages/shared/src/contracts/squareHoleRuntime';
import { SquareHoleRuntimeShell } from './SquareHoleRuntimeShell';

function buildRun(): SquareHoleRunSnapshot {
  return {
    runId: 'run-1',
    profileId: 'profile-1',
    ownerUserId: 'user-1',
    status: 'running',
    snapshotVersion: 3,
    startedAtMs: Date.now(),
    durationLimitMs: 60_000,
    remainingMs: 60_000,
    totalShapeCount: 8,
    completedShapeCount: 0,
    combo: 0,
    bestCombo: 0,
    score: 0,
    ruleLabel: '把当前选项投入指定洞口',
    backgroundImageSrc: null,
    currentShape: {
      shapeId: 'shape-1',
      shapeKind: 'square',
      label: '当前选项',
      targetHoleId: 'hole-b',
      color: '#38bdf8',
      imageSrc: null,
    },
    holes: [
      {
        holeId: 'hole-a',
        holeKind: 'hole-a',
        label: '洞口 A',
        x: 0.28,
        y: 0.32,
        imageSrc: null,
      },
      {
        holeId: 'hole-b',
        holeKind: 'hole-b',
        label: '洞口 B',
        x: 0.66,
        y: 0.52,
        imageSrc: null,
      },
    ],
    lastFeedback: null,
  };
}

function renderRuntime() {
  const run = buildRun();
  const onDropShape = vi.fn(async (_payload: DropSquareHoleShapeRequest) => ({
    feedback: {
      accepted: true,
      rejectReason: null,
      message: '已投入',
    },
    run,
  }));

  render(
    <SquareHoleRuntimeShell
      run={run}
      onBack={vi.fn()}
      onRestart={vi.fn()}
      onDropShape={onDropShape}
    />,
  );

  return { onDropShape };
}

beforeEach(() => {
  Object.defineProperty(HTMLElement.prototype, 'setPointerCapture', {
    configurable: true,
    value: vi.fn(),
  });
  Object.defineProperty(HTMLElement.prototype, 'releasePointerCapture', {
    configurable: true,
    value: vi.fn(),
  });
});

test('点击洞口会提交该洞口选择', async () => {
  const { onDropShape } = renderRuntime();

  fireEvent.click(screen.getByRole('button', { name: '投入 洞口 B' }));

  await waitFor(() => expect(onDropShape).toHaveBeenCalledTimes(1));
  expect(onDropShape.mock.calls[0]?.[0]).toMatchObject({
    runId: 'run-1',
    holeId: 'hole-b',
    clientSnapshotVersion: 3,
  });
});

test('引导高亮不会默认指向当前正确洞口', () => {
  renderRuntime();

  const correctHole = screen.getByRole('button', { name: '投入 洞口 B' });
  const hintedHole = screen.getByRole('button', { name: '投入 洞口 A' });

  expect(correctHole.className).not.toContain('ring-2');
  expect(hintedHole.className).toContain('ring-2');
});

test('拖拽当前选项到洞口上松开会提交该洞口选择', async () => {
  const { onDropShape } = renderRuntime();
  const shape = screen.getByRole('button', { name: '拖拽当前选项' });
  const hole = screen.getByRole('button', { name: '投入 洞口 A' });
  const elementsFromPoint = vi.fn(() => [hole]);
  Object.defineProperty(document, 'elementsFromPoint', {
    configurable: true,
    value: elementsFromPoint,
  });

  fireEvent.pointerDown(shape, { pointerId: 1, clientX: 20, clientY: 20 });
  fireEvent.pointerMove(shape, { pointerId: 1, clientX: 140, clientY: 160 });
  fireEvent.pointerUp(shape, { pointerId: 1, clientX: 140, clientY: 160 });

  await waitFor(() => expect(onDropShape).toHaveBeenCalledTimes(1));
  expect(onDropShape.mock.calls[0]?.[0]).toMatchObject({
    runId: 'run-1',
    holeId: 'hole-a',
    clientSnapshotVersion: 3,
  });
  expect(elementsFromPoint).toHaveBeenCalled();
});
