/* @vitest-environment jsdom */

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

import {
  buildCustomWorldPlayableCharacters,
} from '../../data/characterPresets';
import {
  type Character,
  type CustomWorldProfile,
  WorldType,
} from '../../types';
import { RpgEntryCharacterSelectView } from './RpgEntryCharacterSelectView';

vi.mock('../../data/characterPresets', () => ({
  ROLE_TEMPLATE_CHARACTERS: [],
  buildCustomWorldPlayableCharacters: vi.fn(),
}));

vi.mock('../CharacterAnimator', () => ({
  CharacterAnimator: ({ character }: { character: Character }) => (
    <div>{character.name}</div>
  ),
}));

vi.mock('../CharacterDetailModal', () => ({
  CharacterDetailModal: () => null,
}));

vi.mock('../SelectionCustomizationModals', () => ({
  CharacterDraftModal: () => null,
}));

function createCharacter(name: string, title: string): Character {
  return {
    id: '',
    name,
    title,
    description: `${name}的定位描述`,
    backstory: `${name}的背景故事`,
    personality: `${name} 冷静 果断`,
    gender: 'female',
    portrait: `/portraits/${name}.png`,
    attributes: {
      strength: 10,
      agility: 11,
      intelligence: 12,
      spirit: 13,
    },
    skills: [],
  } as unknown as Character;
}

afterEach(() => {
  vi.restoreAllMocks();
});

test('custom world character selection stays stable when character ids are empty', async () => {
  const user = userEvent.setup();
  const handleConfirm = vi.fn();
  const consoleErrorSpy = vi
    .spyOn(console, 'error')
    .mockImplementation(() => undefined);

  vi.mocked(buildCustomWorldPlayableCharacters).mockReturnValue([
    createCharacter('沈砺', '潮锋斥候'),
    createCharacter('闻潮', '雾海哨兵'),
  ]);

  HTMLElement.prototype.scrollTo = function scrollTo(
    this: HTMLElement,
    options?: ScrollToOptions | number,
  ) {
    if (typeof options === 'object' && options) {
      if (typeof options.left === 'number') {
        this.scrollLeft = options.left;
      }
      if (typeof options.top === 'number') {
        this.scrollTop = options.top;
      }
    }
    this.dispatchEvent(new Event('scroll'));
  };

  vi
    .spyOn(HTMLElement.prototype, 'getBoundingClientRect')
    .mockImplementation(function mockGetBoundingClientRect(this: HTMLElement) {
      if ((this as HTMLElement).dataset.carouselCard === 'true') {
        return {
          width: 240,
          height: 360,
          top: 0,
          right: 240,
          bottom: 360,
          left: 0,
          x: 0,
          y: 0,
          toJSON: () => ({}),
        } as DOMRect;
      }

      return {
        width: 0,
        height: 0,
        top: 0,
        right: 0,
        bottom: 0,
        left: 0,
        x: 0,
        y: 0,
        toJSON: () => ({}),
      } as DOMRect;
    });

  render(
    <RpgEntryCharacterSelectView
      worldType={WorldType.CUSTOM}
      customWorldProfile={{
        attributeSchema: {
          id: 'schema:custom:test',
          worldId: 'custom:test',
          schemaVersion: 1,
          generatedFrom: {
            worldType: WorldType.CUSTOM,
            worldName: '潮城',
            settingSummary: '潮水与迷雾交织的港城。',
            tone: '潮湿、危险、带着试探。',
            conflictCore: '在涨落之间抢先一步。',
          },
          slots: [
            {
              slotId: 'axis_a',
              name: '潮骨',
            },
            {
              slotId: 'axis_b',
              name: '浪步',
            },
            {
              slotId: 'axis_c',
              name: '舟识',
            },
            {
              slotId: 'axis_d',
              name: '潮魄',
            },
            {
              slotId: 'axis_e',
              name: '契汐',
            },
            {
              slotId: 'axis_f',
              name: '回澜',
            },
          ],
        },
      } as unknown as CustomWorldProfile}
      onBack={() => {}}
      onConfirm={handleConfirm}
    />,
  );

  expect(screen.getByText(/潮骨:/u)).toBeTruthy();
  expect(screen.queryByText(/力量:/u)).toBeNull();

  await user.click(screen.getByRole('button', { name: /闻潮/u }));

  await waitFor(() => {
    expect(screen.getByRole('button', { name: /查看闻潮的详情/u })).toBeTruthy();
  });

  await user.click(screen.getByRole('button', { name: /进入营地/u }));

  expect(handleConfirm).toHaveBeenCalledWith(
    expect.objectContaining({
      name: '闻潮',
      title: '雾海哨兵',
    }),
  );

  const duplicateKeyCalls = consoleErrorSpy.mock.calls.filter((call) =>
    call.some(
      (arg) =>
        typeof arg === 'string'
        && arg.includes('Encountered two children with the same key'),
    ),
  );

  expect(duplicateKeyCalls).toHaveLength(0);
});
