/* @vitest-environment jsdom */

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

import type {
  Match3DClickItemRequest,
  Match3DRunSnapshot,
} from '../../../packages/shared/src/contracts/match3dRuntime';
import {
  confirmLocalMatch3DClick,
  startLocalMatch3DRun,
} from '../../services/match3d-runtime';
import { Match3DRuntimeShell } from './Match3DRuntimeShell';

function renderRuntime(run: Match3DRunSnapshot) {
  let currentRun = run;
  let authorityRun = run;
  const onClickItem = vi.fn(async (payload: Match3DClickItemRequest) => {
    const result = await confirmLocalMatch3DClick(authorityRun, payload);
    authorityRun = result.run;
    return result;
  });
  const onOptimisticRunChange = vi.fn((nextRun: Match3DRunSnapshot) => {
    currentRun = nextRun;
    rerender(
      <Match3DRuntimeShell
        run={currentRun}
        onBack={vi.fn()}
        onRestart={vi.fn()}
        onOptimisticRunChange={onOptimisticRunChange}
        onClickItem={onClickItem}
      />,
    );
  });
  const { rerender } = render(
    <Match3DRuntimeShell
      run={currentRun}
      onBack={vi.fn()}
      onRestart={vi.fn()}
      onOptimisticRunChange={onOptimisticRunChange}
      onClickItem={onClickItem}
    />,
  );
  return {
    onClickItem,
    onOptimisticRunChange,
  };
}

test('展示圆形空间和 7 格备选栏', () => {
  renderRuntime(startLocalMatch3DRun(4));

  expect(screen.getByTestId('match3d-board')).toBeTruthy();
  expect(screen.getAllByTestId('match3d-tray-slot')).toHaveLength(7);
});

test('点击可见物品后先乐观入槽再等待确认', async () => {
  const run = startLocalMatch3DRun(4);
  const clickableItem = run.items.find((item) => item.clickable);
  expect(clickableItem).toBeTruthy();
  const { onClickItem, onOptimisticRunChange } = renderRuntime(run);

  fireEvent.click(
    screen.getByTestId(`match3d-item-${clickableItem!.itemInstanceId}`),
  );

  expect(onOptimisticRunChange).toHaveBeenCalled();
  await waitFor(() => expect(onClickItem).toHaveBeenCalledTimes(1));
});

test('后端形状视觉键不会被统一兜底成红色苹字', () => {
  const run = startLocalMatch3DRun(2);
  run.items = run.items.slice(0, 2).map((item, index) => ({
    ...item,
    itemInstanceId: `shape-${index}`,
    itemTypeId: `shape-type-${index}`,
    visualKey: index === 0 ? 'red_circle' : 'yellow_triangle',
    x: 0.42 + index * 0.16,
    y: 0.5,
    layer: index,
    clickable: true,
  }));
  renderRuntime(run);

  expect(screen.getByTestId('match3d-visual-red_circle')).toBeTruthy();
  expect(screen.getByTestId('match3d-visual-yellow_triangle')).toBeTruthy();
  expect(screen.queryAllByText('苹')).toHaveLength(0);
});

test('水果题材视觉键也渲染为无文字纯色几何体', () => {
  const run = startLocalMatch3DRun(3);
  run.items = run.items.slice(0, 3).map((item, index) => ({
    ...item,
    itemInstanceId: `fruit-${index}`,
    itemTypeId: `fruit-type-${index}`,
    visualKey:
      index === 0
        ? 'watermelon-green'
        : index === 1
          ? 'apple-red'
          : 'grape-purple',
    x: 0.35 + index * 0.15,
    y: 0.5,
    radius: index === 0 ? 0.12 : index === 1 ? 0.09 : 0.07,
    layer: index,
    clickable: true,
  }));
  renderRuntime(run);

  expect(screen.getByTestId('match3d-visual-watermelon-green')).toBeTruthy();
  expect(
    screen.getByTestId('match3d-visual-apple-red').getAttribute('data-shape'),
  ).toBe('heart');
  expect(
    screen
      .getByTestId('match3d-visual-grape-purple')
      .getAttribute('data-shape'),
  ).toBe('star');
  expect(screen.queryByText('苹果')).toBeNull();
  expect(screen.queryByText('苹')).toBeNull();
});

test('运行态支持梯形和平行四边形等差异化几何造型', () => {
  const run = startLocalMatch3DRun(3);
  run.items = run.items.slice(0, 3).map((item, index) => ({
    ...item,
    itemInstanceId: `geometry-${index}`,
    itemTypeId: `geometry-type-${index}`,
    visualKey:
      index === 0
        ? 'peach-pink'
        : index === 1
          ? 'banana-yellow'
          : 'orange_hexagon',
    x: 0.35 + index * 0.15,
    y: 0.5,
    layer: index,
    clickable: true,
  }));
  renderRuntime(run);

  expect(
    screen.getByTestId('match3d-visual-peach-pink').getAttribute('data-shape'),
  ).toBe('trapezoid');
  expect(
    screen
      .getByTestId('match3d-visual-banana-yellow')
      .getAttribute('data-shape'),
  ).toBe('parallelogram');
  expect(
    screen
      .getByTestId('match3d-visual-orange_hexagon')
      .getAttribute('data-shape'),
  ).toBe('hexagon');
});

test('异常旧坐标只做显示层收束，不让物品贴出圆形空间', () => {
  const run = startLocalMatch3DRun(1);
  const item = run.items[0]!;
  run.items = [
    {
      ...item,
      itemInstanceId: 'legacy-outside',
      visualKey: 'apple-red',
      x: -0.4,
      y: 0.5,
      radius: 0.1,
      clickable: true,
    },
  ];
  renderRuntime(run);

  const token = screen.getByTestId(
    'match3d-item-legacy-outside',
  ) as HTMLElement;
  expect(parseFloat(token.style.left)).toBeGreaterThanOrEqual(0);
  expect(parseFloat(token.style.left)).toBeLessThanOrEqual(100);
});
