// @vitest-environment jsdom

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

import type { BigFishSessionSnapshotResponse } from '../../../packages/shared/src/contracts/bigFish';
import { BigFishResultView } from './BigFishResultView';

vi.mock('../ResolvedAssetImage', () => ({
  ResolvedAssetImage: ({
    src,
    alt,
    className,
  }: {
    src?: string | null;
    alt?: string;
    className?: string;
  }) => (src ? <img src={src} alt={alt} className={className} /> : null),
}));

function findNearestClassName(
  element: HTMLElement,
  classNamePart: string,
): HTMLElement | null {
  let current: HTMLElement | null = element;

  while (current) {
    if (current.className.includes(classNamePart)) {
      return current;
    }

    current = current.parentElement;
  }

  return null;
}

function createSession(): BigFishSessionSnapshotResponse {
  return {
    sessionId: 'big-fish-session-1',
    currentTurn: 2,
    progressPercent: 88,
    stage: 'asset_refining',
    anchorPack: {
      gameplayPromise: {
        key: 'gameplayPromise',
        label: '玩法承诺',
        value: '弱小逆袭',
        status: 'confirmed',
      },
      ecologyVisualTheme: {
        key: 'ecologyVisualTheme',
        label: '生态与视觉母题',
        value: '深海谜境',
        status: 'confirmed',
      },
      growthLadder: {
        key: 'growthLadder',
        label: '成长阶梯',
        value: '8 级进化',
        status: 'confirmed',
      },
      riskTempo: {
        key: 'riskTempo',
        label: '风险节奏',
        value: '平衡',
        status: 'confirmed',
      },
    },
    draft: {
      title: '深海谜境',
      subtitle: '逐级吞噬成长',
      coreFun: '弱小逆袭',
      ecologyTheme: '深海谜境',
      levels: [
        {
          level: 1,
          name: '荧潮幼体',
          oneLineFantasy: '在深海荧光裂谷中寻找第一个同伴。',
          textDescription:
            '荧潮幼体是深海谜境里的初始个体，体型最小，会先谨慎试探并寻找可吞噬目标。',
          silhouetteDirection: '圆润鱼苗',
          sizeRatio: 1,
          visualDescription:
            '带有浅青色荧光纹路的小型鱼苗，轮廓圆润，呈现弱小但灵动的开局形象。',
          visualPromptSeed: '深海荧光幼体',
          idleMotionDescription:
            '待机时轻微漂浮，尾鳍做小幅摆动，像是在观察周围海流。',
          moveMotionDescription:
            '移动时身体前探，尾鳍清晰摆尾推进，呈现连续游动感。',
          motionPromptSeed: '轻微摆尾',
          mergeSourceLevel: null,
          preyWindow: [1],
          threatWindow: [2],
          isFinalLevel: false,
        },
      ],
      background: {
        theme: '深海谜境',
        colorMood: '深蓝与青绿',
        foregroundHints: '漂浮微粒',
        midgroundComposition: '中央留白',
        backgroundDepth: '深海纵深',
        safePlayAreaHint: '中央 70%',
        spawnEdgeHint: '四周边缘',
        backgroundPromptSeed: '深海谜境背景',
      },
      runtimeParams: {
        levelCount: 1,
        mergeCountPerUpgrade: 3,
        spawnTargetCount: 12,
        leaderMoveSpeed: 160,
        followerCatchUpSpeed: 120,
        offscreenCullSeconds: 3,
        preySpawnDeltaLevels: [1],
        threatSpawnDeltaLevels: [1],
        winLevel: 1,
      },
    },
    assetSlots: [
      {
        slotId: 'big-fish-asset-level-main',
        assetKind: 'level_main_image',
        level: 1,
        motionKey: null,
        status: 'ready',
        assetUrl:
          '/generated-big-fish-assets/big-fish-session-1/level-main-image/level-1/image.png',
        promptSnapshot: '深海荧光幼体',
        updatedAt: '2026-04-23T10:00:00.000Z',
      },
      {
        slotId: 'big-fish-asset-background',
        assetKind: 'stage_background',
        level: null,
        motionKey: null,
        status: 'ready',
        assetUrl:
          '/generated-big-fish-assets/big-fish-session-1/stage-background/image.png',
        promptSnapshot: '深海谜境背景',
        updatedAt: '2026-04-23T10:00:00.000Z',
      },
    ],
    assetCoverage: {
      levelMainImageReadyCount: 1,
      levelMotionReadyCount: 0,
      backgroundReady: true,
      requiredLevelCount: 1,
      publishReady: false,
      blockers: ['还缺少 2 个基础动作'],
    },
    messages: [],
    lastAssistantReply: '主图占位图已生成。',
    publishReady: false,
    updatedAt: '2026-04-23T10:00:00.000Z',
  };
}

describe('BigFishResultView', () => {
  test('uses PlatformEmptyState chrome when draft is missing', () => {
    render(
      <BigFishResultView
        session={{
          ...createSession(),
          draft: null,
        }}
        onBack={() => {}}
        onExecuteAction={() => {}}
        onStartTestRun={() => {}}
      />,
    );

    const emptyState = screen.getByText('还没有可编辑的玩法草稿');

    expect(emptyState.className).toContain('platform-empty-state');
    expect(emptyState.className).toContain('bg-white/74');
    expect(emptyState.className).toContain('text-[var(--platform-text-base)]');
  });

  test('renders generated formal previews with accurate status copy', () => {
    render(
      <BigFishResultView
        session={createSession()}
        onBack={() => {}}
        onExecuteAction={() => {}}
        onStartTestRun={() => {}}
      />,
    );

    expect(screen.getByText('主图 已生成')).toBeTruthy();
    const levelImage = screen.getByAltText('荧潮幼体');
    expect(levelImage).toBeTruthy();
    const levelFrame = findNearestClassName(levelImage, 'relative');
    expect(levelFrame?.className).toContain('aspect-square');
    expect(levelFrame?.className).toContain('radial-gradient');
    expect(levelFrame?.className).toContain('linear-gradient');
    expect(levelFrame?.className).not.toContain(
      'bg-[var(--platform-subpanel-fill)]',
    );
    const backgroundImage = screen.getByAltText('深海谜境 场地背景');
    expect(backgroundImage).toBeTruthy();
    const backgroundFrame = findNearestClassName(backgroundImage, 'relative');
    expect(backgroundFrame?.className).toContain('aspect-[9/16]');
    expect(backgroundFrame?.className).toContain('radial-gradient');
    expect(backgroundFrame?.className).toContain('linear-gradient');
    expect(backgroundFrame?.className).not.toContain(
      'bg-[var(--platform-subpanel-fill)]',
    );
    expect(
      findNearestClassName(screen.getByText('荧潮幼体'), 'platform-subpanel')
        ?.className,
    ).toContain('rounded-[1.5rem]');
    for (const label of ['猎物 1', '威胁 2', '主图 已生成']) {
      const badge = screen.getByText(label);

      expect(badge.className).toContain('rounded-full');
      expect(badge.className).toContain(
        'bg-[var(--platform-subpanel-fill)]',
      );
    }
    expect(
      findNearestClassName(screen.getByText('场地背景'), 'platform-subpanel')
        ?.className,
    ).toContain('rounded-[1.5rem]');
    expect(
      findNearestClassName(screen.getByText('发布校验'), 'platform-subpanel')
        ?.className,
    ).toContain('rounded-[1.5rem]');
    const blockerStatus = findNearestClassName(
      screen.getByText('还缺少 2 个基础动作'),
      'platform-status-message',
    );
    expect(blockerStatus?.className).toContain('platform-status-message');
    expect(blockerStatus?.className).toContain(
      'border-[var(--platform-warm-border)]',
    );
    expect(blockerStatus?.className).toContain(
      'bg-[var(--platform-warm-bg)]',
    );
    for (const label of ['弱小逆袭', '深海谜境', '1 级']) {
      const badge = screen
        .getAllByText(label)
        .find((element) => element.className.includes('inline-flex'));

      if (!badge) {
        throw new Error(`missing hero badge for ${label}`);
      }
      expect(badge.className).toContain('inline-flex');
      expect(badge.className).toContain('rounded-full');
      expect(badge.className).toContain('border-transparent');
    }
  });

  test('uses platform pill badge for ready publish status', () => {
    render(
      <BigFishResultView
        session={{
          ...createSession(),
          publishReady: true,
          assetCoverage: {
            levelMainImageReadyCount: 1,
            levelMotionReadyCount: 2,
            backgroundReady: true,
            requiredLevelCount: 1,
            publishReady: true,
            blockers: [],
          },
        }}
        onBack={() => {}}
        onExecuteAction={() => {}}
        onStartTestRun={() => {}}
      />,
    );

    const readyBadge = screen.getByText('已达到发布条件');

    expect(readyBadge.tagName).toBe('SPAN');
    expect(readyBadge.className).toContain('rounded-full');
    expect(readyBadge.className).toContain('border-emerald-200');
    expect(readyBadge.className).toContain('bg-emerald-50');
  });

  test('uses level descriptions as default prompt content in asset studio', () => {
    render(
      <BigFishResultView
        session={createSession()}
        onBack={() => {}}
        onExecuteAction={() => {}}
        onStartTestRun={() => {}}
      />,
    );

    fireEvent.click(screen.getByRole('button', { name: '主图' }));
    expect(screen.getByText('PROMPT').className).toContain('tracking-[0.18em]');
    const studioPreviewFrame = findNearestClassName(
      screen.getByAltText('Lv.1 主图工坊'),
      'relative',
    );
    expect(studioPreviewFrame?.className).toContain('aspect-[9/5]');
    expect(studioPreviewFrame?.className).toContain('border-dashed');
    expect(studioPreviewFrame?.className).toContain('bg-cyan-50/40');
    expect(studioPreviewFrame?.className).not.toContain(
      'bg-[var(--platform-subpanel-fill)]',
    );
    expect(
      screen.getByText(
        '带有浅青色荧光纹路的小型鱼苗，轮廓圆润，呈现弱小但灵动的开局形象。',
      ),
    ).toBeTruthy();
    fireEvent.click(screen.getByRole('button', { name: '关闭' }));

    fireEvent.click(screen.getByRole('button', { name: '待机' }));
    expect(
      screen.getByText('待机时轻微漂浮，尾鳍做小幅摆动，像是在观察周围海流。'),
    ).toBeTruthy();
    fireEvent.click(screen.getByRole('button', { name: '关闭' }));

    fireEvent.click(screen.getByRole('button', { name: '移动' }));
    expect(
      screen.getByText('移动时身体前探，尾鳍清晰摆尾推进，呈现连续游动感。'),
    ).toBeTruthy();
  });

  test('uses PlatformActionButton chrome for white surface asset actions', () => {
    render(
      <BigFishResultView
        session={createSession()}
        onBack={() => {}}
        onExecuteAction={() => {}}
        onStartTestRun={() => {}}
      />,
    );

    for (const actionName of ['主图', '待机', '移动', '生成背景']) {
      const action = screen.getByRole('button', { name: actionName });

      expect(action.className).toContain('platform-button');
      expect(action.className).toContain('rounded-full');
    }

    fireEvent.click(screen.getByRole('button', { name: '主图' }));

    for (const actionName of ['关闭', '生成并应用正式图']) {
      const action = screen.getByRole('button', { name: actionName });

      expect(action.className).toContain('platform-button');
      expect(action.className).toContain('rounded-full');
    }
  });

  test('reuses shared hero action chrome for top-level result actions', () => {
    render(
      <BigFishResultView
        session={createSession()}
        onBack={() => {}}
        onExecuteAction={() => {}}
        onStartTestRun={() => {}}
      />,
    );

    expect(screen.getByRole('button', { name: '返回' }).className).toContain(
      'rounded-full',
    );
    expect(screen.getByRole('button', { name: '测试' }).className).toContain(
      'platform-action-button--editor-dark',
    );
    expect(screen.getByRole('button', { name: '发布' }).className).toContain(
      'platform-action-button--editor-dark',
    );
  });

  test('shows publish failures in a dismissible modal', () => {
    const onDismissError = vi.fn();

    render(
      <BigFishResultView
        session={createSession()}
        error="big_fish 发布校验未通过：还缺少 16 个基础动作"
        onBack={() => {}}
        onDismissError={onDismissError}
        onExecuteAction={() => {}}
        onStartTestRun={() => {}}
      />,
    );

    expect(screen.getByRole('dialog')).toBeTruthy();
    expect(screen.getByText('发布失败')).toBeTruthy();
    expect(
      screen.getByText('big_fish 发布校验未通过：还缺少 16 个基础动作'),
    ).toBeTruthy();
    const iconBadge = screen.getByLabelText('发布失败提示');
    expect(iconBadge.className).toContain(
      'bg-[var(--platform-button-danger-fill)]',
    );
    expect(iconBadge.className).toContain(
      'text-[var(--platform-button-danger-text)]',
    );

    fireEvent.click(screen.getByRole('button', { name: '知道了' }));
    expect(onDismissError).toHaveBeenCalledTimes(1);
  });

  test('shows published state and prevents duplicate publish clicks', () => {
    const onExecuteAction = vi.fn();

    render(
      <BigFishResultView
        session={{
          ...createSession(),
          stage: 'published',
          publishReady: true,
          assetCoverage: {
            levelMainImageReadyCount: 1,
            levelMotionReadyCount: 2,
            backgroundReady: true,
            requiredLevelCount: 1,
            publishReady: true,
            blockers: [],
          },
        }}
        onBack={() => {}}
        onExecuteAction={onExecuteAction}
        onStartTestRun={() => {}}
      />,
    );

    const publishedButton = screen.getByRole('button', { name: '已发布' });
    expect((publishedButton as HTMLButtonElement).disabled).toBe(true);
    expect(screen.getAllByText('已发布').length).toBeGreaterThan(0);
    const publishedBadge = screen
      .getAllByText('已发布')
      .find((element) => element.tagName === 'SPAN');
    expect(publishedBadge?.className).toContain('border-emerald-200');
    expect(publishedBadge?.className).toContain('bg-emerald-50');
    fireEvent.click(publishedButton);
    expect(onExecuteAction).not.toHaveBeenCalled();
  });
});
