import { renderToStaticMarkup } from 'react-dom/server';
import { expect, test } from 'vitest';

import type { CreationEntryConfig } from '../../services/creationEntryConfigService';
import { derivePlatformCreationTypes } from '../platform-entry/platformEntryCreationTypes';
import { buildCreationWorkShelfItems } from './creationWorkShelf';
import { CustomWorldCreationHub } from './CustomWorldCreationHub';

const noopCreateType = () => {};
const DAY_MS = 24 * 60 * 60 * 1000;

function buildUpdatedAtDaysAgo(daysAgo: number) {
  return new Date(Date.now() - daysAgo * DAY_MS).toISOString();
}

const testEntryConfig = {
  startCard: {
    title: '新建作品',
    description: '选择模板后进入对应的创作表单。',
    idleBadge: '模板 Tab',
    busyBadge: '正在开启',
  },
  typeModal: {
    title: '选择创作类型',
    description: '先选玩法类型，再进入对应创作工作台。',
  },
  eventBanner: {
    title: '泥点挑战',
    description: '创作活动测试横幅。',
    coverImageSrc: '/creation-type-references/puzzle.webp',
    prizePoolMudPoints: 1000,
    startsAtText: '2026-05-01',
    endsAtText: '2026-05-31',
  },
  eventBanners: [
    {
      title: '后台拼图赛',
      description: '后台配置的拼图横幅。',
      coverImageSrc: '/creation-type-references/puzzle.webp',
      prizePoolMudPoints: 1000,
      startsAtText: '2026-05-01',
      endsAtText: '2026-05-31',
      renderMode: 'structured',
    },
    {
      title: '后台抓大鹅赛',
      description: '后台配置的抓大鹅横幅。',
      coverImageSrc: '/creation-type-references/match3d.webp',
      prizePoolMudPoints: 1200,
      startsAtText: '2026-06-01',
      endsAtText: '2026-06-30',
      renderMode: 'structured',
    },
  ],
  creationTypes: [
    {
      id: 'rpg',
      title: '文字冒险',
      subtitle: '经典 RPG 体验',
      badge: '可创建',
      imageSrc: '/creation-type-references/rpg.webp',
      visible: true,
      open: true,
      sortOrder: 10,
      categoryId: 'recommended',
      categoryLabel: '热门推荐',
      categorySortOrder: 20,
      updatedAtMicros: 1,
    },
    {
      id: 'puzzle',
      title: '拼图',
      subtitle: '拼图关卡创作',
      badge: '可创建',
      imageSrc: '/creation-type-references/puzzle.webp',
      visible: true,
      open: true,
      sortOrder: 30,
      categoryId: 'recommended',
      categoryLabel: '热门推荐',
      categorySortOrder: 20,
      updatedAtMicros: 1,
    },
    {
      id: 'match3d',
      title: '抓大鹅',
      subtitle: '3D 消除关卡',
      badge: '可创作',
      imageSrc: '/creation-type-references/match3d.webp',
      visible: true,
      open: true,
      sortOrder: 40,
      categoryId: 'recommended',
      categoryLabel: '热门推荐',
      categorySortOrder: 20,
      updatedAtMicros: 1,
    },
    {
      id: 'jump-hop',
      title: '跳一跳',
      subtitle: '节奏跳跃挑战',
      badge: '可创建',
      imageSrc: '/creation-type-references/jump-hop.webp',
      visible: true,
      open: true,
      sortOrder: 45,
      categoryId: 'recommended',
      categoryLabel: '热门推荐',
      categorySortOrder: 20,
      updatedAtMicros: 1,
    },
    {
      id: 'square-hole',
      title: '方洞',
      subtitle: '形状投放挑战',
      badge: '可创建',
      imageSrc: '/creation-type-references/square-hole.webp',
      visible: false,
      open: true,
      sortOrder: 50,
      categoryId: 'recommended',
      categoryLabel: '热门推荐',
      categorySortOrder: 20,
      updatedAtMicros: 1,
    },
    {
      id: 'visual-novel',
      title: '视觉小说',
      subtitle: '分支叙事体验',
      badge: '敬请期待',
      imageSrc: '/creation-type-references/visual-novel.webp',
      visible: false,
      open: false,
      sortOrder: 60,
      categoryId: 'recommended',
      categoryLabel: '热门推荐',
      categorySortOrder: 20,
      updatedAtMicros: 1,
    },
    {
      id: 'airp',
      title: 'AI RPG',
      subtitle: '原生角色扮演',
      badge: '即将开放',
      imageSrc: '/creation-type-references/airp.webp',
      visible: true,
      open: false,
      sortOrder: 70,
      categoryId: 'recommended',
      categoryLabel: '热门推荐',
      categorySortOrder: 20,
      updatedAtMicros: 1,
    },
  ],
} satisfies CreationEntryConfig;

const testCreationTypes = derivePlatformCreationTypes(
  testEntryConfig.creationTypes,
);

test('creation hub draft card renders compiled work summary fields', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[
        {
          workId: 'draft:session-1',
          sourceType: 'agent_session',
          status: 'draft',
          title: '一个被潮雾切开的列岛世界',
          subtitle: '补齐关键锚点',
          summary:
            '玩家是失职返乡的守灯人 · 核心冲突：守灯会与沉船商盟争夺航道解释权',
          coverImageSrc: null,
          updatedAt: new Date('2026-04-13T12:00:00.000Z').toISOString(),
          publishedAt: null,
          stage: 'clarifying',
          stageLabel: '补齐关键锚点',
          playableNpcCount: 0,
          landmarkCount: 0,
          sessionId: 'session-1',
          profileId: null,
          canResume: true,
          canEnterWorld: false,
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
    />,
  );

  expect(html).toContain('一个被潮雾切开的列岛世界');
  expect(html).toContain('玩家是失职返乡的守灯人');
  expect(html).toContain('守灯会与沉船商盟争夺航道解释权');
  expect(html).toContain('拼图');
  expect(html).toContain('拼图关卡创作');
  expect(html).toContain('抓大鹅');
  expect(html).toContain('3D 消除关卡');
  expect(html).toContain('文字冒险');
  expect(html).toContain('经典 RPG 体验');
  expect(html).not.toContain('大鱼吃小鱼');
});

test('creation start card renders reference-aligned banner and template metadata', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      mode="start-only"
    />,
  );

  expect(html).toContain('creation-event-banner');
  expect(html).toContain('creation-event-banner__track');
  expect(html).toContain('creation-event-banner__slide');
  expect(html).toContain('creation-event-banner__timebar');
  expect(html).toContain('后台拼图赛');
  expect(html).toContain('后台抓大鹅赛');
  expect(html).toContain('1,000');
  expect(html).toContain('1,200');
  expect(html).toContain('泥点数');
  expect(html).not.toContain('泥点挑战');
  expect(html).not.toContain('拼图主题创作赛');
  expect(html).not.toContain('抓大鹅主题创作赛');
  expect(html).not.toContain('最近创作');
  expect(html).toMatch(
    /creation-event-banner__timebar[\s\S]*creation-event-banner__pager[\s\S]*creation-template-card/u,
  );
  expect(html).toContain('creation-template-card__body');
  expect(html).toContain('creation-template-card__cost-badge');
  expect(html).toContain('拼图关卡创作');
  expect(html).toContain('10-20泥点数');
  expect(html).toContain('即将开放');
  expect(html).not.toContain('可创建');
  expect(html).not.toContain('可创作');
  expect(html).not.toContain('creation-event-banner__counter');
  expect(html).not.toContain('预计消耗 10-20 泥点');
  expect(html).not.toContain('platform-creation-reference-card');
});

test('creation start card falls back to legacy single banner when eventBanners is empty', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={{
        ...testEntryConfig,
        eventBanners: [],
      }}
      creationTypes={testCreationTypes}
      mode="start-only"
    />,
  );

  expect(html).toContain('泥点挑战');
  expect(html).not.toContain('后台拼图赛');
});

test('creation start card renders html banner in an empty-permission sandbox', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={{
        ...testEntryConfig,
        eventBanners: [
          {
            ...testEntryConfig.eventBanner,
            title: 'HTML 后台横幅',
            renderMode: 'html',
            htmlCode: '<section><h1>自定义横幅</h1></section>',
          },
        ],
      }}
      creationTypes={testCreationTypes}
      mode="start-only"
    />,
  );

  expect(html).toContain('title="HTML 后台横幅"');
  expect(html).toContain('sandbox=""');
  expect(html).toContain('&lt;section&gt;&lt;h1&gt;自定义横幅&lt;/h1&gt;&lt;/section&gt;');
});

test('creation start card renders recent tab with the same template cards', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[
        {
          workId: 'draft:recent-session',
          sourceType: 'agent_session',
          status: 'draft',
          title: '后端返回的最近草稿',
          subtitle: '待完善草稿',
          summary: '这条内容来自作品架摘要。',
          coverImageSrc: null,
          updatedAt: buildUpdatedAtDaysAgo(1),
          publishedAt: null,
          stage: 'clarifying',
          stageLabel: '待完善草稿',
          playableNpcCount: 0,
          landmarkCount: 0,
          sessionId: 'recent-session',
          profileId: null,
          canResume: true,
          canEnterWorld: false,
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      mode="start-only"
    />,
  );

  expect(html).toContain('aria-label="创作入口页签"');
  expect(html).toContain('role="tab"');
  expect(html).toContain('aria-selected="true"');
  expect(html).toContain('creation-template-list__grid');
  expect(html).toContain('creation-template-card');
  expect(html).toContain('最近创作');
  expect(html).toContain('仅显示最近7天内使用过的模板');
  expect(html).toContain('文字冒险');
  expect(html).toContain('经典 RPG 体验');
  expect(html).not.toContain('creation-recent-work-grid');
  expect(html).not.toContain('打开最近创作');
  expect(html).not.toContain('后端返回的最近草稿');
  expect(html).not.toContain('这条内容来自作品架摘要');
});

test('creation start card prefers backend recent summaries over local pending placeholders', () => {
  const recentWorkItems = buildCreationWorkShelfItems({
    rpgItems: [
      {
        workId: 'draft:backend-session',
        sourceType: 'agent_session',
        status: 'draft',
        title: '后端最近草稿',
        subtitle: '真实作品架摘要',
        summary: '最近创作应该只读取后端摘要。',
        coverImageSrc: null,
        updatedAt: buildUpdatedAtDaysAgo(1),
        publishedAt: null,
        stage: 'failed',
        stageLabel: '生成失败',
        playableNpcCount: 0,
        landmarkCount: 0,
        sessionId: 'backend-session',
        profileId: null,
        canResume: true,
        canEnterWorld: false,
      },
    ],
    bigFishItems: [],
    puzzleItems: [],
  });
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[
        {
          workId: 'draft:local-pending-session',
          sourceType: 'agent_session',
          status: 'draft',
          title: '本地生成中占位',
          subtitle: '本地占位',
          summary: '这条占位不应该进入最近创作。',
          coverImageSrc: null,
          updatedAt: buildUpdatedAtDaysAgo(0),
          publishedAt: null,
          stage: 'generating',
          stageLabel: '生成中',
          playableNpcCount: 0,
          landmarkCount: 0,
          sessionId: 'local-pending-session',
          profileId: null,
          canResume: true,
          canEnterWorld: false,
        },
      ]}
      recentWorkItems={recentWorkItems}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      mode="start-only"
    />,
  );

  expect(html).toContain('最近创作');
  expect(html).toContain('文字冒险');
  expect(html).toContain('经典 RPG 体验');
  expect(html).not.toContain('后端最近草稿');
  expect(html).not.toContain('最近创作应该只读取后端摘要');
  expect(html).not.toContain('本地生成中占位');
});

test('creation start card excludes works older than the recent window', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[
        {
          workId: 'draft:old-session',
          sourceType: 'agent_session',
          status: 'draft',
          title: '八天前的草稿',
          subtitle: '旧草稿',
          summary: '这条草稿已经超过最近创作期限。',
          coverImageSrc: null,
          updatedAt: buildUpdatedAtDaysAgo(8),
          publishedAt: null,
          stage: 'clarifying',
          stageLabel: '待完善草稿',
          playableNpcCount: 0,
          landmarkCount: 0,
          sessionId: 'old-session',
          profileId: null,
          canResume: true,
          canEnterWorld: false,
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      mode="start-only"
    />,
  );

  expect(html).not.toContain('最近创作');
  expect(html).not.toContain('仅显示最近7天内使用过的模板');
  expect(html).not.toContain('八天前的草稿');
  expect(html).not.toContain('这条草稿已经超过最近创作期限');
});

test('creation start card maps backend jump-hop draft to template card', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      jumpHopItems={[
        {
          runtimeKind: 'jump-hop',
          workId: 'jump-hop-work-1',
          profileId: 'jump-hop-profile-1',
          ownerUserId: 'user-1',
          sourceSessionId: 'jump-hop-session-1',
          workTitle: '跳一跳生成草稿',
          workDescription: '后端仍在生成跳一跳玩法。',
          themeTags: ['跳一跳'],
          difficulty: 'standard',
          stylePreset: 'minimal-blocks',
          coverImageSrc: null,
          publicationStatus: 'draft',
          playCount: 0,
          updatedAt: buildUpdatedAtDaysAgo(1),
          publishedAt: null,
          publishReady: false,
          generationStatus: 'generating',
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      onOpenJumpHopDetail={() => {}}
      mode="start-only"
    />,
  );

  expect(html).toContain('最近创作');
  expect(html).toContain('跳一跳');
  expect(html).toContain('节奏跳跃挑战');
  expect(html).toContain('creation-template-card');
  expect(html).not.toContain('跳一跳生成草稿');
  expect(html).not.toContain('后端仍在生成跳一跳玩法');
});

test('creation start card includes failed drafts in the recent tab', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[
        {
          workId: 'draft:failed-session',
          sourceType: 'agent_session',
          status: 'draft',
          title: '失败但仍可恢复的草稿',
          subtitle: '生成失败',
          summary: '失败草稿也来自真实作品架摘要。',
          coverImageSrc: null,
          updatedAt: buildUpdatedAtDaysAgo(1),
          publishedAt: null,
          stage: 'failed',
          stageLabel: '生成失败',
          playableNpcCount: 0,
          landmarkCount: 0,
          sessionId: 'failed-session',
          profileId: null,
          canResume: true,
          canEnterWorld: false,
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      mode="start-only"
    />,
  );

  expect(html).toContain('最近创作');
  expect(html).toContain('creation-template-list__grid');
  expect(html).toContain('文字冒险');
  expect(html).toContain('经典 RPG 体验');
  expect(html).not.toContain('creation-recent-work-grid');
  expect(html).not.toContain('失败但仍可恢复的草稿');
  expect(html).not.toContain('失败草稿也来自真实作品架摘要');
});

test('creation start card maps failed mini-game drafts into recent template cards', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      match3dItems={[
        {
          workId: 'match3d-failed-work',
          profileId: 'match3d-failed-profile',
          ownerUserId: 'user-1',
          gameName: '失败抓大鹅草稿',
          themeText: '水果',
          summary: '失败的小玩法草稿也应该进入最近创作。',
          tags: [],
          coverImageSrc: null,
          clearCount: 0,
          difficulty: 1,
          publicationStatus: 'draft',
          playCount: 0,
          updatedAt: buildUpdatedAtDaysAgo(1),
          publishedAt: null,
          publishReady: false,
          generationStatus: 'failed',
        },
      ]}
      mode="start-only"
    />,
  );

  expect(html).toContain('最近创作');
  expect(html).toContain('抓大鹅');
  expect(html).toContain('3D 消除关卡');
  expect(html).toContain('creation-template-card');
  expect(html).not.toContain('失败抓大鹅草稿');
  expect(html).not.toContain('失败的小玩法草稿也应该进入最近创作。');
});

test('creation start card keeps typography in compact UI scale', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      mode="start-only"
    />,
  );

  expect(html).toMatch(/creation-template-card__title[^"]*\btext-sm\b/u);
  expect(html).toMatch(/creation-template-card__subtitle[^"]*\btext-xs\b/u);
  expect(html).toMatch(
    /creation-template-card__cost-badge[^"]*\btext-\[11px\](?:\s|")/u,
  );
  expect(html).not.toMatch(
    /\b(text-lg|text-xl|sm:text-base|sm:text-lg|sm:text-xl|text-\[1\.08rem\])\b/u,
  );
});

test('creation start card removes the outer template list frame and tightens card grid', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      mode="start-only"
    />,
  );

  expect(html).toContain('creation-template-list');
  expect(html).toMatch(/creation-template-list__grid[^"]*\bgap-2\b/u);
  expect(html).toMatch(/creation-template-card[^"]*\bmin-h-\[12\.5rem\]/u);
  expect(html).not.toMatch(
    /creation-template-list[^"]*\bborder\b[^"]*\bborder-\[#f0dfd6\]/u,
  );
});

test('creation hub renders puzzle works in the same unified list with puzzle tag', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      puzzleItems={[
        {
          workId: 'puzzle:work-1',
          profileId: 'puzzle-profile-1',
          ownerUserId: 'user-1',
          authorDisplayName: '测试作者',
          levelName: '潮雾拼图',
          summary: '一张被切成拼图的潮雾港口主视觉。',
          themeTags: ['潮雾', '港口'],
          coverImageSrc: null,
          publicationStatus: 'published',
          updatedAt: new Date('2026-04-22T10:00:00.000Z').toISOString(),
          publishedAt: new Date('2026-04-22T10:05:00.000Z').toISOString(),
          playCount: 12,
          remixCount: 3,
          likeCount: 4,
          publishReady: true,
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      onOpenPuzzleDetail={() => {}}
    />,
  );

  expect(html).toContain('潮雾拼图');
  expect(html).toContain('拼图');
  expect(html).toContain('aria-label="游玩 12次"');
  expect(html).toContain('aria-label="改造 3次"');
  expect(html).toContain('aria-label="点赞 4赞"');
  expect(html).not.toContain('作品号');
  expect(html).not.toContain('PZ-PROFILE1');
  expect(html).not.toContain('潮雾</span>');
  expect(html).not.toContain('港口</span>');
  expect(html).not.toContain('我的拼图作品');
});

test('creation hub marks generating and newly completed drafts', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      puzzleItems={[
        {
          workId: 'puzzle-work-session-1',
          profileId: 'puzzle-profile-session-1',
          ownerUserId: 'user-1',
          authorDisplayName: '测试作者',
          workTitle: '潮雾拼图草稿',
          workDescription: '正在生成首张拼图主视觉。',
          levelName: '潮雾拼图',
          summary: '正在生成首张拼图主视觉。',
          themeTags: ['潮雾'],
          coverImageSrc: null,
          publicationStatus: 'draft',
          updatedAt: new Date('2026-04-22T10:00:00.000Z').toISOString(),
          publishedAt: null,
          publishReady: false,
          sourceSessionId: 'puzzle-session-1',
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      onOpenPuzzleDetail={() => {}}
      getWorkState={(item) =>
        item.kind === 'puzzle'
          ? { isGenerating: true, hasUnreadUpdate: true }
          : null
      }
    />,
  );

  expect(html).toContain('生成中');
  expect(html).toContain('aria-label="新生成完成"');
  expect(html).toContain('生成中...');
  expect(html).toContain('creation-work-card__spinner');
});

test('creation hub does not mask completed puzzle drafts while a later level image is generating', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      puzzleItems={[
        {
          workId: 'puzzle-work-session-1',
          profileId: 'puzzle-profile-session-1',
          ownerUserId: 'user-1',
          authorDisplayName: '测试作者',
          workTitle: '潮雾拼图草稿',
          workDescription: '已经有可查看的首关结果。',
          levelName: '潮雾拼图',
          summary: '已经有可查看的首关结果。',
          themeTags: ['潮雾'],
          coverImageSrc: '/generated-puzzle-assets/session/cover.png',
          publicationStatus: 'draft',
          updatedAt: new Date('2026-04-22T10:00:00.000Z').toISOString(),
          publishedAt: null,
          publishReady: false,
          sourceSessionId: 'puzzle-session-1',
          generationStatus: 'generating',
          levels: [
            {
              levelId: 'puzzle-level-1',
              levelName: '潮雾拼图',
              pictureDescription: '潮雾港口。',
              pictureReference: null,
              candidates: [
                {
                  candidateId: 'candidate-1',
                  imageSrc: '/generated-puzzle-assets/session/cover.png',
                  assetId: 'asset-1',
                  prompt: '潮雾港口',
                  actualPrompt: null,
                  sourceType: 'generated',
                  selected: true,
                },
              ],
              selectedCandidateId: 'candidate-1',
              coverImageSrc: '/generated-puzzle-assets/session/cover.png',
              coverAssetId: 'asset-1',
              generationStatus: 'ready',
            },
            {
              levelId: 'puzzle-level-2',
              levelName: '灯塔',
              pictureDescription: '灯塔新关卡。',
              pictureReference: null,
              candidates: [],
              selectedCandidateId: null,
              coverImageSrc: null,
              coverAssetId: null,
              generationStatus: 'generating',
            },
          ],
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      onOpenPuzzleDetail={() => {}}
    />,
  );

  expect(html).not.toContain('生成中...');
  expect(html).not.toContain('creation-work-card__spinner');
  expect(html).toContain('继续创作《潮雾拼图草稿》');
});

test('creation hub published work uses unified list card layout', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      puzzleItems={[
        {
          workId: 'puzzle:work-1',
          profileId: 'puzzle-profile-1',
          ownerUserId: 'user-1',
          authorDisplayName: '测试作者',
          levelName: '潮雾拼图',
          summary: '一张被切成拼图的潮雾港口主视觉。',
          themeTags: ['潮雾', '港口'],
          coverImageSrc: null,
          publicationStatus: 'published',
          updatedAt: new Date('2026-04-22T10:00:00.000Z').toISOString(),
          publishedAt: new Date('2026-04-22T10:05:00.000Z').toISOString(),
          playCount: 12,
          likeCount: 0,
          publishReady: true,
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      onOpenPuzzleDetail={() => {}}
    />,
  );

  expect(html).toContain('creation-work-list');
  expect(html).toContain('platform-category-game-item');
  expect(html).toContain('creation-work-card__side-cover');
  expect(html).not.toContain('col-span-2 sm:col-span-1');
});

test('creation hub draft cards use cover background and hide updated time', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      mode="works-only"
      items={[]}
      puzzleItems={[
        {
          workId: 'puzzle:old-draft',
          profileId: 'puzzle-profile-old',
          ownerUserId: 'user-1',
          authorDisplayName: '测试作者',
          workTitle: '旧草稿',
          workDescription: '先前修改的拼图草稿。',
          levelName: '旧草稿',
          summary: '先前修改的拼图草稿。',
          themeTags: [],
          coverImageSrc: '/covers/old-draft.webp',
          publicationStatus: 'draft',
          updatedAt: '2026-05-07T00:00:00.000Z',
          publishedAt: null,
          publishReady: false,
        },
        {
          workId: 'puzzle:new-draft',
          profileId: 'puzzle-profile-new',
          ownerUserId: 'user-1',
          authorDisplayName: '测试作者',
          workTitle: '新草稿',
          workDescription: '最近修改的拼图草稿。',
          levelName: '新草稿',
          summary: '最近修改的拼图草稿。',
          themeTags: [],
          coverImageSrc: '/covers/new-draft.webp',
          publicationStatus: 'draft',
          updatedAt: '1778457601.234567Z',
          publishedAt: null,
          publishReady: false,
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      onOpenPuzzleDetail={() => {}}
    />,
  );

  const newerIndex = html.indexOf('新草稿');
  const olderIndex = html.indexOf('旧草稿');

  expect(newerIndex).toBeGreaterThanOrEqual(0);
  expect(olderIndex).toBeGreaterThanOrEqual(0);
  expect(newerIndex).toBeLessThan(olderIndex);
  expect(html).toContain(
    'class="absolute inset-0 h-full w-full object-cover" src="/covers/new-draft.webp"',
  );
  expect(html).toContain('creation-work-card__side-cover');
  expect(html).toContain('src="/covers/new-draft.webp"');
  expect(html).toContain(
    '--creation-work-card-cover-fallback:url(/creation-type-references/puzzle.webp)',
  );
  expect(html).not.toContain('1778457601.234567Z');
  expect(html).not.toContain('2026-05-07');
  expect(html).not.toContain('更新于');
  expect(html).not.toContain('最后修改');
});

test('creation hub draft cards fall back to creation type cover when cover is missing', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      mode="works-only"
      items={[]}
      puzzleItems={[
        {
          workId: 'puzzle:no-cover-draft',
          profileId: 'puzzle-profile-no-cover',
          ownerUserId: 'user-1',
          authorDisplayName: '测试作者',
          workTitle: '缺少封面的拼图草稿',
          workDescription: '没有生成封面时也需要保留图像背景。',
          levelName: '缺少封面的拼图草稿',
          summary: '没有生成封面时也需要保留图像背景。',
          themeTags: [],
          coverImageSrc: null,
          publicationStatus: 'draft',
          updatedAt: '2026-05-07T00:00:00.000Z',
          publishedAt: null,
          publishReady: false,
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      onOpenPuzzleDetail={() => {}}
    />,
  );

  expect(html).toContain('缺少封面的拼图草稿');
  expect(html).toContain(
    'class="absolute inset-0 h-full w-full object-cover" src="/creation-type-references/puzzle.webp"',
  );
  expect(html).toContain(
    '--creation-work-card-cover-fallback:url(/creation-type-references/puzzle.webp)',
  );
  expect(html).not.toContain('>封面</div>');
});

test('creation hub published card keeps publish info without fixed action text', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      mode="works-only"
      items={[]}
      puzzleItems={[
        {
          workId: 'puzzle:published-card',
          profileId: 'puzzle-profile-published',
          ownerUserId: 'user-1',
          authorDisplayName: '测试作者',
          workTitle: '统一卡片作品',
          workDescription: '作品卡仍要保留原有的积分与统计信息。',
          levelName: '统一卡片作品',
          summary: '作品卡仍要保留原有的积分与统计信息。',
          themeTags: ['潮雾'],
          coverImageSrc: '/covers/unified-card.webp',
          publicationStatus: 'published',
          updatedAt: '2026-05-07T00:00:00.000Z',
          publishedAt: '2026-05-07T00:00:00.000Z',
          playCount: 88,
          remixCount: 9,
          likeCount: 6,
          publishReady: true,
          pointIncentiveTotalPoints: 4,
          pointIncentiveClaimablePoints: 1,
        },
      ]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      onOpenPuzzleDetail={() => {}}
      onClaimPuzzlePointIncentive={() => {}}
    />,
  );

  expect(html).toContain('积分激励');
  expect(html).toContain('待领取');
  expect(html).toContain('游玩');
  expect(html).toContain('改造');
  expect(html).toContain('点赞');
  expect(html).toContain('creation-work-card__side-cover');
  expect(html).not.toContain('creation-work-card__action');
  expect(html).not.toContain('>查看详情<');
});

test('creation hub root keeps the remap theme hook without the page card shell', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      items={[]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      mode="works-only"
    />,
  );

  expect(html).toContain('platform-remap-surface');
  expect(html).not.toContain('platform-page-stage');
});

test('creation hub draft tabs use discover-style channel labels', () => {
  const html = renderToStaticMarkup(
    <CustomWorldCreationHub
      mode="works-only"
      items={[]}
      loading={false}
      error={null}
      onRetry={() => {}}
      onCreateType={noopCreateType}
      onOpenDraft={() => {}}
      onEnterPublished={() => {}}
      entryConfig={testEntryConfig}
      creationTypes={testCreationTypes}
      puzzleItems={[
        {
          workId: 'puzzle:works-tab',
          profileId: 'puzzle-profile-works-tab',
          ownerUserId: 'user-1',
          authorDisplayName: '测试作者',
          levelName: '测试草稿',
          summary: '测试草稿',
          themeTags: [],
          coverImageSrc: null,
          publicationStatus: 'draft',
          updatedAt: '2026-05-07T00:00:00.000Z',
          publishedAt: null,
          playCount: 0,
          remixCount: 0,
          likeCount: 0,
          publishReady: false,
        },
      ]}
      onOpenPuzzleDetail={() => {}}
    />,
  );

  expect(html).toContain('platform-mobile-home-channel');
  expect(html).toContain('platform-mobile-home-channel--active');
  expect(html).not.toContain('platform-tab--active');
});
