/* @vitest-environment jsdom */

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

import type { CustomWorldAgentSessionSnapshot } from '../../../packages/shared/src/contracts/customWorldAgent';
import {
  createCustomWorldAgentSession,
  executeCustomWorldAgentAction,
  getCustomWorldAgentOperation,
  getCustomWorldAgentSession,
} from '../../services/aiService';
import {
  listCustomWorldGallery,
  listCustomWorldLibrary,
  upsertCustomWorldProfile,
} from '../../services/storageService';
import type { GameState } from '../../types';
import {
  PreGameSelectionFlow,
  type SelectionStage,
} from './PreGameSelectionFlow';

vi.mock('../../services/aiService', () => ({
  createCustomWorldAgentSession: vi.fn(),
  executeCustomWorldAgentAction: vi.fn(),
  generateCustomWorldProfile: vi.fn(),
  getCustomWorldAgentOperation: vi.fn(),
  getCustomWorldAgentSession: vi.fn(),
  sendCustomWorldAgentMessage: vi.fn(),
}));

vi.mock('../../services/storageService', () => ({
  getCustomWorldGalleryDetail: vi.fn(),
  listCustomWorldGallery: vi.fn(),
  listCustomWorldLibrary: vi.fn(),
  publishCustomWorldProfile: vi.fn(),
  unpublishCustomWorldProfile: vi.fn(),
  upsertCustomWorldProfile: vi.fn(),
}));

vi.mock('../custom-world-agent/CustomWorldAgentWorkspace', () => ({
  CustomWorldAgentWorkspace: ({
    session,
    onExecuteAction,
  }: {
    session: CustomWorldAgentSessionSnapshot | null;
    onExecuteAction: (payload: { action: string }) => void;
  }) => (
    <div className="agent-workspace-mock">
      Agent工作区：{session?.sessionId ?? 'missing-session'}
      <button
        type="button"
        onClick={() => {
          onExecuteAction({
            action: 'draft_foundation',
          });
        }}
      >
        开始生成草稿
      </button>
    </div>
  ),
}));

const mockSession: CustomWorldAgentSessionSnapshot = {
  sessionId: 'custom-world-agent-session-1',
  stage: 'clarifying',
  focusCardId: null,
  creatorIntent: {},
  creatorIntentReadiness: {
    isReady: false,
    completedKeys: ['world_hook'],
    missingKeys: [
      'player_premise',
      'theme_and_tone',
      'core_conflict',
      'relationship_seed',
      'iconic_element',
    ],
  },
  anchorPack: {},
  lockState: {},
  draftProfile: null,
  messages: [
    {
      id: 'message-1',
      role: 'assistant',
      kind: 'summary',
      text: '先告诉我你想做一个怎样的 RPG 世界。',
      createdAt: '2026-04-14T12:00:00.000Z',
      relatedOperationId: null,
    },
  ],
  draftCards: [],
  pendingClarifications: [],
  suggestedActions: [],
  recommendedReplies: [],
  qualityFindings: [],
  assetCoverage: {
    roleAssets: [],
    sceneAssets: [],
    allRoleAssetsReady: false,
    allSceneAssetsReady: false,
  },
  updatedAt: '2026-04-14T12:00:00.000Z',
};

function TestWrapper() {
  const [selectionStage, setSelectionStage] =
    useState<SelectionStage>('platform');

  return (
    <PreGameSelectionFlow
      selectionStage={selectionStage}
      setSelectionStage={setSelectionStage}
      gameState={{} as GameState}
      hasSavedGame={false}
      savedSnapshot={null}
      handleContinueGame={() => {}}
      handleStartNewGame={() => {}}
      handleCustomWorldSelect={() => {}}
    />
  );
}

beforeEach(() => {
  vi.clearAllMocks();
  window.history.replaceState(null, '', '/');
  window.sessionStorage.clear();
  vi.mocked(listCustomWorldLibrary).mockResolvedValue([]);
  vi.mocked(listCustomWorldGallery).mockResolvedValue([]);
  vi.mocked(upsertCustomWorldProfile).mockResolvedValue({
    entry: {
      ownerUserId: 'user-1',
      profileId: 'agent-draft-custom-world-agent-session-1',
      profile: {
        id: 'agent-draft-custom-world-agent-session-1',
        name: '潮雾列岛',
      } as never,
      visibility: 'draft',
      publishedAt: null,
      updatedAt: '2026-04-14T12:00:00.000Z',
      authorDisplayName: '玩家',
      worldName: '潮雾列岛',
      subtitle: '旧灯塔与失控航路',
      summaryText: '第一版世界底稿已经整理完成。',
      coverImageSrc: null,
      themeMode: 'tide',
      playableNpcCount: 1,
      landmarkCount: 1,
    },
    entries: [],
  });
  vi.mocked(createCustomWorldAgentSession).mockResolvedValue({
    session: mockSession,
  });
  vi.mocked(executeCustomWorldAgentAction).mockResolvedValue({
    operation: {
      operationId: 'operation-draft-foundation-1',
      type: 'draft_foundation',
      status: 'queued',
      phaseLabel: '已接收请求',
      phaseDetail: '正在准备生成世界底稿。',
      progress: 10,
      error: null,
    },
  });
  vi.mocked(getCustomWorldAgentOperation).mockResolvedValue({
    operationId: 'operation-draft-foundation-1',
    type: 'draft_foundation',
    status: 'running',
    phaseLabel: '生成世界底稿',
    phaseDetail: '正在根据已确认锚点编译第一版世界结构。',
    progress: 38,
    error: null,
  });
  vi.mocked(getCustomWorldAgentSession).mockResolvedValue(mockSession);
});

test('create tab opens game type modal, keeps AIRP and visual novel locked, and enters agent workspace for RPG', async () => {
  const user = userEvent.setup();

  render(<TestWrapper />);

  await user.click(screen.getByRole('button', { name: '创作' }));
  await user.click(screen.getByRole('button', { name: /开启新的创作/u }));

  expect(screen.getByText('选择创作类型')).toBeTruthy();

  const airpButton = screen.getByRole('button', { name: /AIRP/u });
  const visualNovelButton = screen.getByRole('button', {
    name: /视觉小说/u,
  });

  expect((airpButton as HTMLButtonElement).disabled).toBe(true);
  expect((visualNovelButton as HTMLButtonElement).disabled).toBe(true);

  await user.click(screen.getByRole('button', { name: /角色扮演 RPG/u }));

  await waitFor(() => {
    expect(createCustomWorldAgentSession).toHaveBeenCalledTimes(1);
  });

  expect(
    await screen.findByText('Agent工作区：custom-world-agent-session-1'),
  ).toBeTruthy();
});

test('starting draft generation leaves the agent workspace and shows the generation progress view', async () => {
  const user = userEvent.setup();

  render(<TestWrapper />);

  await user.click(screen.getByRole('button', { name: '创作' }));
  await user.click(screen.getByRole('button', { name: /开启新的创作/u }));
  await user.click(screen.getByRole('button', { name: /角色扮演 RPG/u }));

  expect(
    await screen.findByText('Agent工作区：custom-world-agent-session-1'),
  ).toBeTruthy();

  await user.click(screen.getByRole('button', { name: '开始生成草稿' }));

  await waitFor(() => {
    expect(executeCustomWorldAgentAction).toHaveBeenCalledWith(
      'custom-world-agent-session-1',
      {
        action: 'draft_foundation',
      },
    );
  });

  expect(await screen.findByText('世界草稿生成进度')).toBeTruthy();
  expect(screen.queryByText(/Agent工作区/u)).toBeNull();
  expect(screen.getAllByText('生成世界底稿').length).toBeGreaterThan(0);
});

test('existing draft sessions enter the legacy result layout directly', async () => {
  const user = userEvent.setup();

  vi.mocked(getCustomWorldAgentOperation).mockResolvedValue({
    operationId: 'operation-draft-foundation-1',
    type: 'draft_foundation',
    status: 'completed',
    phaseLabel: '世界底稿已生成',
    phaseDetail: '第一版世界底稿和 4 张草稿卡已经整理完成。',
    progress: 100,
    error: null,
  });
  vi.mocked(getCustomWorldAgentSession).mockResolvedValue({
    ...mockSession,
    stage: 'object_refining',
    creatorIntent: {
      sourceMode: 'card',
      worldHook: '被海雾吞没的旧航路群岛',
      playerPremise: '玩家回到群岛调查沉船真相。',
      themeKeywords: ['海雾', '旧航路'],
      toneDirectives: ['压抑', '悬疑'],
      openingSituation: '首夜就有陌生船只闯入禁航区。',
      coreConflicts: ['航运公会与守灯会争夺航路控制权'],
      keyFactions: [],
      keyCharacters: [],
      keyLandmarks: [],
      iconicElements: ['会移动的海雾'],
      forbiddenDirectives: [],
      rawSettingText: '',
    },
    draftProfile: {
      name: '潮雾列岛',
      subtitle: '旧灯塔与失控航路',
      summary: '第一版世界底稿已经整理完成。',
      tone: '压抑、潮湿、悬疑',
      playerGoal: '查清沉船与禁航区异动的真相。',
      majorFactions: ['守灯会', '航运公会'],
      coreConflicts: ['守灯会与航运公会争夺旧航路控制权'],
      playableNpcs: [
        {
          id: 'playable-1',
          name: '沈砺',
          title: '旧航路引路人',
          role: '关键同行者',
          publicIdentity: '最熟悉旧航路的人。',
          publicMask: '看上去像可靠旧友。',
          currentPressure: '他必须在两股势力间站队。',
          hiddenHook: '暗中替沉船商盟引路。',
          relationToPlayer: '旧友兼潜在背叛者',
          threadIds: ['thread-1'],
          summary: '他像旧友，但也像一把始终没收回鞘的刀。',
        },
      ],
      storyNpcs: [
        {
          id: 'story-1',
          name: '顾潮音',
          title: '守灯会值夜人',
          role: '场景关键角色',
          publicIdentity: '负责夜间巡灯与封锁。',
          publicMask: '对外一直冷静克制。',
          currentPressure: '她知道更多禁航区真相。',
          hiddenHook: '曾亲眼见过失控海雾吞船。',
          relationToPlayer: '最早愿意交换线索的人',
          threadIds: ['thread-1'],
          summary: '她总像比所有人更早知道海雾会往哪一侧压下来。',
        },
      ],
      landmarks: [
        {
          id: 'landmark-1',
          name: '回潮旧灯塔',
          purpose: '观察雾潮与往来船只',
          mood: '潮湿、压抑、风声不止',
          importance: '开局核心场景',
          characterIds: ['story-1'],
          threadIds: ['thread-1'],
          summary: '旧灯塔是整片群岛最先看见异动的地方。',
        },
      ],
      factions: [],
      threads: [],
      chapters: [],
      worldHook: '被海雾吞没的旧航路群岛',
      playerPremise: '玩家回到群岛调查沉船真相。',
      openingSituation: '首夜就有陌生船只闯入禁航区。',
      iconicElements: ['会移动的海雾'],
      sourceAnchorSummary: '海雾、旧灯塔、失控航路。',
    },
    draftCards: [
      {
        id: 'world-foundation',
        kind: 'world',
        title: '潮雾列岛',
        subtitle: '旧灯塔与失控航路',
        summary: '第一版世界底稿已经整理完成。',
        status: 'warning',
        linkedIds: ['playable-1', 'story-1', 'landmark-1'],
        warningCount: 0,
      },
    ],
  });

  render(<TestWrapper />);

  await user.click(screen.getByRole('button', { name: '创作' }));
  await user.click(screen.getByRole('button', { name: /开启新的创作/u }));
  await user.click(screen.getByRole('button', { name: /角色扮演 RPG/u }));

  await waitFor(
    async () => {
      expect(await screen.findByText('世界档案')).toBeTruthy();
      expect(
        screen.getByRole('button', {
          name: /保存到我的作品|自动保存中|已保存到我的作品/u,
        }),
      ).toBeTruthy();
    },
    { timeout: 2500 },
  );

  expect(screen.queryByText(/Agent工作区/u)).toBeNull();
  expect(screen.queryByRole('button', { name: /^锚点/u })).toBeNull();
  expect(screen.getByText(/原始设定/u)).toBeTruthy();

  await user.click(screen.getByRole('button', { name: /场景角色/u }));
  await user.click(screen.getByRole('button', { name: /顾潮音/u }));

  expect(await screen.findByText(/编辑场景角色：顾潮音/u)).toBeTruthy();
  expect(
    screen.getByRole('button', { name: /AI生成形象与动作/u }),
  ).toBeTruthy();
  expect(screen.getByText('技能')).toBeTruthy();

});
