import { Loader2 } from 'lucide-react';
import { AnimatePresence, motion } from 'motion/react';
import {
  type Dispatch,
  lazy,
  type SetStateAction,
  Suspense,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';

import type { PublicUserSummary } from '../../../packages/shared/src/contracts/auth';
import type {
  BarkBattleConfigEditorPayload,
  BarkBattleDraftConfig,
  BarkBattlePublishedConfig,
  BarkBattleWorkSummary,
} from '../../../packages/shared/src/contracts/barkBattle';
import type {
  BigFishRuntimeSnapshotResponse,
  BigFishSessionSnapshotResponse,
  ExecuteBigFishActionRequest,
  SendBigFishMessageRequest,
  SubmitBigFishInputRequest,
} from '../../../packages/shared/src/contracts/bigFish';
import type { BigFishWorkSummary } from '../../../packages/shared/src/contracts/bigFishWorkSummary';
import type {
  CreativeAgentSessionSnapshot,
  CreativeAgentSseEvent,
  CreativeDraftEditResult,
  StreamCreativeAgentMessageRequest,
} from '../../../packages/shared/src/contracts/creativeAgent';
import type { CustomWorldWorkSummary } from '../../../packages/shared/src/contracts/customWorldWorkSummary';
import type {
  BabyObjectMatchDraft,
  CreateBabyObjectMatchDraftRequest,
} from '../../../packages/shared/src/contracts/edutainmentBabyObject';
import type { JumpHopWorkSummaryResponse } from '../../../packages/shared/src/contracts/jumpHop';
import type {
  CreateMatch3DSessionRequest,
  ExecuteMatch3DActionRequest,
  Match3DActionResponse,
  Match3DAgentSessionSnapshot,
  Match3DSessionResponse,
  SendMatch3DMessageRequest,
} from '../../../packages/shared/src/contracts/match3dAgent';
import type { Match3DRunSnapshot } from '../../../packages/shared/src/contracts/match3dRuntime';
import type {
  Match3DWorkProfile,
  Match3DWorkSummary,
} from '../../../packages/shared/src/contracts/match3dWorks';
import type {
  PuzzleAgentActionRequest,
  PuzzleAgentOperationRecord,
} from '../../../packages/shared/src/contracts/puzzleAgentActions';
import type {
  PuzzleDraftLevel,
  PuzzleResultDraft,
} from '../../../packages/shared/src/contracts/puzzleAgentDraft';
import type {
  CreatePuzzleAgentSessionRequest,
  PuzzleAgentSessionSnapshot,
  SendPuzzleAgentMessageRequest,
} from '../../../packages/shared/src/contracts/puzzleAgentSession';
import type { PuzzleCreativeTemplateSelection } from '../../../packages/shared/src/contracts/puzzleCreativeTemplate';
import type {
  PuzzleRunSnapshot,
  PuzzleRuntimePropKind,
  SubmitPuzzleLeaderboardRequest,
} from '../../../packages/shared/src/contracts/puzzleRuntimeSession';
import type { PuzzleWorkSummary } from '../../../packages/shared/src/contracts/puzzleWorkSummary';
import type {
  CustomWorldGalleryCard,
  CustomWorldLibraryEntry,
  ProfileDashboardSummary,
  ProfilePlayedWorkSummary,
  ProfilePlayStatsResponse,
  ProfileSaveArchiveResumeResponse,
  ProfileSaveArchiveSummary,
} from '../../../packages/shared/src/contracts/runtime';
import type {
  CreateSquareHoleSessionRequest,
  ExecuteSquareHoleActionRequest,
  SendSquareHoleMessageRequest,
  SquareHoleActionResponse,
  SquareHoleSessionResponse,
  SquareHoleSessionSnapshot,
} from '../../../packages/shared/src/contracts/squareHoleAgent';
import type { SquareHoleRunSnapshot } from '../../../packages/shared/src/contracts/squareHoleRuntime';
import type {
  SquareHoleWorkProfile,
  SquareHoleWorkSummary,
} from '../../../packages/shared/src/contracts/squareHoleWorks';
import type {
  CreateVisualNovelSessionRequest,
  ExecuteVisualNovelAgentActionRequest,
  SendVisualNovelMessageRequest,
  VisualNovelAgentSessionSnapshot,
  VisualNovelResultDraft,
  VisualNovelRunSnapshot,
  VisualNovelRuntimeActionRequest,
  VisualNovelSessionResponse,
  VisualNovelWorkDetail,
  VisualNovelWorkSummary,
} from '../../../packages/shared/src/contracts/visualNovel';
import type { WoodenFishWorkSummaryResponse } from '../../../packages/shared/src/contracts/woodenFish';
import { buildCustomWorldPlayableCharacters } from '../../data/characterPresets';
import {
  buildPublicWorkStagePath,
  pushAppHistoryPath,
} from '../../routing/appPageRoutes';
import { resolveWorkNotFoundRecoveryAction } from '../../routing/runtimeNotFoundRecovery';
import {
  ApiClientError,
  BACKGROUND_AUTH_REQUEST_OPTIONS,
  getStoredAccessToken,
} from '../../services/apiClient';
import {
  ensureRuntimeGuestToken,
  getPublicAuthUserByCode,
  getPublicAuthUserById,
} from '../../services/authService';
import {
  createBarkBattleDraft,
  listBarkBattleGallery,
  listBarkBattleWorks,
  publishBarkBattleWork,
  updateBarkBattleDraftConfig,
} from '../../services/bark-battle-creation';
import { startBarkBattleRun } from '../../services/bark-battle-runtime';
import {
  createBigFishCreationSession,
  executeBigFishCreationAction,
  getBigFishCreationSession,
  streamBigFishCreationMessage,
} from '../../services/big-fish-creation';
import {
  likeBigFishGalleryWork,
  listBigFishGallery,
  remixBigFishGalleryWork,
} from '../../services/big-fish-gallery';
import {
  recordBigFishPlay,
  startBigFishRun as startBigFishRuntimeRun,
  submitBigFishInput as submitBigFishRuntimeInput,
} from '../../services/big-fish-runtime';
import {
  deleteBigFishWork,
  listBigFishWorks,
} from '../../services/big-fish-works';
import {
  type CreationEntryConfig,
  fetchCreationEntryConfig,
} from '../../services/creationEntryConfigService';
import {
  clearCreationUrlState,
  readCreationUrlState,
  writeCreationUrlState,
} from '../../services/creationUrlState';
import {
  cancelCreativeAgentSession,
  confirmCreativePuzzleTemplate,
  createCreativeAgentSession,
  streamCreativeAgentMessage,
  streamCreativeDraftEdit,
} from '../../services/creative-agent';
import {
  readCustomWorldAgentUiState,
  shouldRestoreCustomWorldAgentUiState,
} from '../../services/customWorldAgentUiState';
import {
  createBabyObjectMatchDraft,
  deleteLocalBabyObjectMatchDraft,
  hasBabyObjectMatchPlaceholderAssets,
  listLocalBabyObjectMatchDrafts,
  publishBabyObjectMatchWork,
  regenerateBabyObjectMatchDraftAssets,
  saveBabyObjectMatchDraft,
} from '../../services/edutainment-baby-object';
import {
  jumpHopClient,
  type JumpHopGalleryCardResponse,
  type JumpHopRunResponse,
  type JumpHopSessionResponse,
  type JumpHopSessionSnapshotResponse,
  JumpHopWorkProfileResponse,
  JumpHopWorkspaceCreateRequest,
} from '../../services/jump-hop/jumpHopClient';
import { match3dCreationClient } from '../../services/match3d-creation';
import { createServerMatch3DRuntimeAdapter } from '../../services/match3d-runtime';
import {
  deleteMatch3DWork,
  getMatch3DWorkDetail,
  listMatch3DGallery,
  listMatch3DWorks,
} from '../../services/match3d-works';
import {
  mergeMatch3DGeneratedItemAssetsForRuntime,
  normalizeMatch3DGeneratedItemAssetsForRuntime,
  preloadMatch3DGeneratedRuntimeAssets,
} from '../../services/match3dGeneratedModelCache';
import {
  buildBabyObjectMatchGenerationAnchorEntries,
  buildBigFishGenerationAnchorEntries,
  buildJumpHopGenerationAnchorEntries,
  buildMatch3DGenerationAnchorEntries,
  buildMiniGameDraftGenerationProgress,
  buildPuzzleGenerationAnchorEntries,
  buildSquareHoleGenerationAnchorEntries,
  buildWoodenFishGenerationAnchorEntries,
  createMiniGameDraftGenerationState,
  type MiniGameDraftGenerationState,
  resolveMiniGameDraftGenerationStartedAtMs,
} from '../../services/miniGameDraftGenerationProgress';
import { getPlatformProfileDashboard } from '../../services/platform-entry/platformProfileClient';
import {
  buildBabyObjectMatchPublicWorkCode,
  buildBarkBattlePublicWorkCode,
  buildBigFishPublicWorkCode,
  buildJumpHopPublicWorkCode,
  buildMatch3DPublicWorkCode,
  buildPuzzlePublicWorkCode,
  buildSquareHolePublicWorkCode,
  buildVisualNovelPublicWorkCode,
  buildWoodenFishPublicWorkCode,
  isSameBabyObjectMatchPublicWorkCode,
  isSameBarkBattlePublicWorkCode,
  isSameBigFishPublicWorkCode,
  isSameJumpHopPublicWorkCode,
  isSameMatch3DPublicWorkCode,
  isSamePuzzlePublicWorkCode,
  isSameSquareHolePublicWorkCode,
  isSameVisualNovelPublicWorkCode,
  isSameWoodenFishPublicWorkCode,
} from '../../services/publicWorkCode';
import {
  createPuzzleAgentSession,
  executePuzzleAgentAction,
  getPuzzleAgentSession,
  streamPuzzleAgentMessage,
} from '../../services/puzzle-agent';
import {
  getPuzzleGalleryDetail,
  likePuzzleGalleryWork,
  listPuzzleGallery,
  remixPuzzleGalleryWork,
} from '../../services/puzzle-gallery';
import {
  generatePuzzleOnboardingWork,
  savePuzzleOnboardingWork,
} from '../../services/puzzle-onboarding';
import {
  advancePuzzleNextLevel,
  startPuzzleRun,
  submitPuzzleLeaderboard,
} from '../../services/puzzle-runtime';
import {
  advanceLocalPuzzleLevel,
  applyLocalPuzzleFreezeTime,
  dragLocalPuzzlePiece,
  extendLocalPuzzleTime,
  isLocalPuzzleRun,
  refreshLocalPuzzleTimer,
  resolvePuzzleRestartLevelId,
  restartLocalPuzzleLevel,
  setLocalPuzzlePaused,
  startLocalPuzzleRun,
  submitLocalPuzzleLeaderboard,
  swapLocalPuzzlePieces,
} from '../../services/puzzle-runtime/puzzleLocalRuntime';
import {
  claimPuzzleWorkPointIncentive,
  deletePuzzleWork,
  listPuzzleWorks,
  updatePuzzleWork,
} from '../../services/puzzle-works';
import {
  clearPuzzleRuntimeUrlState,
  type PuzzleRuntimeUrlState,
  readPuzzleRuntimeUrlState,
  writePuzzleRuntimeUrlState,
} from '../../services/puzzleRuntimeUrlState';
import { deleteRpgCreationAgentSession } from '../../services/rpg-creation';
import { rpgCreationPreviewAdapter } from '../../services/rpg-creation/rpgCreationPreviewAdapter';
import {
  deleteRpgEntryWorldProfile,
  getRpgEntryWorldGalleryDetailByCode,
  likeRpgEntryWorldGallery,
  recordRpgEntryWorldGalleryPlay,
  remixRpgEntryWorldGallery,
} from '../../services/rpg-entry/rpgEntryLibraryClient';
import {
  getRpgProfilePlayStats,
  submitRpgProfileFeedback,
} from '../../services/rpg-entry/rpgProfileClient';
import { requestRpgRuntimeJson } from '../../services/rpg-runtime/rpgRuntimeRequest';
import { squareHoleCreationClient } from '../../services/square-hole-creation';
import {
  dropSquareHoleShape,
  finishSquareHoleTimeUp,
  restartSquareHoleRun,
  startSquareHoleRun,
  stopSquareHoleRun,
} from '../../services/square-hole-runtime';
import {
  deleteSquareHoleWork,
  getSquareHoleWorkDetail,
  listSquareHoleGallery,
  listSquareHoleWorks,
} from '../../services/square-hole-works';
import {
  compileVisualNovelWorkProfile,
  createVisualNovelSession,
  executeVisualNovelAction,
  getVisualNovelSession,
  streamVisualNovelMessage,
} from '../../services/visual-novel-creation';
import {
  listVisualNovelGallery,
  startVisualNovelRun,
  streamVisualNovelRuntimeAction,
} from '../../services/visual-novel-runtime';
import {
  deleteVisualNovelWork,
  getVisualNovelWorkDetail,
  listVisualNovelWorks,
  publishVisualNovelWork,
  updateVisualNovelWork,
} from '../../services/visual-novel-works';
import {
  woodenFishClient,
  type WoodenFishGalleryCardResponse,
  type WoodenFishRunResponse,
  type WoodenFishSessionResponse,
  type WoodenFishSessionSnapshotResponse,
  type WoodenFishWorkProfileResponse,
  type WoodenFishWorkspaceCreateRequest,
} from '../../services/wooden-fish/woodenFishClient';
import type { CustomWorldProfile } from '../../types';
import { useAuthUi } from '../auth/AuthUiContext';
import { PublishShareModal } from '../common/PublishShareModal';
import type { PublishShareModalPayload } from '../common/publishShareModalModel';
import { UnifiedModal } from '../common/UnifiedModal';
import { resolveCreativeAgentTargetSelectionStage } from '../creative-agent/creativeAgentViewModel';
import {
  buildCreationWorkShelfItems,
  type CreationWorkShelfItem,
  isPersistedBarkBattleDraftGenerating,
  isPersistedPuzzleDraftGenerating,
  resolvePuzzleWorkCoverImageSrc,
} from '../custom-world-home/creationWorkShelf';
import {
  buildPlatformRecommendFeedEntries,
  selectAdjacentPlatformRecommendEntry,
} from '../rpg-entry/rpgEntryPublicGalleryViewModel';
import {
  isEdutainmentGalleryEntry,
  mapBabyObjectMatchDraftToPlatformGalleryCard,
  mapBarkBattleWorkToPlatformGalleryCard,
  mapPuzzleWorkToPlatformGalleryCard,
  type PlatformPublicGalleryCard,
  resolvePlatformPublicWorkCode,
} from '../rpg-entry/rpgEntryWorldPresentation';
import { useRpgCreationAgentOperationPolling } from '../rpg-entry/useRpgCreationAgentOperationPolling';
import { useRpgCreationEnterWorld } from '../rpg-entry/useRpgCreationEnterWorld';
import { useRpgCreationResultAutosave } from '../rpg-entry/useRpgCreationResultAutosave';
import { useRpgCreationSessionController } from '../rpg-entry/useRpgCreationSessionController';
import { UnifiedCreationPage } from '../unified-creation/UnifiedCreationPage';
import {
  getUnifiedCreationSpec,
  type UnifiedCreationPlayId,
} from '../unified-creation/unifiedCreationSpecs';
import {
  buildVisualNovelEntryGenerationAnchorEntries,
  buildVisualNovelEntryGenerationProgress,
  type VisualNovelEntryFormPayload,
} from '../visual-novel-creation/visualNovelEntryGeneration';
import { createMockVisualNovelRunFromDraft } from '../visual-novel-runtime/visualNovelMockData';
import {
  buildBarkBattleDraftConfigFromWorkSummary,
  buildBarkBattlePublishedConfigFromDraft,
  buildBarkBattlePublishedConfigFromWork,
  buildBarkBattlePublishSnapshot,
  buildBarkBattleWorkSummaryFromDraft,
  mergeBarkBattlePublishedConfigAssets,
  mergeBarkBattleWorksByWorkId,
  mergeBarkBattleWorkSummary,
  resolveBarkBattleDraftGenerationStatus,
  shouldPreserveLocalBarkBattleWorkOnRefresh,
} from './barkBattleWorkCache';
import {
  type PlatformCreationLaunchTarget,
  resolvePlatformCreationLaunchIntent,
} from './platformCreationLaunchModel';
import {
  buildBabyObjectMatchCreationUrlState,
  buildBarkBattleCreationUrlState,
  buildBigFishCreationUrlState,
  buildJumpHopCreationUrlState,
  buildMatch3DCreationUrlState,
  buildPuzzleCreationUrlState,
  buildPuzzleDraftRuntimeUrlState,
  buildPuzzlePublishedRuntimeUrlState,
  buildPuzzleRuntimeUrlStateKey,
  buildSquareHoleCreationUrlState,
  buildVisualNovelCreationUrlState,
  buildWoodenFishCreationUrlState,
  hasPuzzleRuntimeUrlStateValue,
  matchesBabyObjectMatchCreationUrlRestoreTarget,
  matchesBarkBattleCreationUrlRestoreTarget,
  matchesBigFishCreationUrlRestoreTarget,
  matchesSessionProfileWorkCreationUrlRestoreTarget,
  matchesVisualNovelCreationUrlRestoreTarget,
  normalizeCreationUrlValue,
  resolveCreationUrlRestoreTarget,
  resolveInitialCreationUrlRestoreDecision,
  resolveJumpHopCreationUrlRestoreStage,
  resolveWoodenFishCreationUrlRestoreStage,
} from './platformCreationUrlStateModel';
import { resolvePlatformCreationWorkDeleteConfirmationModel } from './platformCreationWorkDeleteFlow';
import {
  buildPlatformErrorDialogDismissKey,
  buildPlatformTaskCompletionDialogDismissKey,
  formatPlatformDialogSource,
  isBackgroundGenerationStillRunningMessage,
  PLATFORM_TASK_COMPLETION_MESSAGE,
  type PlatformDialogCandidate,
  type PlatformErrorDialogState,
  type PlatformTaskCompletionDialogState,
  type PlatformTaskFailureDialogState,
  resolveActivePlatformDialog,
  resolvePlatformErrorDialog,
} from './platformDialogStateModel';
import {
  buildCreationWorkShelfRuntimeState,
  buildDraftCompletionDialogSource,
  buildDraftFailedShelfSummary,
  buildPendingBarkBattleWorks,
  buildPendingBigFishWorks,
  buildPendingJumpHopWorks,
  buildPendingMatch3DWorks,
  buildPendingPuzzleWorks,
  buildPendingSquareHoleWorks,
  buildPendingVisualNovelWorks,
  buildPendingWoodenFishWorks,
  collectDraftNoticeKeys,
  collectVisibleDraftNoticeKeys,
  createPendingDraftShelfState,
  type DraftGenerationNoticeMap,
  type DraftGenerationNoticeStatus,
  getDraftGenerationNotice,
  getGenerationNoticeShelfKeys,
  hasDraftGenerationNoticeStatus,
  hasUnreadDraftGenerationUpdates,
  hasUnreadReadyDraftGenerationNotice,
  isPersistedDraftFailed,
  isPersistedDraftGenerating,
  mergeBigFishWorkSummary,
  mergePuzzleWorkSummary,
  normalizeDraftNoticeId,
  type PendingDraftShelfKind,
  type PendingDraftShelfMap,
  type PendingDraftShelfMetadata,
} from './platformDraftGenerationShelfModel';
import {
  canExposePublicWork,
  EDUTAINMENT_HIDDEN_MESSAGE,
} from './platformEdutainmentVisibility';
import { PlatformEntryCreationTypeModal } from './PlatformEntryCreationTypeModal';
import type { PlatformCreationTypeId } from './platformEntryCreationTypes';
import {
  derivePlatformCreationTypes,
  isPlatformCreationTypeOpen,
  isPlatformCreationTypeVisible,
} from './platformEntryCreationTypes';
import {
  PuzzleOnboardingLoginOverlay,
  type PuzzleOnboardingPhase,
  PuzzleOnboardingView,
} from './PlatformEntryFlowShellImpl/PuzzleOnboardingView';
import {
  PlatformEntryHomeView,
  type PlatformHomeTab,
} from './PlatformEntryHomeView';
import { usePlatformDesktopLayout } from './platformEntryResponsive';
import {
  buildCreationHubFallbackItems,
  resolveRpgCreationErrorMessage,
} from './platformEntryShared';
import type {
  PlatformEntryFlowShellProps,
  SelectionStage,
} from './platformEntryTypes';
import { PlatformEntryWorldDetailView } from './PlatformEntryWorldDetailView';
import { PlatformErrorDialog } from './PlatformErrorDialog';
import { PlatformFeedbackView } from './PlatformFeedbackView';
import { resolvePlatformGenerationProgressTickDecision } from './platformGenerationProgressTickModel';
import {
  buildMatch3DProfileFromSession,
  hasMatch3DRuntimeAsset,
  hasMatch3DRuntimeBackgroundAsset,
  mapMatch3DWorksForRuntimeUi,
  mapMatch3DWorkToPublicWorkDetail,
  mapPublicWorkDetailToMatch3DWork,
  normalizeMatch3DWorkForRuntimeUi,
  promoteMatch3DGeneratedBackgroundAsset,
  resolveActiveMatch3DRuntimeProfile,
  resolveMatch3DRuntimeBackgroundImageSrc,
  resolveMatch3DRuntimeGeneratedBackgroundAsset,
  resolveMatch3DRuntimeGeneratedItemAssets,
} from './platformMatch3DRuntimeProfile';
import {
  createFailedMiniGameDraftGenerationStateForRestoredDraft,
  createMiniGameDraftGenerationStateForRestoredDraft,
  createPuzzleDraftGenerationStateFromPayload,
  isMiniGameDraftGenerating,
  isMiniGameDraftReady,
  mergeMatch3DGeneratedAssetsIntoGenerationState,
  mergePuzzleSessionProgressIntoGenerationState,
  rebaseMiniGameDraftBackgroundCompileTaskForDisplay,
  rebaseMiniGameDraftGenerationStateForDisplay,
  resolveFinishedMiniGameDraftGenerationState,
} from './platformMiniGameDraftGenerationStateModel';
import {
  buildMatch3DFormPayloadFromSession,
  buildMatch3DFormPayloadFromWork,
  buildPendingMatch3DDraftMetadata,
  buildPendingPuzzleDraftMetadata,
  buildPuzzleCompileActionFromFormPayload,
  buildPuzzleFormPayloadFromAction,
  buildPuzzleFormPayloadFromSession,
  buildPuzzleFormPayloadFromWork,
  buildPuzzleWorkUpdatePayloadFromDraft,
  isEmptyPuzzleFormOnlyDraft,
  isPuzzleFormOnlyDraft,
} from './platformMiniGameDraftPayloadModel';
import {
  buildJumpHopPendingSession,
  buildPuzzleRuntimeWorkFromSession,
  buildSquareHoleProfileFromSession,
  buildVisualNovelSessionFromWorkDetail,
  buildWoodenFishPendingSession,
  buildWoodenFishSessionFromWorkDetail,
} from './platformMiniGameSessionMappingModel';
import { resolvePlatformPlayedWorkOpenIntent } from './platformPlayedWorkOpenModel';
import {
  adjustProfileDashboardWalletBalance,
  reconcileProfileWalletLocalDeltaWithServerDashboard,
  resolveProfileWalletBalance,
} from './platformProfileWalletDeltaModel';
import {
  type PlatformPublicCodeSearchStep,
  resolvePlatformPublicCodeSearchPlan,
} from './platformPublicCodeSearchModel';
import {
  buildPlatformPublicGalleryFeeds,
  getPlatformPublicGalleryEntryKey,
  getPlatformRecommendRuntimeKind,
  isSamePlatformPublicGalleryEntry,
  type RecommendRuntimeKind,
  resolvePlatformRecommendRuntimeAutoStartDecision,
  resolvePlatformRecommendRuntimeStartIntent,
} from './platformPublicGalleryFlow';
import {
  mapBarkBattleWorkToPublicWorkDetail,
  mapBigFishWorkToPublicWorkDetail,
  mapJumpHopWorkToPublicWorkDetail,
  mapPuzzleWorkToPublicWorkDetail,
  mapRpgGalleryCardToPublicWorkDetail,
  mapSquareHoleWorkToPublicWorkDetail,
  mapVisualNovelWorkToPublicWorkDetail,
  mapWoodenFishWorkToPublicWorkDetail,
  resolveActivePlatformPublicWorkAuthorEntry,
  resolvePlatformPublicWorkActionMode,
  resolvePlatformPublicWorkDetailOpenDecision,
  resolvePlatformPublicWorkDetailOpenStrategy,
  resolvePlatformPublicWorkEditIntent,
  resolvePlatformPublicWorkLikeIntent,
  resolvePlatformPublicWorkRemixIntent,
  resolvePlatformPublicWorkStartIntent,
  resolveVisiblePuzzleDetailCoverCount,
} from './platformPublicWorkDetailFlow';
import {
  hasRecoverableGeneratedPuzzleDraft,
  normalizeRecoveredPuzzleDraftSession,
} from './platformPuzzleDraftRecoveryModel';
import {
  buildPuzzleResultProfileId,
  buildPuzzleResultWorkId,
} from './platformPuzzleIdentityModel';
import { mergePuzzleServiceRuntimeState } from './platformPuzzleRuntimeStateModel';
import {
  type PlatformPuzzleRuntimeAuthMode,
  resolvePlatformRecommendRuntimeAuthPlan,
} from './platformRecommendRuntimeAuthModel';
import {
  buildPlatformRpgAgentResultPublishGateView,
  resolvePlatformRpgAgentResultPreviewSourceLabel,
} from './platformRpgAgentResultPreviewModel';
import {
  resolveSelectionStageAfterMissingCreationState,
  resolveSelectionStageAfterProtectedDataLoss,
} from './platformSelectionStageModel';
import { PlatformTaskCompletionDialog } from './PlatformTaskCompletionDialog';
import { PlatformWorkDetailView } from './PlatformWorkDetailView';
import { usePlatformCreationAgentFlowController } from './usePlatformCreationAgentFlowController';
import { usePlatformEntryBootstrap } from './usePlatformEntryBootstrap';
import { usePlatformEntryLibraryDetail } from './usePlatformEntryLibraryDetail';
import { usePlatformEntryNavigation } from './usePlatformEntryNavigation';

type CreationWorkShelfKind = CreationWorkShelfItem['kind'];
type CreationFlowReturnTarget = 'create' | 'draft-shelf';
type Match3DBackgroundCompileTask = {
  session: Match3DAgentSessionSnapshot;
  payload: CreateMatch3DSessionRequest;
  generationState: MiniGameDraftGenerationState;
  error: string | null;
};
type PuzzleBackgroundCompileTask = {
  session: PuzzleAgentSessionSnapshot;
  payload: CreatePuzzleAgentSessionRequest;
  generationState: MiniGameDraftGenerationState;
  error: string | null;
};

type PuzzleDetailReturnTarget = {
  tab: PlatformHomeTab;
};

type PuzzleRuntimeReturnStage =
  | 'puzzle-result'
  | 'puzzle-gallery-detail'
  | 'work-detail'
  | 'platform';
type PuzzleRuntimeAuthMode = PlatformPuzzleRuntimeAuthMode;

type PuzzleOnboardingDraft = {
  promptText: string;
  item: PuzzleWorkSummary;
};

type BigFishRuntimeReturnStage = 'big-fish-result' | 'work-detail' | 'platform';
type BarkBattleRuntimeReturnStage =
  | 'bark-battle-result'
  | 'work-detail'
  | 'platform';
type BigFishRuntimeSessionSource = 'draft' | 'work' | null;
type SquareHoleRuntimeReturnStage =
  | 'square-hole-result'
  | 'work-detail'
  | 'platform';
type VisualNovelRuntimeReturnStage =
  | 'visual-novel-result'
  | 'visual-novel-gallery-detail'
  | 'work-detail'
  | 'platform';
type BabyObjectMatchRuntimeReturnStage =
  | 'baby-object-match-result'
  | 'work-detail'
  | 'platform';
type JumpHopRuntimeReturnStage = 'jump-hop-result' | 'work-detail' | 'platform';
type WoodenFishRuntimeReturnStage =
  | 'wooden-fish-result'
  | 'work-detail'
  | 'platform';
type VisualNovelEntryGenerationPhase = 'generating' | 'ready' | 'failed';
type BabyObjectMatchGenerationPhase = 'generating' | 'ready' | 'failed';

type PuzzleSaveArchiveState = {
  runtimeKind?: unknown;
  entryProfileId?: unknown;
  currentProfileId?: unknown;
  currentLevelId?: unknown;
};

type DeleteCreationWorkConfirmation = {
  id: string;
  title: string;
  detail: string;
  run: () => void;
};

async function resumePuzzleProfileSaveArchiveRaw(worldKey: string) {
  return requestRpgRuntimeJson<
    ProfileSaveArchiveResumeResponse<PuzzleSaveArchiveState>
  >(
    `/profile/save-archives/${encodeURIComponent(worldKey)}`,
    { method: 'POST' },
    '恢复拼图存档失败',
  );
}

const RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS =
  BACKGROUND_AUTH_REQUEST_OPTIONS;
const RECOMMEND_PUZZLE_BACKGROUND_AUTH_OPTIONS =
  RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS;
type RecommendRuntimeAuthUi =
  | { user?: { id?: string } | null }
  | null
  | undefined;
async function buildRecommendRuntimeGuestOptions() {
  const { token } = await ensureRuntimeGuestToken();
  return {
    ...RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS,
    runtimeGuestToken: token,
  };
}
function resolveCurrentRecommendRuntimeAuthPlan(
  authUi: RecommendRuntimeAuthUi,
  input: { embedded?: boolean; allowRuntimeGuestAuth?: boolean } = {},
) {
  return resolvePlatformRecommendRuntimeAuthPlan({
    embedded: input.embedded,
    allowRuntimeGuestAuth: input.allowRuntimeGuestAuth,
    authUserId: authUi?.user?.id ?? null,
    hasStoredAccessToken: Boolean(getStoredAccessToken()),
  });
}
async function buildRecommendRuntimeOptionsFromAuthPlan(
  plan: ReturnType<typeof resolvePlatformRecommendRuntimeAuthPlan>,
) {
  if (plan.requestKind === 'runtime-guest') {
    return buildRecommendRuntimeGuestOptions();
  }
  if (plan.requestKind === 'background') {
    return RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS;
  }
  return {};
}
async function buildRecommendRuntimeAuthOptions(
  authUi: RecommendRuntimeAuthUi,
  embedded?: boolean,
) {
  return buildRecommendRuntimeOptionsFromAuthPlan(
    resolveCurrentRecommendRuntimeAuthPlan(authUi, { embedded }),
  );
}
const PUZZLE_DRAFT_GENERATION_POINT_COST = 2;
const MATCH3D_DRAFT_GENERATION_POINT_COST = 10;
const BARK_BATTLE_DRAFT_GENERATION_POINT_COST = 3;

const PUZZLE_ONBOARDING_FIRST_VISIT_STORAGE_KEY =
  'genarrative.puzzle-onboarding.first-visit.v1';
const PUZZLE_ONBOARDING_COPY = '待定待定待定';
const PUZZLE_ONBOARDING_CLEAR_COPY = '只差一步，就可以永久保留你的梦';
const PUZZLE_ONBOARDING_GENERATED_DELAY_MS = 700;

function isPuzzleOnboardingEnabled(): boolean {
  // 中文注释：当前产品要求隐藏首访新手引导，旧流程暂时保留用于后续显式恢复。
  return false;
}

function escapePuzzleOnboardingSvgText(value: string) {
  return value
    .replace(/&/gu, '&amp;')
    .replace(/</gu, '&lt;')
    .replace(/>/gu, '&gt;')
    .replace(/"/gu, '&quot;');
}

function buildPuzzleOnboardingFallbackImage(promptText: string) {
  const trimmedPrompt = promptText.trim();
  const displayPrompt = escapePuzzleOnboardingSvgText(
    trimmedPrompt.slice(0, 12) || '陶泥儿拼图',
  );
  return (
    'data:image/svg+xml;utf8,' +
    encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">
  <defs>
    <linearGradient id="sky" x1="0" y1="0" x2="1" y2="1">
      <stop offset="0" stop-color="#fde68a" />
      <stop offset="0.48" stop-color="#38bdf8" />
      <stop offset="1" stop-color="#312e81" />
    </linearGradient>
    <radialGradient id="glow" cx="34%" cy="30%" r="42%">
      <stop offset="0" stop-color="#fff7ed" stop-opacity="0.86" />
      <stop offset="1" stop-color="#fff7ed" stop-opacity="0" />
    </radialGradient>
  </defs>
  <rect width="1024" height="1024" fill="url(#sky)" />
  <circle cx="352" cy="292" r="248" fill="url(#glow)" />
  <path d="M0 654 C156 570 296 680 452 610 C626 532 782 598 1024 500 V1024 H0 Z" fill="#0f172a" opacity="0.88" />
  <path d="M0 802 C196 710 332 838 540 750 C704 682 846 724 1024 670 V1024 H0 Z" fill="#111827" opacity="0.72" />
  <path d="M160 344 C242 268 340 282 430 350 C532 428 646 388 752 322 C844 266 918 302 958 362" fill="none" stroke="#fff7ed" stroke-width="18" stroke-linecap="round" opacity="0.72" />
  <path d="M188 538 H836" stroke="#ffffff" stroke-width="16" stroke-linecap="round" opacity="0.26" />
  <path d="M260 620 H764" stroke="#ffffff" stroke-width="12" stroke-linecap="round" opacity="0.2" />
  <text x="512" y="868" text-anchor="middle" font-family="sans-serif" font-size="54" font-weight="800" fill="#ffffff" opacity="0.84">${displayPrompt}</text>
</svg>`)
  );
}

function buildPuzzleOnboardingFallbackWork(
  promptText: string,
): PuzzleWorkSummary {
  const now = new Date().toISOString();
  const seed = Date.now();
  const coverImageSrc = buildPuzzleOnboardingFallbackImage(promptText);
  const level: PuzzleDraftLevel = {
    levelId: 'onboarding-local-level-1',
    levelName: '梦境拼图',
    pictureDescription: promptText,
    pictureReference: null,
    candidates: [
      {
        candidateId: 'onboarding-local-candidate-1',
        imageSrc: coverImageSrc,
        assetId: 'onboarding-local-asset-1',
        prompt: promptText,
        actualPrompt: promptText,
        sourceType: 'generated',
        selected: true,
      },
    ],
    selectedCandidateId: 'onboarding-local-candidate-1',
    coverImageSrc,
    coverAssetId: 'onboarding-local-asset-1',
    generationStatus: 'ready',
  };

  return {
    workId: `onboarding-local-work-${seed}`,
    profileId: `onboarding-local-profile-${seed}`,
    ownerUserId: 'onboarding-guest',
    sourceSessionId: null,
    authorDisplayName: '陶泥儿主',
    workTitle: '梦境拼图',
    workDescription: promptText,
    levelName: level.levelName,
    summary: promptText,
    themeTags: ['新手引导', '拼图'],
    coverImageSrc,
    coverAssetId: level.coverAssetId,
    publicationStatus: 'draft',
    updatedAt: now,
    publishedAt: null,
    playCount: 0,
    remixCount: 0,
    likeCount: 0,
    publishReady: true,
    levels: [level],
  };
}

function shouldUseLocalPuzzleOnboardingFallback(error: unknown) {
  return (
    error instanceof ApiClientError &&
    error.status === 404 &&
    (error.code === 'NOT_FOUND' || error.message.includes('资源不存在'))
  );
}

function isMissingPuzzleWorkError(error: unknown) {
  return (
    (error instanceof ApiClientError &&
      error.status === 404 &&
      (error.code === 'NOT_FOUND' ||
        error.message.includes('资源不存在') ||
        error.message.includes('未找到'))) ||
    (error instanceof Error &&
      (error.message.includes('资源不存在') ||
        error.message.includes('未找到拼图作品')))
  );
}

function maybeAlertWorkNotFoundAndReturnHome() {
  if (typeof window === 'undefined') {
    return false;
  }

  const recoveryAction = resolveWorkNotFoundRecoveryAction(
    window.location.pathname,
  );
  if (!recoveryAction) {
    return false;
  }

  // 中文注释：直接打开公开详情或运行态深链失效时，确认提示后必须离开空详情页。
  window.alert('作品不存在或已下架，将返回首页。');
  pushAppHistoryPath(recoveryAction.nextPath);
  return true;
}

function hasSeenPuzzleOnboarding() {
  if (!isPuzzleOnboardingEnabled()) {
    return true;
  }

  if (typeof window === 'undefined') {
    return true;
  }

  try {
    return (
      window.localStorage.getItem(PUZZLE_ONBOARDING_FIRST_VISIT_STORAGE_KEY) ===
      '1'
    );
  } catch {
    return false;
  }
}

function markPuzzleOnboardingSeen() {
  if (typeof window === 'undefined') {
    return;
  }

  try {
    window.localStorage.setItem(PUZZLE_ONBOARDING_FIRST_VISIT_STORAGE_KEY, '1');
  } catch {
    // 中文注释：localStorage 不可写时只降级为本次会话展示，不影响主流程。
  }
}

async function resolvePublicWorkAuthorSummary(
  entry: PlatformPublicGalleryCard,
): Promise<PublicUserSummary | null> {
  if ('authorPublicUserCode' in entry && entry.authorPublicUserCode?.trim()) {
    try {
      return await getPublicAuthUserByCode(entry.authorPublicUserCode);
    } catch {
      if (!entry.ownerUserId.trim()) {
        return null;
      }
    }
  }

  if (entry.ownerUserId.trim()) {
    return getPublicAuthUserById(entry.ownerUserId);
  }

  return null;
}

function openPuzzleRuntimeStage(
  setSelectionStage: (stage: SelectionStage) => void,
  state: PuzzleRuntimeUrlState,
) {
  pushAppHistoryPath('/runtime/puzzle');
  setSelectionStage('puzzle-runtime');
  writePuzzleRuntimeUrlState(state);
}

const CustomWorldGenerationView = lazy(async () => {
  const module = await import('../CustomWorldGenerationView');
  return {
    default: module.CustomWorldGenerationView,
  };
});

const UnifiedCreationWorkspace = lazy(async () => {
  const module = await import('../unified-creation/UnifiedCreationWorkspace');
  return {
    default: module.UnifiedCreationWorkspace,
  };
});

const UnifiedGenerationPage = lazy(async () => {
  const module = await import('../unified-creation/UnifiedGenerationPage');
  return {
    default: module.UnifiedGenerationPage,
  };
});

const RpgCreationResultView = lazy(async () => {
  const module = await import('../rpg-creation-result/RpgCreationResultView');
  return {
    default: module.RpgCreationResultView,
  };
});

const CustomWorldAgentWorkspace = lazy(async () => {
  const module = await import(
    '../custom-world-agent/CustomWorldAgentWorkspace'
  );
  return {
    default: module.CustomWorldAgentWorkspace,
  };
});

const BigFishAgentWorkspace = lazy(async () => {
  const module = await import('../big-fish-creation/BigFishAgentWorkspace');
  return {
    default: module.BigFishAgentWorkspace,
  };
});

const BigFishResultView = lazy(async () => {
  const module = await import('../big-fish-result/BigFishResultView');
  return {
    default: module.BigFishResultView,
  };
});

const BigFishRuntimeShell = lazy(async () => {
  const module = await import('../big-fish-runtime/BigFishRuntimeShell');
  return {
    default: module.BigFishRuntimeShell,
  };
});

const Match3DResultView = lazy(async () => {
  const module = await import('../match3d-result/Match3DResultView');
  return {
    default: module.Match3DResultView,
  };
});

const Match3DRuntimeShell = lazy(async () => {
  const module = await import('../match3d-runtime/Match3DRuntimeShell');
  return {
    default: module.Match3DRuntimeShell,
  };
});

const SquareHoleAgentWorkspace = lazy(async () => {
  const module = await import(
    '../square-hole-creation/SquareHoleAgentWorkspace'
  );
  return {
    default: module.SquareHoleAgentWorkspace,
  };
});

const SquareHoleResultView = lazy(async () => {
  const module = await import('../square-hole-result/SquareHoleResultView');
  return {
    default: module.SquareHoleResultView,
  };
});

const SquareHoleRuntimeShell = lazy(async () => {
  const module = await import('../square-hole-runtime/SquareHoleRuntimeShell');
  return {
    default: module.SquareHoleRuntimeShell,
  };
});

const JumpHopResultView = lazy(async () => {
  const module = await import('../jump-hop-result/JumpHopResultView');
  return {
    default: module.JumpHopResultView,
  };
});

const JumpHopRuntimeShell = lazy(async () => {
  const module = await import('../jump-hop-runtime/JumpHopRuntimeShell');
  return {
    default: module.JumpHopRuntimeShell,
  };
});

const WoodenFishResultView = lazy(async () => {
  const module = await import('../wooden-fish-result/WoodenFishResultView');
  return {
    default: module.WoodenFishResultView,
  };
});

const WoodenFishRuntimeShell = lazy(async () => {
  const module = await import('../wooden-fish-runtime/WoodenFishRuntimeShell');
  return {
    default: module.WoodenFishRuntimeShell,
  };
});

const BarkBattleConfigEditor = lazy(async () => {
  const module = await import('../bark-battle-creation/BarkBattleConfigEditor');
  return {
    default: module.BarkBattleConfigEditor,
  };
});

const BarkBattleGeneratingView = lazy(async () => {
  const module = await import(
    '../bark-battle-creation/BarkBattleGeneratingView'
  );
  return {
    default: module.BarkBattleGeneratingView,
  };
});

const BarkBattleResultView = lazy(async () => {
  const module = await import('../bark-battle-creation/BarkBattleResultView');
  return {
    default: module.BarkBattleResultView,
  };
});

const BarkBattleRuntimeShell = lazy(async () => {
  const module = await import(
    '../../games/bark-battle/ui/BarkBattleRuntimeShell'
  );
  return {
    default: module.BarkBattleRuntimeShell,
  };
});

const CustomWorldCreationHub = lazy(async () => {
  const module = await import('../custom-world-home/CustomWorldCreationHub');
  return {
    default: module.CustomWorldCreationHub,
  };
});

const CreativeAgentWorkspace = lazy(async () => {
  const module = await import('../creative-agent/CreativeAgentWorkspace');
  return {
    default: module.CreativeAgentWorkspace,
  };
});

const VisualNovelAgentWorkspace = lazy(async () => {
  const module = await import(
    '../visual-novel-creation/VisualNovelAgentWorkspace'
  );
  return {
    default: module.VisualNovelAgentWorkspace,
  };
});

const BabyObjectMatchWorkspace = lazy(async () => {
  const module = await import(
    '../edutainment-creation/BabyObjectMatchWorkspace'
  );
  return {
    default: module.BabyObjectMatchWorkspace,
  };
});

const BabyObjectMatchResultView = lazy(async () => {
  const module = await import(
    '../edutainment-result/BabyObjectMatchResultView'
  );
  return {
    default: module.BabyObjectMatchResultView,
  };
});

const BabyObjectMatchRuntimeShell = lazy(async () => {
  const module = await import(
    '../edutainment-runtime/BabyObjectMatchRuntimeShell'
  );
  return {
    default: module.BabyObjectMatchRuntimeShell,
  };
});

const BabyLoveDrawingRuntimeShell = lazy(async () => {
  const module = await import(
    '../edutainment-runtime/BabyLoveDrawingRuntimeShell'
  );
  return {
    default: module.BabyLoveDrawingRuntimeShell,
  };
});

const VisualNovelResultView = lazy(async () => {
  const module = await import('../visual-novel-result/VisualNovelResultView');
  return {
    default: module.VisualNovelResultView,
  };
});

const VisualNovelRuntimeShell = lazy(async () => {
  const module = await import(
    '../visual-novel-runtime/VisualNovelRuntimeShell'
  );
  return {
    default: module.VisualNovelRuntimeShell,
  };
});

const PuzzleResultView = lazy(async () => {
  const module = await import('../puzzle-result/PuzzleResultView');
  return {
    default: module.PuzzleResultView,
  };
});

const PuzzleGalleryDetailView = lazy(async () => {
  const module = await import('../puzzle-gallery/PuzzleGalleryDetailView');
  return {
    default: module.PuzzleGalleryDetailView,
  };
});

const PuzzleRuntimeShell = lazy(async () => {
  const module = await import('../puzzle-runtime/PuzzleRuntimeShell');
  return {
    default: module.PuzzleRuntimeShell,
  };
});

function LazyPanelFallback({ label }: { label: string }) {
  return (
    <div className="flex h-full min-h-0 items-center justify-center">
      <div className="platform-subpanel rounded-2xl px-5 py-4 text-sm text-[var(--platform-text-base)]">
        {label}
      </div>
    </div>
  );
}

function CreationResultRecoveryPanel({
  title,
  message,
  actionLabel,
  onAction,
}: {
  title: string;
  message: string;
  actionLabel: string;
  onAction: () => void;
}) {
  return (
    <div className="flex h-full min-h-0 items-center justify-center px-3 py-6">
      <div className="platform-subpanel w-full max-w-sm rounded-[1.5rem] p-5 text-center">
        <div className="text-base font-black text-[var(--platform-text-strong)]">
          {title}
        </div>
        <div className="mt-2 text-sm leading-6 text-[var(--platform-text-base)]">
          {message}
        </div>
        <button
          type="button"
          onClick={onAction}
          className="platform-button platform-button--primary mt-4 min-h-11 justify-center px-4 py-3 text-sm"
        >
          {actionLabel}
        </button>
      </div>
    </div>
  );
}

export function PlatformEntryFlowShellImpl({
  selectionStage,
  setSelectionStage,
  hasSavedGame,
  savedSnapshot,
  handleContinueGame,
  handleStartNewGame,
  handleCustomWorldSelect,
  initialPublicWorkCode,
}: PlatformEntryFlowShellProps) {
  const authUi = useAuthUi();
  const platformThemeClass =
    authUi?.platformTheme === 'dark'
      ? 'platform-theme--dark'
      : 'platform-theme--light';
  const isDesktopLayout = usePlatformDesktopLayout();
  const [showCreationTypeModal, setShowCreationTypeModal] = useState(false);
  const [draftGenerationPointNotice, setDraftGenerationPointNotice] = useState<{
    title: string;
    message: string;
  } | null>(null);
  const [selectedDetailEntry, setSelectedDetailEntry] =
    useState<CustomWorldLibraryEntry<CustomWorldProfile> | null>(null);
  const [selectedPublicWorkDetail, setSelectedPublicWorkDetail] =
    useState<PlatformPublicGalleryCard | null>(null);
  const [selectedPublicWorkAuthor, setSelectedPublicWorkAuthor] =
    useState<PublicUserSummary | null>(null);
  const publicWorkAuthorRequestKeyRef = useRef(0);
  const [publicWorkDetailError, setPublicWorkDetailError] = useState<
    string | null
  >(null);
  const [isPublicWorkDetailBusy, setIsPublicWorkDetailBusy] = useState(false);
  const [bigFishWorks, setBigFishWorks] = useState<BigFishWorkSummary[]>([]);
  const [bigFishGalleryEntries, setBigFishGalleryEntries] = useState<
    BigFishWorkSummary[]
  >([]);
  const [match3dWorks, setMatch3DWorks] = useState<Match3DWorkSummary[]>([]);
  const [match3dGalleryEntries, setMatch3DGalleryEntries] = useState<
    Match3DWorkSummary[]
  >([]);
  const [match3dProfile, setMatch3DProfile] =
    useState<Match3DWorkProfile | null>(null);
  const [match3dRuntimeProfile, setMatch3DRuntimeProfile] =
    useState<Match3DWorkProfile | null>(null);
  const [match3dRun, setMatch3DRun] = useState<Match3DRunSnapshot | null>(null);
  const [match3dRuntimeReturnStage, setMatch3DRuntimeReturnStage] = useState<
    'match3d-result' | 'work-detail'
  >('match3d-result');
  const [match3dFormDraftPayload, setMatch3DFormDraftPayload] =
    useState<CreateMatch3DSessionRequest | null>(null);
  const [match3dGenerationState, setMatch3DGenerationState] =
    useState<MiniGameDraftGenerationState | null>(null);
  const [match3dBackgroundCompileTasks, setMatch3DBackgroundCompileTasks] =
    useState<Record<string, Match3DBackgroundCompileTask>>({});
  const [isMatch3DLoadingLibrary, setIsMatch3DLoadingLibrary] = useState(false);
  const [squareHoleWorks, setSquareHoleWorks] = useState<
    SquareHoleWorkSummary[]
  >([]);
  const [squareHoleGalleryEntries, setSquareHoleGalleryEntries] = useState<
    SquareHoleWorkSummary[]
  >([]);
  const [squareHoleProfile, setSquareHoleProfile] =
    useState<SquareHoleWorkProfile | null>(null);
  const [squareHoleRun, setSquareHoleRun] =
    useState<SquareHoleRunSnapshot | null>(null);
  const [squareHoleRuntimeReturnStage, setSquareHoleRuntimeReturnStage] =
    useState<SquareHoleRuntimeReturnStage>('square-hole-result');
  const [isSquareHoleLoadingLibrary, setIsSquareHoleLoadingLibrary] =
    useState(false);
  const [squareHoleGenerationState, setSquareHoleGenerationState] =
    useState<MiniGameDraftGenerationState | null>(null);
  const [jumpHopSession, setJumpHopSession] =
    useState<JumpHopSessionSnapshotResponse | null>(null);
  const [jumpHopRun, setJumpHopRun] = useState<
    JumpHopRunResponse['run'] | null
  >(null);
  const [jumpHopWork, setJumpHopWork] =
    useState<JumpHopWorkProfileResponse | null>(null);
  const [jumpHopGalleryEntries, setJumpHopGalleryEntries] = useState<
    JumpHopGalleryCardResponse[]
  >([]);
  const [jumpHopWorks, setJumpHopWorks] = useState<
    JumpHopWorkSummaryResponse[]
  >([]);
  const [jumpHopRuntimeReturnStage, setJumpHopRuntimeReturnStage] =
    useState<JumpHopRuntimeReturnStage>('jump-hop-result');
  const [jumpHopGenerationState, setJumpHopGenerationState] =
    useState<MiniGameDraftGenerationState | null>(null);
  const [jumpHopError, setJumpHopError] = useState<string | null>(null);
  const [isJumpHopBusy, setIsJumpHopBusy] = useState(false);
  const [barkBattleWorks, setBarkBattleWorks] = useState<
    BarkBattleWorkSummary[]
  >([]);
  const [barkBattleGalleryEntries, setBarkBattleGalleryEntries] = useState<
    BarkBattleWorkSummary[]
  >([]);
  const [woodenFishSession, setWoodenFishSession] =
    useState<WoodenFishSessionSnapshotResponse | null>(null);
  const [woodenFishRun, setWoodenFishRun] = useState<
    WoodenFishRunResponse['run'] | null
  >(null);
  const [woodenFishWork, setWoodenFishWork] =
    useState<WoodenFishWorkProfileResponse | null>(null);
  const [woodenFishWorks, setWoodenFishWorks] = useState<
    WoodenFishWorkSummaryResponse[]
  >([]);
  const [woodenFishGalleryEntries, setWoodenFishGalleryEntries] = useState<
    WoodenFishGalleryCardResponse[]
  >([]);
  const [woodenFishRuntimeReturnStage, setWoodenFishRuntimeReturnStage] =
    useState<WoodenFishRuntimeReturnStage>('wooden-fish-result');
  const [woodenFishGenerationState, setWoodenFishGenerationState] =
    useState<MiniGameDraftGenerationState | null>(null);
  const [woodenFishError, setWoodenFishError] = useState<string | null>(null);
  const [isWoodenFishBusy, setIsWoodenFishBusy] = useState(false);
  const [barkBattlePublishedConfig, setBarkBattlePublishedConfig] =
    useState<BarkBattlePublishedConfig | null>(null);
  const [barkBattleDraftConfig, setBarkBattleDraftConfig] =
    useState<BarkBattleDraftConfig | null>(null);
  const [barkBattleRuntimeMode, setBarkBattleRuntimeMode] = useState<
    'draft' | 'published'
  >('draft');
  const [barkBattleRuntimeReturnStage, setBarkBattleRuntimeReturnStage] =
    useState<BarkBattleRuntimeReturnStage>('platform');
  const [barkBattleError, setBarkBattleError] = useState<string | null>(null);
  const [
    barkBattleGenerationPartialFailed,
    setBarkBattleGenerationPartialFailed,
  ] = useState(false);
  const [isBarkBattleBusy, setIsBarkBattleBusy] = useState(false);
  const [bigFishRun, setBigFishRun] =
    useState<BigFishRuntimeSnapshotResponse | null>(null);
  const [bigFishRuntimeShare, setBigFishRuntimeShare] = useState<{
    title: string;
    publicWorkCode: string;
  } | null>(null);
  const [_bigFishRuntimeWork, setBigFishRuntimeWork] =
    useState<BigFishWorkSummary | null>(null);
  const [bigFishRuntimeStartedAt, setBigFishRuntimeStartedAt] = useState<
    number | null
  >(null);
  const [_bigFishRuntimeSessionSource, setBigFishRuntimeSessionSource] =
    useState<BigFishRuntimeSessionSource>(null);
  const [bigFishRuntimeReturnStage, setBigFishRuntimeReturnStage] =
    useState<BigFishRuntimeReturnStage>('platform');
  const bigFishInputInFlightRef = useRef(false);
  const [isBigFishLoadingLibrary, setIsBigFishLoadingLibrary] = useState(false);
  const [bigFishGenerationState, setBigFishGenerationState] =
    useState<MiniGameDraftGenerationState | null>(null);
  const [activeRecommendEntryKey, setActiveRecommendEntryKey] = useState<
    string | null
  >(null);
  const [activeRecommendRuntimeKind, setActiveRecommendRuntimeKind] =
    useState<RecommendRuntimeKind | null>(null);
  const [activeRecommendRuntimeError, setActiveRecommendRuntimeError] =
    useState<string | null>(null);
  const [isStartingRecommendEntry, setIsStartingRecommendEntry] =
    useState(false);
  const recommendRuntimeStartRequestRef = useRef(0);
  const [, setPuzzleOperation] = useState<PuzzleAgentOperationRecord | null>(
    null,
  );
  const [puzzleWorks, setPuzzleWorks] = useState<PuzzleWorkSummary[]>([]);
  const [puzzleGalleryEntries, setPuzzleGalleryEntries] = useState<
    PuzzleWorkSummary[]
  >([]);
  const [selectedPuzzleDetail, setSelectedPuzzleDetail] =
    useState<PuzzleWorkSummary | null>(null);
  const [puzzleDetailReturnTarget, setPuzzleDetailReturnTarget] =
    useState<PuzzleDetailReturnTarget | null>(null);
  const [puzzleRuntimeReturnStage, setPuzzleRuntimeReturnStage] =
    useState<PuzzleRuntimeReturnStage>('puzzle-gallery-detail');
  const [puzzleRuntimeAuthMode, setPuzzleRuntimeAuthMode] =
    useState<PuzzleRuntimeAuthMode>('default');
  const [isPuzzleLeaderboardBusy, setIsPuzzleLeaderboardBusy] = useState(false);
  const submittedPuzzleLeaderboardKeysRef = useRef(new Set<string>());
  const puzzleStartInFlightKeyRef = useRef<string | null>(null);
  const [puzzleRun, setPuzzleRun] = useState<PuzzleRunSnapshot | null>(null);
  const puzzleRunRef = useRef<PuzzleRunSnapshot | null>(null);
  const errorSetterRefNoop = useMemo(
    () =>
      ((_: SetStateAction<string | null>) => undefined) as Dispatch<
        SetStateAction<string | null>
      >,
    [],
  );
  const bigFishErrorSetterRef = useRef(errorSetterRefNoop);
  const match3DErrorSetterRef = useRef(errorSetterRefNoop);
  const squareHoleErrorSetterRef = useRef(errorSetterRefNoop);
  const puzzleErrorSetterRef = useRef(errorSetterRefNoop);
  const visualNovelErrorSetterRef = useRef(errorSetterRefNoop);
  const [isPuzzleLoadingLibrary, setIsPuzzleLoadingLibrary] = useState(false);
  const [puzzleShelfError, setPuzzleShelfError] = useState<string | null>(null);
  const [puzzleCreationError, setPuzzleCreationError] = useState<string | null>(
    null,
  );
  const [puzzleGenerationState, setPuzzleGenerationState] =
    useState<MiniGameDraftGenerationState | null>(null);
  const [puzzleBackgroundCompileTasks, setPuzzleBackgroundCompileTasks] =
    useState<Record<string, PuzzleBackgroundCompileTask>>({});
  const [miniGameGenerationProgressNowMs, setMiniGameGenerationProgressNowMs] =
    useState(() => Date.now());
  const [puzzleFormDraftPayload, setPuzzleFormDraftPayload] =
    useState<CreatePuzzleAgentSessionRequest | null>(null);
  const [puzzleOnboardingPrompt, setPuzzleOnboardingPrompt] = useState('');
  const [puzzleOnboardingPhase, setPuzzleOnboardingPhase] =
    useState<PuzzleOnboardingPhase>('input');
  const [puzzleOnboardingDraft, setPuzzleOnboardingDraft] =
    useState<PuzzleOnboardingDraft | null>(null);
  const [puzzleOnboardingError, setPuzzleOnboardingError] = useState<
    string | null
  >(null);
  const [isPuzzleOnboardingSaving, setIsPuzzleOnboardingSaving] =
    useState(false);
  const [creativeAgentSession, setCreativeAgentSession] =
    useState<CreativeAgentSessionSnapshot | null>(null);
  const [creativeAgentError, setCreativeAgentError] = useState<string | null>(
    null,
  );
  const [isCreativeAgentBusy, setIsCreativeAgentBusy] = useState(false);
  const [isCreativeAgentStreaming, setIsCreativeAgentStreaming] =
    useState(false);
  const [creativeAgentEvents, setCreativeAgentEvents] = useState<
    CreativeAgentSseEvent[]
  >([]);
  const [activeCreativeAgentSessionId, setActiveCreativeAgentSessionId] =
    useState<string | null>(null);
  const [creativeDraftEditError, setCreativeDraftEditError] = useState<
    string | null
  >(null);
  const [isCreativeDraftEditBusy, setIsCreativeDraftEditBusy] = useState(false);
  const [visualNovelWork, setVisualNovelWork] =
    useState<VisualNovelWorkDetail | null>(null);
  const [visualNovelWorks, setVisualNovelWorks] = useState<
    VisualNovelWorkSummary[]
  >([]);
  const [visualNovelGalleryEntries, setVisualNovelGalleryEntries] = useState<
    VisualNovelWorkSummary[]
  >([]);
  const [visualNovelRun, setVisualNovelRun] =
    useState<VisualNovelRunSnapshot | null>(null);
  const [visualNovelRuntimeReturnStage, setVisualNovelRuntimeReturnStage] =
    useState<VisualNovelRuntimeReturnStage>('visual-novel-result');
  const [visualNovelFormDraftPayload, setVisualNovelFormDraftPayload] =
    useState<VisualNovelEntryFormPayload | null>(null);
  const [
    visualNovelGenerationStartedAtMs,
    setVisualNovelGenerationStartedAtMs,
  ] = useState<number | null>(null);
  const [visualNovelGenerationPhase, setVisualNovelGenerationPhase] =
    useState<VisualNovelEntryGenerationPhase>('generating');
  const [babyObjectMatchDraft, setBabyObjectMatchDraft] =
    useState<BabyObjectMatchDraft | null>(null);
  const [babyObjectMatchDrafts, setBabyObjectMatchDrafts] = useState<
    BabyObjectMatchDraft[]
  >([]);
  const [babyObjectMatchFormPayload, setBabyObjectMatchFormPayload] =
    useState<CreateBabyObjectMatchDraftRequest | null>(null);
  const [babyObjectMatchGenerationState, setBabyObjectMatchGenerationState] =
    useState<MiniGameDraftGenerationState | null>(null);
  const [babyObjectMatchGenerationPhase, setBabyObjectMatchGenerationPhase] =
    useState<BabyObjectMatchGenerationPhase>('generating');
  const [
    babyObjectMatchRuntimeReturnStage,
    setBabyObjectMatchRuntimeReturnStage,
  ] = useState<BabyObjectMatchRuntimeReturnStage>('baby-object-match-result');
  const [babyObjectMatchError, setBabyObjectMatchError] = useState<
    string | null
  >(null);
  const [isBabyObjectMatchBusy, setIsBabyObjectMatchBusy] = useState(false);
  const [isVisualNovelLoadingLibrary, setIsVisualNovelLoadingLibrary] =
    useState(false);
  const [isPuzzleNextLevelGenerating, setIsPuzzleNextLevelGenerating] =
    useState(false);
  const [isSearchingPublicCode, setIsSearchingPublicCode] = useState(false);
  const [publicSearchError, setPublicSearchError] = useState<string | null>(
    null,
  );
  const [searchedPublicUser, setSearchedPublicUser] =
    useState<PublicUserSummary | null>(null);
  const [deletingCreationWorkId, setDeletingCreationWorkId] = useState<
    string | null
  >(null);
  const [pendingDeleteCreationWork, setPendingDeleteCreationWork] =
    useState<DeleteCreationWorkConfirmation | null>(null);
  const [
    claimingPuzzlePointIncentiveProfileId,
    setClaimingPuzzlePointIncentiveProfileId,
  ] = useState<string | null>(null);
  const [publishSharePayload, setPublishSharePayload] =
    useState<PublishShareModalPayload | null>(null);
  const [creationEntryConfig, setCreationEntryConfig] =
    useState<CreationEntryConfig | null>(null);
  const [creationEntryConfigError, setCreationEntryConfigError] = useState<
    string | null
  >(null);
  const creationEntryTypes = useMemo(
    () =>
      creationEntryConfig
        ? derivePlatformCreationTypes(creationEntryConfig.creationTypes)
        : [],
    [creationEntryConfig],
  );
  const unifiedCreationConfigById = useMemo(() => {
    const entries = creationEntryConfig?.creationTypes ?? [];
    return new Map(entries.map((entry) => [entry.id, entry]));
  }, [creationEntryConfig]);
  const getUnifiedSpec = useCallback(
    (playId: UnifiedCreationPlayId) =>
      getUnifiedCreationSpec(playId, unifiedCreationConfigById.get(playId)),
    [unifiedCreationConfigById],
  );
  const isBigFishCreationVisible = isPlatformCreationTypeVisible(
    creationEntryTypes,
    'big-fish',
  );
  const isJumpHopCreationVisible = isPlatformCreationTypeVisible(
    creationEntryTypes,
    'jump-hop',
  );
  const isSquareHoleCreationVisible = isPlatformCreationTypeVisible(
    creationEntryTypes,
    'square-hole',
  );
  const isBabyObjectMatchVisible = isPlatformCreationTypeVisible(
    creationEntryTypes,
    'baby-object-match',
  );
  const isVisualNovelCreationOpen = isPlatformCreationTypeOpen(
    creationEntryTypes,
    'visual-novel',
  );
  const [profilePlayStats, setProfilePlayStats] =
    useState<ProfilePlayStatsResponse | null>(null);
  const [profilePlayStatsError, setProfilePlayStatsError] = useState<
    string | null
  >(null);
  const [isProfilePlayStatsLoading, setIsProfilePlayStatsLoading] =
    useState(false);
  const [isProfilePlayStatsOpen, setIsProfilePlayStatsOpen] = useState(false);
  const hadReadableProtectedDataRef = useRef(false);
  const hasInitialAgentSession = Boolean(
    readCustomWorldAgentUiState().activeSessionId &&
      shouldRestoreCustomWorldAgentUiState(),
  );
  const handledInitialPublicWorkCodeRef = useRef<string | null>(null);
  const selectionStageRef = useRef(selectionStage);
  const creationFlowReturnTargetRef =
    useRef<CreationFlowReturnTarget>('create');
  const activeMatch3DGenerationSessionIdRef = useRef<string | null>(null);
  const activePuzzleGenerationSessionIdRef = useRef<string | null>(null);
  const [draftGenerationNotices, setDraftGenerationNotices] =
    useState<DraftGenerationNoticeMap>({});
  const [pendingDraftShelfItems, setPendingDraftShelfItems] =
    useState<PendingDraftShelfMap>({});
  const profileWalletLocalDeltaRef = useRef(0);
  const lastProfileDashboardSnapshotRef =
    useRef<ProfileDashboardSummary | null>(null);
  const [
    pendingPlatformTaskCompletionDialog,
    setPendingPlatformTaskCompletionDialog,
  ] = useState<PlatformTaskCompletionDialogState | null>(null);
  const [
    pendingPlatformTaskFailureDialog,
    setPendingPlatformTaskFailureDialog,
  ] = useState<PlatformTaskFailureDialogState | null>(null);
  const [profileTaskRefreshKey, setProfileTaskRefreshKey] = useState(0);
  const [initialCreationUrlState] = useState(() => readCreationUrlState());
  const handledInitialCreationUrlStateRef = useRef(false);
  const [initialPuzzleRuntimeUrlState] = useState(() =>
    readPuzzleRuntimeUrlState(),
  );
  const handledPuzzleRuntimeUrlStateKeyRef = useRef<string | null>(null);

  useEffect(() => {
    selectionStageRef.current = selectionStage;
  }, [selectionStage]);

  const resetRecommendRuntimeSelection = useCallback(() => {
    // 中文注释：推荐页嵌入运行态进入改造/创作后会清掉玩法 run；
    // 同步清空推荐选择，避免返回推荐页时复用已失效的运行态占位。
    recommendRuntimeStartRequestRef.current += 1;
    setActiveRecommendEntryKey(null);
    setActiveRecommendRuntimeKind(null);
    setActiveRecommendRuntimeError(null);
    setIsStartingRecommendEntry(false);
  }, []);

  const updatePendingDraftShelfItem = useCallback(
    (
      kind: PendingDraftShelfKind,
      id: string | null | undefined,
      status: DraftGenerationNoticeStatus,
      seen = false,
      metadata?: PendingDraftShelfMetadata,
    ) => {
      const normalizedId = normalizeDraftNoticeId(id);
      if (!normalizedId) {
        return;
      }

      setPendingDraftShelfItems((current) => ({
        ...current,
        [kind]: (() => {
          const currentItems = current[kind] ?? {};
          return {
            ...currentItems,
            [normalizedId]: createPendingDraftShelfState(
              status,
              seen,
              new Date().toISOString(),
              metadata ?? currentItems[normalizedId],
            ),
          };
        })(),
      }));
    },
    [],
  );
  const clearPendingDraftShelfItem = useCallback(
    (kind: PendingDraftShelfKind, id: string | null | undefined) => {
      const normalizedId = normalizeDraftNoticeId(id);
      if (!normalizedId) {
        return;
      }

      setPendingDraftShelfItems((current) => {
        const currentItems = current[kind];
        if (!currentItems?.[normalizedId]) {
          return current;
        }

        const nextItems = { ...currentItems };
        delete nextItems[normalizedId];
        return {
          ...current,
          [kind]: nextItems,
        };
      });
    },
    [],
  );

  const updateDraftGenerationNotices = useCallback(
    (
      keys: string[],
      status: DraftGenerationNoticeStatus,
      seen = false,
      message?: string | null,
    ) => {
      const uniqueKeys = Array.from(new Set(keys.filter(Boolean)));
      if (uniqueKeys.length === 0) {
        return;
      }

      const completedAtMs = status === 'ready' ? Date.now() : undefined;
      const normalizedMessage = message?.trim();
      setDraftGenerationNotices((current) => {
        const next = { ...current };
        for (const key of uniqueKeys) {
          next[key] =
            completedAtMs === undefined
              ? {
                  status,
                  seen,
                  ...(normalizedMessage ? { message: normalizedMessage } : {}),
                }
              : {
                  status,
                  seen,
                  completedAtMs,
                  ...(normalizedMessage ? { message: normalizedMessage } : {}),
                };
        }
        return next;
      });
    },
    [],
  );

  const markDraftNoticeSeen = useCallback((keys: string[]) => {
    const uniqueKeys = Array.from(new Set(keys.filter(Boolean)));
    if (uniqueKeys.length === 0) {
      return;
    }

    setDraftGenerationNotices((current) => {
      let changed = false;
      const next = { ...current };
      for (const key of uniqueKeys) {
        const notice = next[key];
        if (notice?.status === 'ready' && !notice.seen) {
          next[key] = { ...notice, seen: true };
          changed = true;
        }
      }
      return changed ? next : current;
    });
  }, []);

  const markDraftGenerating = useCallback(
    (kind: CreationWorkShelfKind, ids: Array<string | null | undefined>) => {
      setPendingPlatformTaskCompletionDialog(null);
      setPendingPlatformTaskFailureDialog(null);
      updateDraftGenerationNotices(
        collectDraftNoticeKeys(kind, ids),
        'generating',
      );
    },
    [
      setPendingPlatformTaskCompletionDialog,
      setPendingPlatformTaskFailureDialog,
      updateDraftGenerationNotices,
    ],
  );
  const markDraftReady = useCallback(
    (
      kind: CreationWorkShelfKind,
      ids: Array<string | null | undefined>,
      viewedImmediately: boolean,
    ) => {
      setPendingPlatformTaskFailureDialog(null);
      updateDraftGenerationNotices(
        collectDraftNoticeKeys(kind, ids),
        'ready',
        viewedImmediately,
      );
      setProfileTaskRefreshKey((current) => current + 1);
      const completedAtMs = Date.now();
      setPendingPlatformTaskCompletionDialog({
        key: `${kind}:${collectDraftNoticeKeys(kind, ids).join('|')}:${completedAtMs}`,
        source: buildDraftCompletionDialogSource(kind, ids),
        message: PLATFORM_TASK_COMPLETION_MESSAGE,
        completedAtMs,
      });
    },
    [
      setPendingPlatformTaskCompletionDialog,
      setPendingPlatformTaskFailureDialog,
      updateDraftGenerationNotices,
    ],
  );
  const markDraftFailed = useCallback(
    (
      kind: CreationWorkShelfKind,
      ids: Array<string | null | undefined>,
      errorMessage?: string | null,
      showFailureDialog = true,
    ) => {
      setPendingPlatformTaskCompletionDialog(null);
      const noticeKeys = collectDraftNoticeKeys(kind, ids);
      updateDraftGenerationNotices(noticeKeys, 'failed', false, errorMessage);
      const normalizedErrorMessage = errorMessage?.trim();
      if (normalizedErrorMessage && showFailureDialog) {
        const failedAtMs = Date.now();
        setPendingPlatformTaskFailureDialog({
          key: `draft-failure:${kind}:${noticeKeys.join('|')}:${failedAtMs}`,
          source: buildDraftCompletionDialogSource(kind, ids),
          message: normalizedErrorMessage,
          failedAtMs,
        });
      }
    },
    [
      setPendingPlatformTaskCompletionDialog,
      setPendingPlatformTaskFailureDialog,
      updateDraftGenerationNotices,
    ],
  );
  const markPendingDraftGenerating = useCallback(
    (
      kind: PendingDraftShelfKind,
      id: string | null | undefined,
      metadata?: PendingDraftShelfMetadata,
    ) => {
      setPendingPlatformTaskCompletionDialog(null);
      setPendingPlatformTaskFailureDialog(null);
      updatePendingDraftShelfItem(kind, id, 'generating', false, metadata);
    },
    [
      setPendingPlatformTaskCompletionDialog,
      setPendingPlatformTaskFailureDialog,
      updatePendingDraftShelfItem,
    ],
  );
  const markPendingDraftReady = useCallback(
    (
      kind: PendingDraftShelfKind,
      id: string | null | undefined,
      viewedImmediately: boolean,
    ) => {
      updatePendingDraftShelfItem(kind, id, 'ready', viewedImmediately);
    },
    [updatePendingDraftShelfItem],
  );
  const markPendingDraftFailed = useCallback(
    (kind: PendingDraftShelfKind, id: string | null | undefined) => {
      updatePendingDraftShelfItem(kind, id, 'failed', false);
    },
    [updatePendingDraftShelfItem],
  );
  const getMatch3DBackgroundCompileTask = useCallback(
    (sessionId: string | null | undefined) => {
      const normalizedSessionId = normalizeDraftNoticeId(sessionId);
      return normalizedSessionId
        ? (match3dBackgroundCompileTasks[normalizedSessionId] ?? null)
        : null;
    },
    [match3dBackgroundCompileTasks],
  );
  const getPuzzleBackgroundCompileTask = useCallback(
    (sessionId: string | null | undefined) => {
      const normalizedSessionId = normalizeDraftNoticeId(sessionId);
      return normalizedSessionId
        ? (puzzleBackgroundCompileTasks[normalizedSessionId] ?? null)
        : null;
    },
    [puzzleBackgroundCompileTasks],
  );

  useEffect(() => {
    let cancelled = false;
    setCreationEntryConfigError(null);
    void fetchCreationEntryConfig()
      .then((config) => {
        if (!cancelled) {
          setCreationEntryConfig(config);
        }
      })
      .catch((error: unknown) => {
        if (!cancelled) {
          setCreationEntryConfigError(
            error instanceof Error ? error.message : '读取创作入口配置失败。',
          );
        }
      });
    return () => {
      cancelled = true;
    };
  }, []);

  useEffect(() => {
    profileWalletLocalDeltaRef.current = 0;
    lastProfileDashboardSnapshotRef.current = null;
  }, [authUi?.user?.id]);

  const getPlatformProfileDashboardWithLocalWalletDelta = useCallback(
    async (options?: Parameters<typeof getPlatformProfileDashboard>[0]) => {
      const latestDashboard = await getPlatformProfileDashboard(options);
      const reconciledDelta =
        reconcileProfileWalletLocalDeltaWithServerDashboard(
          lastProfileDashboardSnapshotRef.current,
          latestDashboard,
          profileWalletLocalDeltaRef.current,
        );
      lastProfileDashboardSnapshotRef.current = latestDashboard;
      profileWalletLocalDeltaRef.current = reconciledDelta;
      return adjustProfileDashboardWalletBalance(
        latestDashboard,
        reconciledDelta,
      );
    },
    [],
  );

  const platformBootstrap = usePlatformEntryBootstrap({
    user: authUi?.user,
    canAccessProtectedData: authUi?.canAccessProtectedData,
    getProfileDashboard: getPlatformProfileDashboardWithLocalWalletDelta,
    handleContinueGame,
    hasInitialAgentSession,
  });
  const {
    canReadProtectedData: canRefreshPlatformDashboard,
    refreshProfileDashboard,
  } = platformBootstrap;
  const refreshPlatformDashboardSilently = useCallback(() => {
    if (!canRefreshPlatformDashboard) {
      return;
    }
    void refreshProfileDashboard().catch(() => undefined);
  }, [canRefreshPlatformDashboard, refreshProfileDashboard]);
  const adjustProfileWalletBalanceLocally = useCallback(
    (delta: number) => {
      if (!Number.isFinite(delta) || delta === 0) {
        return;
      }

      profileWalletLocalDeltaRef.current += Math.trunc(delta);
      platformBootstrap.setProfileDashboard((current) =>
        adjustProfileDashboardWalletBalance(current, delta),
      );
    },
    [platformBootstrap],
  );
  const entryNavigation = usePlatformEntryNavigation({
    setSelectionStage,
    setSelectedDetailEntry,
  });
  const { setPlatformTab } = platformBootstrap;
  const returnPlatformHomeAfterMissingWork = useCallback(() => {
    setPlatformTab('home');
    setSelectionStage('platform');
    if (!maybeAlertWorkNotFoundAndReturnHome()) {
      pushAppHistoryPath('/');
    }
  }, [setPlatformTab, setSelectionStage]);

  useEffect(() => {
    if (selectionStage === 'profile-feedback') {
      setPlatformTab('profile');
    }
  }, [selectionStage, setPlatformTab]);

  const openProfileFeedback = useCallback(() => {
    if (!authUi?.user) {
      authUi?.openLoginModal();
      return;
    }

    setPlatformTab('profile');
    setSelectionStage('profile-feedback');
  }, [authUi, setPlatformTab, setSelectionStage]);

  const enterCreateTab = useCallback(() => {
    // 只依赖稳定的 setter，避免把 bootstrap 对象的 render 级引用变化
    // 传导成 Agent session 恢复 effect 的重复触发。
    setPlatformTab('create');
  }, [setPlatformTab]);
  const enterDraftTab = useCallback(() => {
    setPlatformTab('saves');
  }, [setPlatformTab]);
  const markCreationFlowReturnToCreate = useCallback(() => {
    creationFlowReturnTargetRef.current = 'create';
  }, []);
  const markCreationFlowReturnToDraftShelf = useCallback(() => {
    creationFlowReturnTargetRef.current = 'draft-shelf';
  }, []);
  const returnToCreationFlowSource = useCallback(() => {
    const returnTarget = creationFlowReturnTargetRef.current;
    creationFlowReturnTargetRef.current = 'create';
    clearCreationUrlState();
    if (returnTarget === 'draft-shelf') {
      enterDraftTab();
    } else {
      enterCreateTab();
    }
    selectionStageRef.current = 'platform';
    setSelectionStage('platform');
  }, [enterCreateTab, enterDraftTab, setSelectionStage]);
  const shouldReturnToDraftShelf = useCallback(
    () => creationFlowReturnTargetRef.current === 'draft-shelf',
    [],
  );
  const returnToCreationCenterFromGeneration = useCallback(() => {
    markCreationFlowReturnToCreate();
    enterCreateTab();
    selectionStageRef.current = 'platform';
    setSelectionStage('platform');
  }, [enterCreateTab, markCreationFlowReturnToCreate, setSelectionStage]);
  const isViewingMatch3DGeneration = useCallback((sessionId: string) => {
    return (
      selectionStageRef.current === 'match3d-generating' &&
      activeMatch3DGenerationSessionIdRef.current === sessionId
    );
  }, []);
  const isViewingPuzzleGeneration = useCallback((sessionId: string) => {
    return (
      selectionStageRef.current === 'puzzle-generating' &&
      activePuzzleGenerationSessionIdRef.current === sessionId
    );
  }, []);
  const isDraftNoticeGenerating = useCallback(
    (kind: CreationWorkShelfKind, ids: Array<string | null | undefined>) =>
      hasDraftGenerationNoticeStatus(
        draftGenerationNotices,
        kind,
        ids,
        'generating',
      ),
    [draftGenerationNotices],
  );
  const isDraftNoticeFailed = useCallback(
    (kind: CreationWorkShelfKind, ids: Array<string | null | undefined>) =>
      hasDraftGenerationNoticeStatus(draftGenerationNotices, kind, ids, 'failed'),
    [draftGenerationNotices],
  );
  const isDraftNoticeReadyUnread = useCallback(
    (kind: CreationWorkShelfKind, ids: Array<string | null | undefined>) =>
      hasUnreadReadyDraftGenerationNotice(draftGenerationNotices, kind, ids),
    [draftGenerationNotices],
  );
  const ensureEnoughDraftGenerationPointsFromServer = useCallback(
    async (pointsCost: number) => {
      try {
        const latestDashboard = await getPlatformProfileDashboardWithLocalWalletDelta(
          RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS,
        );
        platformBootstrap.setProfileDashboard(latestDashboard);
        const walletBalance = resolveProfileWalletBalance(latestDashboard);
        if (walletBalance >= pointsCost) {
          setDraftGenerationPointNotice(null);
          return true;
        }

        setDraftGenerationPointNotice({
          title: '泥点不足',
          message: `本次需要 ${pointsCost} 泥点，当前 ${walletBalance} 泥点。`,
        });
        return false;
      } catch {
        setDraftGenerationPointNotice({
          title: '读取泥点余额失败',
          message: '请稍后重试。',
        });
        return false;
      }
    },
    [getPlatformProfileDashboardWithLocalWalletDelta, platformBootstrap],
  );

  const resolveBigFishErrorMessage = useCallback(
    (error: unknown, fallback: string) =>
      resolveRpgCreationErrorMessage(error, fallback),
    [],
  );
  const resolvePuzzleErrorMessage = useCallback(
    (error: unknown, fallback: string) =>
      resolveRpgCreationErrorMessage(error, fallback),
    [],
  );
  const resolveMatch3DErrorMessage = useCallback(
    (error: unknown, fallback: string) =>
      resolveRpgCreationErrorMessage(error, fallback),
    [],
  );
  const resolveSquareHoleErrorMessage = useCallback(
    (error: unknown, fallback: string) =>
      resolveRpgCreationErrorMessage(error, fallback),
    [],
  );
  const resolveBarkBattleErrorMessage = useCallback(
    (error: unknown, fallback: string) =>
      resolveRpgCreationErrorMessage(error, fallback),
    [],
  );

  const refreshBigFishShelf = useCallback(async () => {
    setIsBigFishLoadingLibrary(true);

    try {
      const worksResponse = await listBigFishWorks();
      setBigFishWorks(worksResponse.items);
      bigFishErrorSetterRef.current(null);
    } catch (error) {
      bigFishErrorSetterRef.current(
        resolveBigFishErrorMessage(error, '读取大鱼吃小鱼作品列表失败。'),
      );
    } finally {
      setIsBigFishLoadingLibrary(false);
    }
  }, [resolveBigFishErrorMessage]);

  const refreshBigFishGallery = useCallback(async () => {
    try {
      const galleryResponse = await listBigFishGallery();
      setBigFishGalleryEntries(galleryResponse.items);
      return galleryResponse.items;
    } catch (error) {
      setBigFishGalleryEntries([]);
      bigFishErrorSetterRef.current(
        resolveBigFishErrorMessage(error, '读取大鱼吃小鱼广场失败。'),
      );
      return [];
    }
  }, [resolveBigFishErrorMessage]);

  const refreshMatch3DShelf = useCallback(async () => {
    setIsMatch3DLoadingLibrary(true);

    try {
      const worksResponse = await listMatch3DWorks();
      setMatch3DWorks(mapMatch3DWorksForRuntimeUi(worksResponse.items));
      match3DErrorSetterRef.current(null);
    } catch (error) {
      match3DErrorSetterRef.current(
        resolveMatch3DErrorMessage(error, '读取抓大鹅作品列表失败。'),
      );
    } finally {
      setIsMatch3DLoadingLibrary(false);
    }
  }, [resolveMatch3DErrorMessage]);

  const refreshMatch3DGallery = useCallback(async () => {
    try {
      const galleryResponse = await listMatch3DGallery();
      const items = mapMatch3DWorksForRuntimeUi(galleryResponse.items);
      setMatch3DGalleryEntries(items);
      return items;
    } catch {
      // 中文注释：公开广场是首页展示数据，失败时只降级为空列表；
      // 不写入创作错误态，避免挡住抓大鹅共创入口。
      setMatch3DGalleryEntries([]);
      return [];
    }
  }, []);

  const refreshSquareHoleShelf = useCallback(async () => {
    setIsSquareHoleLoadingLibrary(true);

    try {
      const worksResponse = await listSquareHoleWorks();
      setSquareHoleWorks(worksResponse.items);
      squareHoleErrorSetterRef.current(null);
    } catch (error) {
      squareHoleErrorSetterRef.current(
        resolveSquareHoleErrorMessage(error, '读取方洞挑战作品列表失败。'),
      );
    } finally {
      setIsSquareHoleLoadingLibrary(false);
    }
  }, [resolveSquareHoleErrorMessage]);

  const refreshSquareHoleGallery = useCallback(async () => {
    try {
      const galleryResponse = await listSquareHoleGallery();
      setSquareHoleGalleryEntries(galleryResponse.items);
      return galleryResponse.items;
    } catch {
      setSquareHoleGalleryEntries([]);
      return [];
    }
  }, []);

  const refreshJumpHopGallery = useCallback(async () => {
    try {
      const galleryResponse = await jumpHopClient.listGallery();
      setJumpHopGalleryEntries(galleryResponse.items);
      return galleryResponse.items;
    } catch {
      setJumpHopGalleryEntries([]);
      return [];
    }
  }, []);

  const refreshJumpHopShelf = useCallback(async () => {
    if (!isJumpHopCreationVisible) {
      setJumpHopWorks([]);
      return [];
    }

    try {
      const worksResponse = await jumpHopClient.listWorks();
      setJumpHopWorks(worksResponse.items);
      return worksResponse.items;
    } catch {
      setJumpHopWorks([]);
      return [];
    }
  }, [isJumpHopCreationVisible]);

  const refreshWoodenFishGallery = useCallback(async () => {
    try {
      const galleryResponse = await woodenFishClient.listGallery();
      setWoodenFishGalleryEntries(galleryResponse.items);
      return galleryResponse.items;
    } catch {
      setWoodenFishGalleryEntries([]);
      return [];
    }
  }, []);

  const refreshWoodenFishShelf = useCallback(async () => {
    try {
      const worksResponse = await woodenFishClient.listWorks();
      setWoodenFishWorks(worksResponse.items);
      return worksResponse.items;
    } catch (error) {
      setWoodenFishWorks([]);
      setWoodenFishError(
        resolvePuzzleErrorMessage(error, '读取敲木鱼作品列表失败。'),
      );
      return [];
    }
  }, [resolvePuzzleErrorMessage]);

  const refreshPuzzleShelf = useCallback(async () => {
    setIsPuzzleLoadingLibrary(true);

    try {
      const worksResponse = await listPuzzleWorks();
      setPuzzleWorks(worksResponse.items);
      setPuzzleShelfError(null);
    } catch (error) {
      setPuzzleShelfError(
        resolvePuzzleErrorMessage(error, '读取拼图作品列表失败。'),
      );
    } finally {
      setIsPuzzleLoadingLibrary(false);
    }
  }, [resolvePuzzleErrorMessage]);

  const refreshPuzzleGallery = useCallback(async () => {
    try {
      const galleryResponse = await listPuzzleGallery();
      setPuzzleGalleryEntries(galleryResponse.items);
      return galleryResponse.items;
    } catch (error) {
      setPuzzleGalleryEntries([]);
      puzzleErrorSetterRef.current(
        resolvePuzzleErrorMessage(error, '读取拼图广场失败。'),
      );
      return [];
    }
  }, [resolvePuzzleErrorMessage]);

  const refreshVisualNovelShelf = useCallback(async () => {
    if (!isVisualNovelCreationOpen) {
      setVisualNovelWorks([]);
      visualNovelErrorSetterRef.current(null);
      return [];
    }

    setIsVisualNovelLoadingLibrary(true);

    try {
      const worksResponse = await listVisualNovelWorks();
      setVisualNovelWorks(worksResponse.works);
      visualNovelErrorSetterRef.current(null);
      return worksResponse.works;
    } catch (error) {
      visualNovelErrorSetterRef.current(
        resolvePuzzleErrorMessage(error, '读取视觉小说作品列表失败。'),
      );
      return [];
    } finally {
      setIsVisualNovelLoadingLibrary(false);
    }
  }, [isVisualNovelCreationOpen, resolvePuzzleErrorMessage]);

  const refreshVisualNovelGallery = useCallback(async () => {
    if (!isVisualNovelCreationOpen) {
      setVisualNovelGalleryEntries([]);
      visualNovelErrorSetterRef.current(null);
      return [];
    }

    try {
      const galleryResponse = await listVisualNovelGallery();
      setVisualNovelGalleryEntries(galleryResponse.works);
      return galleryResponse.works;
    } catch (error) {
      setVisualNovelGalleryEntries([]);
      visualNovelErrorSetterRef.current(
        resolvePuzzleErrorMessage(error, '读取视觉小说广场失败。'),
      );
      return [];
    }
  }, [isVisualNovelCreationOpen, resolvePuzzleErrorMessage]);

  const refreshBarkBattleShelf = useCallback(async () => {
    setIsBarkBattleBusy(true);

    try {
      const worksResponse = await listBarkBattleWorks();
      const works = mergeBarkBattleWorksByWorkId(worksResponse.items);
      setBarkBattleWorks((current) =>
        mergeBarkBattleWorksByWorkId([
          ...works,
          ...current.filter((item) =>
            shouldPreserveLocalBarkBattleWorkOnRefresh(item, works),
          ),
        ]),
      );
      setBarkBattleError(null);
      return works;
    } catch (error) {
      setBarkBattleError(
        resolvePuzzleErrorMessage(error, '读取汪汪声浪作品列表失败。'),
      );
      return [];
    } finally {
      setIsBarkBattleBusy(false);
    }
  }, [resolvePuzzleErrorMessage]);

  const refreshBarkBattleGallery = useCallback(async () => {
    try {
      const galleryResponse = await listBarkBattleGallery();
      setBarkBattleGalleryEntries(galleryResponse.items);
      return galleryResponse.items;
    } catch {
      // 中文注释：公开广场读取失败只降级为空列表，避免阻断平台首页。
      setBarkBattleGalleryEntries([]);
      return [];
    }
  }, []);

  const syncUpdatedPublicWorkDetail = useCallback(
    (updatedEntry: PlatformPublicGalleryCard) => {
      setSelectedPublicWorkDetail((current) =>
        current && isSamePlatformPublicGalleryEntry(current, updatedEntry)
          ? updatedEntry
          : current,
      );
    },
    [],
  );

  const handleRpgDraftGenerationStarted = useCallback(
    (sessionId: string) => {
      markDraftGenerating('rpg', [sessionId, `draft:${sessionId}`]);
    },
    [markDraftGenerating],
  );
  const updateBarkBattleWorkCaches = useCallback(
    (updated: BarkBattleWorkSummary) => {
      setBarkBattleWorks((current) => {
        const deduped = mergeBarkBattleWorksByWorkId(current);
        const hasExisting = deduped.some(
          (item) => item.workId === updated.workId,
        );
        if (hasExisting) {
          return deduped.map((item) =>
            mergeBarkBattleWorkSummary(item, updated),
          );
        }
        return [updated, ...deduped];
      });
      setBarkBattleGalleryEntries((current) => {
        const hasExisting = current.some(
          (item) => item.workId === updated.workId,
        );
        if (updated.status !== 'published') {
          return hasExisting
            ? current.map((item) => mergeBarkBattleWorkSummary(item, updated))
            : current;
        }
        if (hasExisting) {
          return current.map((item) =>
            mergeBarkBattleWorkSummary(item, updated),
          );
        }
        return [updated, ...current];
      });
      if (updated.status === 'published') {
        syncUpdatedPublicWorkDetail(
          mapBarkBattleWorkToPublicWorkDetail(updated),
        );
      }
    },
    [syncUpdatedPublicWorkDetail],
  );

  const handleRpgDraftGenerationCompleted = useCallback(
    ({
      sessionId,
      profileId,
      viewedImmediately,
    }: {
      sessionId: string;
      profileId: string | null;
      viewedImmediately: boolean;
    }) => {
      markDraftReady(
        'rpg',
        [sessionId, `draft:${sessionId}`, profileId],
        viewedImmediately,
      );
      void platformBootstrap.refreshCustomWorldWorks().catch(() => undefined);
    },
    [markDraftReady, platformBootstrap],
  );

  const refreshBabyObjectMatchShelf = useCallback(async () => {
    setBabyObjectMatchDrafts(await listLocalBabyObjectMatchDrafts());
  }, []);

  useEffect(() => {
    if (!platformBootstrap.canReadProtectedData) {
      setBarkBattleWorks([]);
      return;
    }

    if (
      platformBootstrap.platformTab === 'create' ||
      selectionStage === 'platform'
    ) {
      void refreshBarkBattleShelf();
    }
  }, [
    platformBootstrap.canReadProtectedData,
    platformBootstrap.platformTab,
    refreshBarkBattleShelf,
    selectionStage,
  ]);

  useEffect(() => {
    if (!platformBootstrap.canReadProtectedData) {
      setJumpHopWorks([]);
      return;
    }

    if (
      platformBootstrap.platformTab === 'create' ||
      selectionStage === 'platform'
    ) {
      void refreshJumpHopShelf();
    }
  }, [
    platformBootstrap.canReadProtectedData,
    platformBootstrap.platformTab,
    refreshJumpHopShelf,
    selectionStage,
  ]);

  const sessionController = useRpgCreationSessionController({
    userId: authUi?.user?.id,
    openLoginModal: authUi?.openLoginModal,
    selectionStage,
    setSelectionStage,
    enterCreateTab,
    onSessionOpened: () => {
      setShowCreationTypeModal(false);
    },
    onDraftGenerationStarted: handleRpgDraftGenerationStarted,
    onDraftGenerationCompleted: handleRpgDraftGenerationCompleted,
  });

  useRpgCreationAgentOperationPolling({
    activeAgentSessionId: sessionController.activeAgentSessionId,
    activeAgentOperationId: sessionController.activeAgentOperationId,
    userId: authUi?.user?.id,
    setAgentOperation: sessionController.setAgentOperation,
    persistAgentUiState: sessionController.persistAgentUiState,
    syncAgentSessionSnapshot: sessionController.syncAgentSessionSnapshot,
  });

  const autosaveCoordinator = useRpgCreationResultAutosave({
    selectionStage,
    activeAgentSessionId: sessionController.activeAgentSessionId,
    generatedCustomWorldProfile: sessionController.generatedCustomWorldProfile,
    isAgentDraftResultView: sessionController.isAgentDraftResultView,
    userId: authUi?.user?.id,
    setGeneratedCustomWorldProfile:
      sessionController.setGeneratedCustomWorldProfile,
    setAgentOperation: sessionController.setAgentOperation,
    setSavedCustomWorldEntries: platformBootstrap.setSavedCustomWorldEntries,
    setSelectedDetailEntry,
    refreshCustomWorldWorks: platformBootstrap.refreshCustomWorldWorks,
    persistAgentUiState: sessionController.persistAgentUiState,
    syncAgentSessionSnapshot: sessionController.syncAgentSessionSnapshot,
    syncAgentCreationResultView: sessionController.syncAgentCreationResultView,
    buildDraftResultProfile: (view) =>
      rpgCreationPreviewAdapter.buildPreviewFromResultView(view),
  });

  const detailNavigation = usePlatformEntryLibraryDetail({
    userId: authUi?.user?.id,
    selectedDetailEntry,
    setSelectedDetailEntry,
    savedCustomWorldEntries: platformBootstrap.savedCustomWorldEntries,
    setSavedCustomWorldEntries: platformBootstrap.setSavedCustomWorldEntries,
    setGeneratedCustomWorldProfile:
      sessionController.setGeneratedCustomWorldProfile,
    setCustomWorldError: sessionController.setCustomWorldError,
    setCustomWorldAutoSaveError:
      autosaveCoordinator.setCustomWorldAutoSaveError,
    setCustomWorldAutoSaveState:
      autosaveCoordinator.setCustomWorldAutoSaveState,
    setCustomWorldGenerationViewSource:
      sessionController.setCustomWorldGenerationViewSource,
    setCustomWorldResultViewSource:
      sessionController.setCustomWorldResultViewSource,
    setSelectionStage,
    setPlatformTabToCreate: enterCreateTab,
    setPlatformTabToDraft: enterDraftTab,
    setPlatformError: platformBootstrap.setPlatformError,
    appendBrowseHistoryEntry: platformBootstrap.appendBrowseHistoryEntry,
    refreshCustomWorldWorks: platformBootstrap.refreshCustomWorldWorks,
    refreshPublishedGallery: platformBootstrap.refreshPublishedGallery,
    persistAgentUiState: sessionController.persistAgentUiState,
    syncAgentCreationResultView: sessionController.syncAgentCreationResultView,
    buildDraftResultProfile: (view) =>
      rpgCreationPreviewAdapter.buildPreviewFromResultView(view),
    suppressAgentDraftResultAutoOpen:
      sessionController.suppressAgentDraftResultAutoOpen,
    releaseAgentDraftResultAutoOpenSuppression:
      sessionController.releaseAgentDraftResultAutoOpenSuppression,
    resetAutoSaveTrackingToIdle:
      autosaveCoordinator.resetAutoSaveTrackingToIdle,
    markAutoSavedProfile: autosaveCoordinator.markAutoSavedProfile,
  });

  const enterWorldCoordinator = useRpgCreationEnterWorld({
    isAgentDraftResultView: sessionController.isAgentDraftResultView,
    activeAgentSessionId: sessionController.activeAgentSessionId,
    currentAgentSessionStage: sessionController.agentSession?.stage ?? null,
    generatedCustomWorldProfile: sessionController.generatedCustomWorldProfile,
    handleCustomWorldSelect,
    syncAgentDraftResultProfile:
      autosaveCoordinator.syncAgentDraftResultProfile,
    executePublishWorld: async () => {
      const latestSession = await autosaveCoordinator.executeAgentActionAndWait(
        {
          action: 'publish_world',
        },
      );
      // 发布动作会在后端同步 gallery 投影；前端发布完成后立即刷新首页/分类页共用的公开作品列表。
      await Promise.allSettled([
        platformBootstrap.refreshPublishedGallery(),
        platformBootstrap.refreshCustomWorldWorks(),
        isBigFishCreationVisible
          ? refreshBigFishGallery()
          : Promise.resolve([] as BigFishWorkSummary[]),
        refreshMatch3DGallery(),
        refreshPuzzleGallery(),
        refreshBarkBattleGallery(),
      ]);
      return latestSession;
    },
    syncAgentCreationResultView: sessionController.syncAgentCreationResultView,
    setGeneratedCustomWorldProfile:
      sessionController.setGeneratedCustomWorldProfile,
  });

  const previewCustomWorldCharacters = useMemo(
    () =>
      sessionController.generatedCustomWorldProfile
        ? buildCustomWorldPlayableCharacters(
            sessionController.generatedCustomWorldProfile,
          )
        : [],
    [sessionController.generatedCustomWorldProfile],
  );
  const agentResultPreview =
    sessionController.agentSession?.resultPreview ?? null;
  const agentResultPreviewBlockers = useMemo(
    () => agentResultPreview?.blockers ?? [],
    [agentResultPreview],
  );
  const agentResultPublishGateView = useMemo(
    () =>
      buildPlatformRpgAgentResultPublishGateView(
        sessionController.generatedCustomWorldProfile,
        agentResultPreviewBlockers,
        Boolean(agentResultPreview?.publishReady),
      ),
    [
      agentResultPreview?.publishReady,
      agentResultPreviewBlockers,
      sessionController.generatedCustomWorldProfile,
    ],
  );
  const agentResultPreviewQualityFindings = useMemo(
    () => agentResultPreview?.qualityFindings ?? [],
    [agentResultPreview],
  );

  const openPublishShareModal = useCallback(
    (payload: PublishShareModalPayload) => {
      const publicWorkCode = payload.publicWorkCode.trim();
      if (!publicWorkCode) {
        return;
      }

      setPublishSharePayload({
        ...payload,
        publicWorkCode,
        title: payload.title.trim() || '我的作品',
      });
    },
    [],
  );

  const openRpgPublishShareModal = useCallback(
    async (profile: CustomWorldProfile | null | undefined) => {
      const profileId = profile?.id?.trim();
      if (!profileId) {
        return;
      }
      const profileName = profile?.name?.trim() || '我的作品';

      const galleryEntries = await platformBootstrap
        .refreshPublishedGallery()
        .catch(() => [] as CustomWorldGalleryCard[]);
      const galleryEntry = galleryEntries.find(
        (entry) => entry.profileId === profileId,
      );
      const publicWorkCode = galleryEntry?.publicWorkCode?.trim();
      if (!publicWorkCode) {
        return;
      }

      openPublishShareModal({
        title: galleryEntry?.worldName || profileName,
        publicWorkCode,
        stage: 'work-detail',
      });
    },
    [openPublishShareModal, platformBootstrap],
  );
  const agentResultPreviewSourceLabel = useMemo(() => {
    return resolvePlatformRpgAgentResultPreviewSourceLabel(
      agentResultPreview?.source,
    );
  }, [agentResultPreview]);
  const publicGalleryFeeds = useMemo(
    () =>
      buildPlatformPublicGalleryFeeds({
        rpgEntries: platformBootstrap.publishedGalleryEntries,
        bigFishEntries: bigFishGalleryEntries,
        match3dEntries: match3dGalleryEntries,
        puzzleEntries: puzzleGalleryEntries,
        barkBattleGalleryEntries,
        barkBattleWorks,
        jumpHopEntries: jumpHopGalleryEntries,
        woodenFishEntries: woodenFishGalleryEntries,
        squareHoleEntries: squareHoleGalleryEntries,
        visualNovelEntries: visualNovelGalleryEntries,
        babyObjectMatchDrafts,
        isBigFishCreationVisible,
        isBabyObjectMatchVisible,
        isVisualNovelCreationOpen,
      }),
    [
      babyObjectMatchDrafts,
      barkBattleGalleryEntries,
      barkBattleWorks,
      bigFishGalleryEntries,
      isBabyObjectMatchVisible,
      isBigFishCreationVisible,
      isVisualNovelCreationOpen,
      jumpHopGalleryEntries,
      match3dGalleryEntries,
      platformBootstrap.publishedGalleryEntries,
      puzzleGalleryEntries,
      squareHoleGalleryEntries,
      visualNovelGalleryEntries,
      woodenFishGalleryEntries,
    ],
  );
  const { featuredEntries: featuredGalleryEntries, latestEntries: latestGalleryEntries } =
    publicGalleryFeeds;
  const recommendRuntimeEntries = useMemo(
    () =>
      buildPlatformRecommendFeedEntries(
        featuredGalleryEntries,
        latestGalleryEntries,
      ),
    [featuredGalleryEntries, latestGalleryEntries],
  );

  const creationHubItems = useMemo<CustomWorldWorkSummary[]>(
    () =>
      platformBootstrap.customWorldWorkEntries.length > 0
        ? platformBootstrap.customWorldWorkEntries
        : buildCreationHubFallbackItems(
            platformBootstrap.savedCustomWorldEntries,
          ),
    [
      platformBootstrap.customWorldWorkEntries,
      platformBootstrap.savedCustomWorldEntries,
    ],
  );
  const bigFishShelfItems = useMemo(
    () => [
      ...buildPendingBigFishWorks(
        pendingDraftShelfItems['big-fish'],
        bigFishWorks,
      ),
      ...bigFishWorks,
    ],
    [bigFishWorks, pendingDraftShelfItems],
  );
  const jumpHopShelfItems = useMemo(
    () => [
      ...buildPendingJumpHopWorks(
        pendingDraftShelfItems['jump-hop'],
        jumpHopWorks,
      ),
      ...jumpHopWorks,
    ],
    [jumpHopWorks, pendingDraftShelfItems],
  );
  const woodenFishShelfItems = useMemo(
    () => [
      ...buildPendingWoodenFishWorks(
        pendingDraftShelfItems['wooden-fish'],
        woodenFishWorks,
      ),
      ...woodenFishWorks,
    ],
    [pendingDraftShelfItems, woodenFishWorks],
  );
  const match3dShelfItems = useMemo(
    () => [
      ...buildPendingMatch3DWorks(pendingDraftShelfItems.match3d, match3dWorks),
      ...match3dWorks,
    ],
    [match3dWorks, pendingDraftShelfItems],
  );
  const squareHoleShelfItems = useMemo(
    () => [
      ...buildPendingSquareHoleWorks(
        pendingDraftShelfItems['square-hole'],
        squareHoleWorks,
      ),
      ...squareHoleWorks,
    ],
    [pendingDraftShelfItems, squareHoleWorks],
  );
  const puzzleShelfItems = useMemo(
    () => [
      ...buildPendingPuzzleWorks(pendingDraftShelfItems.puzzle, puzzleWorks),
      ...puzzleWorks,
    ],
    [pendingDraftShelfItems, puzzleWorks],
  );
  const visualNovelShelfItems = useMemo(
    () =>
      isVisualNovelCreationOpen
        ? [
            ...buildPendingVisualNovelWorks(
              pendingDraftShelfItems['visual-novel'],
              visualNovelWorks,
            ),
            ...visualNovelWorks,
          ]
        : [],
    [isVisualNovelCreationOpen, pendingDraftShelfItems, visualNovelWorks],
  );
  const barkBattleShelfItems = useMemo(
    () => [
      ...buildPendingBarkBattleWorks(
        pendingDraftShelfItems['bark-battle'],
        barkBattleWorks,
      ),
      ...barkBattleWorks,
    ],
    [barkBattleWorks, pendingDraftShelfItems],
  );
  const getCreationWorkShelfState = useCallback(
    (item: CreationWorkShelfItem) =>
      buildCreationWorkShelfRuntimeState({
        item,
        notices: draftGenerationNotices,
        pendingShelfItems: pendingDraftShelfItems,
      }),
    [draftGenerationNotices, pendingDraftShelfItems],
  );
  const visibleDraftNoticeKeys = useMemo(
    () =>
      collectVisibleDraftNoticeKeys({
        rpgItems: creationHubItems,
        bigFishItems: bigFishShelfItems,
        jumpHopItems: jumpHopShelfItems,
        woodenFishItems: woodenFishShelfItems,
        match3dItems: match3dShelfItems,
        squareHoleItems: isSquareHoleCreationVisible
          ? squareHoleShelfItems
          : [],
        puzzleItems: puzzleShelfItems,
        visualNovelItems: visualNovelShelfItems,
        barkBattleItems: barkBattleShelfItems,
        babyObjectMatchItems: babyObjectMatchDrafts,
      }),
    [
      babyObjectMatchDrafts,
      barkBattleShelfItems,
      bigFishShelfItems,
      jumpHopShelfItems,
      woodenFishShelfItems,
      creationHubItems,
      isSquareHoleCreationVisible,
      match3dShelfItems,
      puzzleShelfItems,
      squareHoleShelfItems,
      visualNovelShelfItems,
    ],
  );
  const hasUnreadDraftUpdates = useMemo(
    () =>
      hasUnreadDraftGenerationUpdates(
        draftGenerationNotices,
        visibleDraftNoticeKeys,
      ),
    [draftGenerationNotices, visibleDraftNoticeKeys],
  );
  const resultViewError =
    autosaveCoordinator.customWorldAutoSaveError ??
    sessionController.customWorldError;
  const selectedPublicWorkActionMode = selectedPublicWorkDetail
    ? resolvePlatformPublicWorkActionMode(
        selectedPublicWorkDetail,
        authUi?.user?.id,
      )
    : 'remix';
  const isSelectedPublicWorkOwned = selectedPublicWorkActionMode === 'edit';

  useEffect(() => {
    if (
      selectionStage === 'custom-world-result' &&
      !sessionController.generatedCustomWorldProfile
    ) {
      setSelectionStage(selectedDetailEntry ? 'detail' : 'platform');
    }
  }, [
    selectedDetailEntry,
    selectionStage,
    sessionController.generatedCustomWorldProfile,
    setSelectionStage,
  ]);

  useEffect(() => {
    const progressTickDecision =
      resolvePlatformGenerationProgressTickDecision({
        selectionStage,
        miniGameStates: {
          puzzle: puzzleGenerationState,
          match3d: match3dGenerationState,
          'big-fish': bigFishGenerationState,
          'square-hole': squareHoleGenerationState,
          'jump-hop': jumpHopGenerationState,
          'wooden-fish': woodenFishGenerationState,
          'baby-object-match': babyObjectMatchGenerationState,
        },
        visualNovel: {
          startedAtMs: visualNovelGenerationStartedAtMs,
          phase: visualNovelGenerationPhase,
        },
      });

    if (!progressTickDecision.shouldTick) {
      return undefined;
    }

    setMiniGameGenerationProgressNowMs(Date.now());
    const timerId = window.setInterval(() => {
      setMiniGameGenerationProgressNowMs(Date.now());
    }, 500);

    return () => window.clearInterval(timerId);
  }, [
    babyObjectMatchGenerationState,
    bigFishGenerationState,
    jumpHopGenerationState,
    match3dGenerationState,
    puzzleGenerationState,
    selectionStage,
    squareHoleGenerationState,
    visualNovelGenerationPhase,
    visualNovelGenerationStartedAtMs,
    woodenFishGenerationState,
  ]);

  const runProtectedAction = useCallback(
    (action: () => void) => {
      if (!authUi?.requireAuth) {
        action();
        return;
      }

      authUi.requireAuth(action);
    },
    [authUi],
  );

  const savePuzzleOnboardingDraft = useCallback(async () => {
    if (!puzzleOnboardingDraft || isPuzzleOnboardingSaving) {
      return;
    }

    setIsPuzzleOnboardingSaving(true);
    setPuzzleOnboardingError(null);
    try {
      const response = await savePuzzleOnboardingWork({
        promptText: puzzleOnboardingDraft.promptText,
        item: puzzleOnboardingDraft.item,
      });
      setPuzzleWorks((current) => [response.item, ...current]);
      setSelectedPuzzleDetail(null);
      setPuzzleRun(null);
      setPuzzleRuntimeAuthMode('default');
      setPuzzleOnboardingDraft(null);
      setPuzzleOnboardingPrompt('');
      setPuzzleOnboardingPhase('input');
      platformBootstrap.setPlatformTab('home');
      setSelectionStage('platform');
      clearPuzzleRuntimeUrlState();
      void refreshPuzzleShelf();
    } catch (error) {
      setPuzzleOnboardingError(
        resolvePuzzleErrorMessage(error, '保存新手引导拼图失败。'),
      );
    } finally {
      setIsPuzzleOnboardingSaving(false);
    }
  }, [
    isPuzzleOnboardingSaving,
    platformBootstrap,
    puzzleOnboardingDraft,
    refreshPuzzleShelf,
    resolvePuzzleErrorMessage,
    setSelectionStage,
  ]);

  const requestPuzzleOnboardingLogin = useCallback(() => {
    if (isPuzzleOnboardingSaving) {
      return;
    }
    authUi?.openLoginModal(() => {
      void savePuzzleOnboardingDraft();
    });
  }, [authUi, isPuzzleOnboardingSaving, savePuzzleOnboardingDraft]);

  const skipPuzzleOnboarding = useCallback(() => {
    markPuzzleOnboardingSeen();
    setPuzzleOnboardingDraft(null);
    setPuzzleOnboardingPrompt('');
    setPuzzleOnboardingPhase('input');
    setPuzzleOnboardingError(null);
    setPuzzleRun(null);
    setPuzzleRuntimeAuthMode('default');
    setSelectedPuzzleDetail(null);
    platformBootstrap.setPlatformTab(authUi?.user ? 'home' : 'category');
    setSelectionStage('platform');
    clearPuzzleRuntimeUrlState();
  }, [authUi?.user, platformBootstrap, setSelectionStage]);

  useEffect(() => {
    if (
      !authUi ||
      authUi?.user ||
      selectionStage !== 'platform' ||
      hasSeenPuzzleOnboarding()
    ) {
      return;
    }

    setPuzzleOnboardingPhase('input');
    setPuzzleOnboardingError(null);
    setSelectionStage('puzzle-onboarding');
  }, [authUi, authUi?.user, selectionStage, setSelectionStage]);

  const submitPuzzleOnboardingPrompt = useCallback(async () => {
    const promptText = puzzleOnboardingPrompt.trim();
    if (!promptText || puzzleOnboardingPhase === 'generating') {
      return;
    }

    setPuzzleOnboardingPhase('generating');
    setPuzzleOnboardingError(null);
    try {
      let item: PuzzleWorkSummary;
      try {
        const response = await generatePuzzleOnboardingWork({ promptText });
        item = {
          ...response.item,
          levels:
            response.item.levels && response.item.levels.length > 0
              ? response.item.levels
              : [response.level],
        };
      } catch (error) {
        if (!shouldUseLocalPuzzleOnboardingFallback(error)) {
          throw error;
        }

        // 中文注释：旧后端或资源路由尚未更新时，首访体验继续用前端临时图面兜底，不写入作品库。
        item = buildPuzzleOnboardingFallbackWork(promptText);
      }
      setPuzzleOnboardingDraft({ promptText, item });
      setSelectedPuzzleDetail(item);
      setPuzzleOnboardingPhase('generated');
      markPuzzleOnboardingSeen();
      window.setTimeout(() => {
        setPuzzleRun(startLocalPuzzleRun(item));
        setPuzzleRuntimeAuthMode('default');
        setPuzzleRuntimeReturnStage('platform');
        openPuzzleRuntimeStage(
          setSelectionStage,
          buildPuzzleDraftRuntimeUrlState(item, null),
        );
      }, PUZZLE_ONBOARDING_GENERATED_DELAY_MS);
    } catch (error) {
      setPuzzleOnboardingPhase('input');
      setPuzzleOnboardingError(
        resolvePuzzleErrorMessage(error, '生成新手引导拼图失败。'),
      );
    }
  }, [
    puzzleOnboardingPhase,
    puzzleOnboardingPrompt,
    resolvePuzzleErrorMessage,
    setSelectionStage,
  ]);

  const requestDeleteCreationWork = useCallback(
    (confirmation: DeleteCreationWorkConfirmation) => {
      if (deletingCreationWorkId) {
        return;
      }

      runProtectedAction(() => {
        setPendingDeleteCreationWork(confirmation);
      });
    },
    [deletingCreationWorkId, runProtectedAction],
  );

  const closeDeleteCreationWorkConfirmation = useCallback(() => {
    if (deletingCreationWorkId) {
      return;
    }

    setPendingDeleteCreationWork(null);
  }, [deletingCreationWorkId]);

  const confirmDeleteCreationWork = useCallback(() => {
    const confirmation = pendingDeleteCreationWork;
    if (!confirmation || deletingCreationWorkId) {
      return;
    }

    setPendingDeleteCreationWork(null);
    confirmation.run();
  }, [deletingCreationWorkId, pendingDeleteCreationWork]);

  const prepareCreationLaunch = useCallback(() => {
    if (sessionController.isCreatingAgentSession) {
      return false;
    }

    if (!hasSavedGame) {
      handleStartNewGame();
    }

    markCreationFlowReturnToCreate();
    sessionController.setCreationTypeError(null);
    return true;
  }, [
    handleStartNewGame,
    hasSavedGame,
    markCreationFlowReturnToCreate,
    sessionController,
  ]);

  const openCreationTypePicker = useCallback(() => {
    if (!prepareCreationLaunch()) {
      return;
    }

    setShowCreationTypeModal(true);
  }, [prepareCreationLaunch]);

  const bigFishFlow = usePlatformCreationAgentFlowController<
    BigFishSessionSnapshotResponse,
    Record<string, never>,
    { session: BigFishSessionSnapshotResponse },
    SendBigFishMessageRequest,
    ExecuteBigFishActionRequest,
    { session: BigFishSessionSnapshotResponse }
  >({
    client: {
      createSession: createBigFishCreationSession,
      getSession: getBigFishCreationSession,
      streamMessage: streamBigFishCreationMessage,
      executeAction: executeBigFishCreationAction,
      selectSession: (response) => response.session,
    },
    createPayload: {},
    workspaceStage: 'big-fish-agent-workspace',
    resultStage: 'big-fish-result',
    platformStage: 'platform',
    isCompileAction: (payload) => payload.action === 'big_fish_compile_draft',
    resolveErrorMessage: resolveBigFishErrorMessage,
    errorMessages: {
      open: '开启大鱼吃小鱼共创工作台失败。',
      restoreMissingSession: '这份大鱼吃小鱼草稿缺少会话信息，请重新开始创作。',
      restore: '读取大鱼吃小鱼创作草稿失败。',
      submit: '发送大鱼吃小鱼共创消息失败。',
      execute: '执行大鱼吃小鱼操作失败。',
    },
    enterCreateTab,
    setSelectionStage,
    onSessionOpened: () => {
      setShowCreationTypeModal(false);
    },
    onSessionChanged: (session) => {
      writeCreationUrlState(buildBigFishCreationUrlState(session));
    },
    onActionComplete: ({ payload, response, setSession }) => {
      setSession(response.session);
      if (payload.action === 'big_fish_publish_game') {
        void refreshBigFishShelf();
        void refreshBigFishGallery();
        openPublishShareModal({
          title: response.session.draft?.title ?? '大鱼吃小鱼',
          publicWorkCode: buildBigFishPublicWorkCode(
            response.session.sessionId,
          ),
          stage: 'big-fish-runtime',
        });
      }
      if (payload.action !== 'big_fish_compile_draft') {
        return;
      }
      setBigFishGenerationState((current) =>
        current
          ? resolveFinishedMiniGameDraftGenerationState(current, 'ready', {
              completedAssetCount: response.session.assetSlots.filter(
                (slot) => slot.status === 'ready',
              ).length,
              totalAssetCount: response.session.assetSlots.length,
            })
          : current,
      );
      const openResult = selectionStageRef.current === 'big-fish-generating';
      const noticeIds = [
        `big-fish-work-${response.session.sessionId}`,
        response.session.sessionId,
      ];
      markPendingDraftReady('big-fish', response.session.sessionId, openResult);
      markDraftReady('big-fish', noticeIds, openResult);
      void refreshBigFishShelf();
      return { openResult };
    },
    beforeExecuteAction: ({ payload, session }) => {
      if (payload.action !== 'big_fish_compile_draft') {
        return;
      }
      markDraftGenerating('big-fish', [
        `big-fish-work-${session.sessionId}`,
        session.sessionId,
      ]);
      markPendingDraftGenerating('big-fish', session.sessionId);
      selectionStageRef.current = 'big-fish-generating';
      setSelectionStage('big-fish-generating');
      setBigFishGenerationState(createMiniGameDraftGenerationState('big-fish'));
    },
    onActionError: ({ payload, errorMessage, session }) => {
      if (payload.action !== 'big_fish_compile_draft') {
        return;
      }
      setBigFishGenerationState((current) =>
        current
          ? resolveFinishedMiniGameDraftGenerationState(current, 'failed', {
              error: errorMessage,
            })
          : current,
      );
      markPendingDraftFailed('big-fish', session.sessionId);
      markDraftFailed(
        'big-fish',
        [`big-fish-work-${session.sessionId}`, session.sessionId],
        errorMessage,
      );
      void refreshBigFishShelf();
    },
  });

  const match3dRuntimeAdapter = useMemo(
    () => createServerMatch3DRuntimeAdapter(),
    [],
  );
  const resolveMatch3DRuntimeAdapter = useCallback(
    (_profileId: string | null | undefined) => match3dRuntimeAdapter,
    [match3dRuntimeAdapter],
  );
  const match3dFlow = usePlatformCreationAgentFlowController<
    Match3DAgentSessionSnapshot,
    CreateMatch3DSessionRequest,
    Match3DSessionResponse,
    SendMatch3DMessageRequest,
    ExecuteMatch3DActionRequest,
    Match3DActionResponse
  >({
    client: {
      createSession: match3dCreationClient.createSession,
      getSession: match3dCreationClient.getSession,
      streamMessage: match3dCreationClient.streamMessage,
      executeAction: match3dCreationClient.executeAction,
      selectSession: (response) => response.session,
    },
    createPayload: {},
    workspaceStage: 'match3d-agent-workspace',
    resultStage: 'match3d-result',
    platformStage: 'platform',
    isCompileAction: (payload) => payload.action === 'match3d_compile_draft',
    resolveErrorMessage: resolveMatch3DErrorMessage,
    errorMessages: {
      open: '开启抓大鹅共创工作台失败。',
      restoreMissingSession: '这份抓大鹅草稿缺少会话信息，请重新开始创作。',
      restore: '读取抓大鹅创作草稿失败。',
      submit: '发送抓大鹅共创消息失败。',
      execute: '执行抓大鹅操作失败。',
    },
    enterCreateTab,
    setSelectionStage,
    onSessionOpened: () => {
      setShowCreationTypeModal(false);
    },
    onSessionChanged: (session) => {
      writeCreationUrlState(buildMatch3DCreationUrlState(session));
    },
    onActionComplete: async ({ payload, response, setSession }) => {
      setSession(response.session);
      if (payload.action !== 'match3d_compile_draft') {
        return;
      }
      const openResult = selectionStageRef.current === 'match3d-generating';
      setMatch3DGenerationState((current) =>
        current
          ? resolveFinishedMiniGameDraftGenerationState(current, 'ready', {
              completedAssetCount:
                response.session.draft?.generatedItemAssets?.length ?? 5,
              totalAssetCount:
                response.session.draft?.generatedItemAssets?.length ?? 5,
            })
          : current,
      );

      const profileId = response.session.draft?.profileId;
      if (!profileId) {
        setMatch3DProfile(null);
        setMatch3DRuntimeProfile(null);
        return { openResult };
      }

      let runtimeProfile: Match3DWorkProfile | null = null;
      try {
        const { item } = await getMatch3DWorkDetail(profileId);
        runtimeProfile = normalizeMatch3DWorkForRuntimeUi({
          ...item,
          generatedItemAssets: mergeMatch3DGeneratedItemAssetsForRuntime(
            response.session.draft?.generatedItemAssets,
            item.generatedItemAssets,
          ),
        });
        setMatch3DProfile(runtimeProfile);
        await refreshMatch3DShelf().catch(() => undefined);
      } catch {
        runtimeProfile = buildMatch3DProfileFromSession(response.session);
        setMatch3DProfile(runtimeProfile);
      }
      markPendingDraftReady('match3d', response.session.sessionId, openResult);
      markDraftReady(
        'match3d',
        [profileId, response.session.sessionId],
        openResult,
      );
      if (openResult && runtimeProfile) {
        try {
          await preloadMatch3DGeneratedRuntimeAssets(
            runtimeProfile.generatedItemAssets,
            runtimeProfile.generatedBackgroundAsset,
            { expireSeconds: 300 },
          );
          const { run } = await match3dRuntimeAdapter.startRun(
            runtimeProfile.profileId,
          );
          setMatch3DRuntimeProfile(runtimeProfile);
          setMatch3DRun(run);
          setMatch3DProfile(runtimeProfile);
          setMatch3DRuntimeReturnStage('match3d-result');
          setSelectionStage('match3d-runtime');
        } catch (error) {
          setMatch3DError(
            resolveMatch3DErrorMessage(error, '启动抓大鹅玩法失败。'),
          );
          setSelectionStage('match3d-result');
        }
        return { openResult: false };
      }
      return { openResult };
    },
    beforeExecuteAction: ({ payload, session }) => {
      if (payload.action !== 'match3d_compile_draft') {
        return;
      }
      markDraftGenerating('match3d', [
        session.draft?.profileId,
        session.publishedProfileId,
        session.sessionId,
      ]);
      markPendingDraftGenerating('match3d', session.sessionId);
      selectionStageRef.current = 'match3d-generating';
      setSelectionStage('match3d-generating');
      setMatch3DGenerationState(
        createMiniGameDraftGenerationState(
          'match3d',
          resolveMiniGameDraftGenerationStartedAtMs(session.updatedAt),
        ),
      );
    },
    onActionError: async ({ payload, errorMessage, session, setSession }) => {
      if (payload.action !== 'match3d_compile_draft') {
        return;
      }
      if (isBackgroundGenerationStillRunningMessage(errorMessage)) {
        try {
          const { session: latestSession } =
            await match3dCreationClient.getSession(session.sessionId);
          setSession(latestSession);
          const profileId =
            latestSession.draft?.profileId ?? latestSession.publishedProfileId;
          if (profileId) {
            const { item } = await getMatch3DWorkDetail(profileId);
            setMatch3DProfile(normalizeMatch3DWorkForRuntimeUi(item));
          }
          markPendingDraftGenerating('match3d', latestSession.sessionId);
          markDraftGenerating('match3d', [
            latestSession.draft?.profileId,
            latestSession.publishedProfileId,
            latestSession.sessionId,
          ]);
          await refreshMatch3DShelf().catch(() => undefined);
          return;
        } catch {
          await refreshMatch3DShelf().catch(() => undefined);
        }
      }
      setMatch3DGenerationState((current) =>
        current
          ? resolveFinishedMiniGameDraftGenerationState(current, 'failed', {
              error: errorMessage,
            })
          : current,
      );
      markPendingDraftFailed('match3d', session.sessionId);
      markDraftFailed(
        'match3d',
        [session.draft?.profileId, session.publishedProfileId, session.sessionId],
        errorMessage,
      );
      try {
        const { session: latestSession } =
          await match3dCreationClient.getSession(session.sessionId);
        setSession(latestSession);
        const profileId =
          latestSession.draft?.profileId ?? latestSession.publishedProfileId;
        if (profileId) {
          const { item } = await getMatch3DWorkDetail(profileId);
          setMatch3DProfile(normalizeMatch3DWorkForRuntimeUi(item));
        }
        await refreshMatch3DShelf().catch(() => undefined);
      } catch {
        await refreshMatch3DShelf().catch(() => undefined);
      }
    },
  });

  const squareHoleFlow = usePlatformCreationAgentFlowController<
    SquareHoleSessionSnapshot,
    CreateSquareHoleSessionRequest,
    SquareHoleSessionResponse,
    SendSquareHoleMessageRequest,
    ExecuteSquareHoleActionRequest,
    SquareHoleActionResponse
  >({
    client: {
      createSession: squareHoleCreationClient.createSession,
      getSession: squareHoleCreationClient.getSession,
      streamMessage: squareHoleCreationClient.streamMessage,
      executeAction: squareHoleCreationClient.executeAction,
      selectSession: (response) => response.session,
    },
    createPayload: {},
    workspaceStage: 'square-hole-agent-workspace',
    resultStage: 'square-hole-result',
    platformStage: 'platform',
    isCompileAction: () => false,
    resolveErrorMessage: resolveSquareHoleErrorMessage,
    errorMessages: {
      open: '开启方洞挑战共创工作台失败。',
      restoreMissingSession: '这份方洞挑战草稿缺少会话信息，请重新开始创作。',
      restore: '读取方洞挑战创作草稿失败。',
      submit: '发送方洞挑战共创消息失败。',
      execute: '执行方洞挑战操作失败。',
    },
    enterCreateTab,
    setSelectionStage,
    onSessionOpened: () => {
      setShowCreationTypeModal(false);
    },
    onSessionChanged: (session) => {
      writeCreationUrlState(buildSquareHoleCreationUrlState(session));
    },
    beforeExecuteAction: ({ payload, session }) => {
      if (payload.action === 'square_hole_compile_draft') {
        markDraftGenerating('square-hole', [
          session.draft?.profileId,
          session.publishedProfileId,
          session.sessionId,
        ]);
        markPendingDraftGenerating('square-hole', session.sessionId);
        setSquareHoleGenerationState(
          createMiniGameDraftGenerationState('square-hole'),
        );
        selectionStageRef.current = 'square-hole-generating';
        setSelectionStage('square-hole-generating');
      }
      if (payload.action === 'square_hole_generate_visual_assets') {
        markDraftGenerating('square-hole', [
          session.draft?.profileId,
          session.publishedProfileId,
          session.sessionId,
        ]);
        markPendingDraftGenerating('square-hole', session.sessionId);
        setSquareHoleGenerationState((current) => ({
          ...(current ?? createMiniGameDraftGenerationState('square-hole')),
          phase: 'square-hole-cover',
          completedAssetCount: 0,
          totalAssetCount: 0,
          error: null,
        }));
        selectionStageRef.current = 'square-hole-generating';
        setSelectionStage('square-hole-generating');
      }
    },
    onActionComplete: async ({ payload, response, setSession }) => {
      setSession(response.session);
      if (
        payload.action !== 'square_hole_compile_draft' &&
        payload.action !== 'square_hole_generate_visual_assets'
      ) {
        return;
      }
      const shouldOpenSquareHoleResult = () =>
        selectionStageRef.current === 'square-hole-generating';

      const profileId = response.session.draft?.profileId;
      if (!profileId) {
        setSquareHoleProfile(null);
        markPendingDraftReady(
          'square-hole',
          response.session.sessionId,
          shouldOpenSquareHoleResult(),
        );
        markDraftReady(
          'square-hole',
          [response.session.sessionId, response.session.publishedProfileId],
          shouldOpenSquareHoleResult(),
        );
        return;
      }

      if (payload.action === 'square_hole_compile_draft') {
        try {
          const assetResponse = await squareHoleCreationClient.executeAction(
            response.session.sessionId,
            {
              action: 'square_hole_generate_visual_assets',
            },
          );
          setSession(assetResponse.session);
          const assetProfileId = assetResponse.session.draft?.profileId;
          if (!assetProfileId) {
            const shouldOpenResult = shouldOpenSquareHoleResult();
            setSquareHoleProfile(
              buildSquareHoleProfileFromSession(assetResponse.session),
            );
            markPendingDraftReady(
              'square-hole',
              assetResponse.session.sessionId,
              shouldOpenResult,
            );
            markDraftReady(
              'square-hole',
              [
                assetResponse.session.sessionId,
                assetResponse.session.publishedProfileId,
              ],
              shouldOpenResult,
            );
            if (shouldOpenResult) {
              setSelectionStage('square-hole-result');
            }
            return;
          }
          const { item } = await getSquareHoleWorkDetail(assetProfileId);
          const shouldOpenResult = shouldOpenSquareHoleResult();
          setSquareHoleProfile(item);
          setSquareHoleGenerationState((current) =>
            resolveFinishedMiniGameDraftGenerationState(
              current ?? createMiniGameDraftGenerationState('square-hole'),
              'ready',
              {
                completedAssetCount:
                  item.shapeOptions.length + item.holeOptions.length + 2,
                totalAssetCount:
                  item.shapeOptions.length + item.holeOptions.length + 2,
                error: null,
              },
            ),
          );
          await refreshSquareHoleShelf().catch(() => undefined);
          markPendingDraftReady(
            'square-hole',
            assetResponse.session.sessionId,
            shouldOpenResult,
          );
          markDraftReady(
            'square-hole',
            [assetProfileId, assetResponse.session.sessionId],
            shouldOpenResult,
          );
          if (shouldOpenResult) {
            setSelectionStage('square-hole-result');
          }
        } catch (error) {
          const shouldOpenResult = shouldOpenSquareHoleResult();
          const errorMessage = resolveSquareHoleErrorMessage(
            error,
            '生成方洞挑战图片失败。',
          );
          setSquareHoleError(errorMessage);
          setSquareHoleGenerationState((current) =>
            resolveFinishedMiniGameDraftGenerationState(
              current ?? createMiniGameDraftGenerationState('square-hole'),
              'failed',
              { error: errorMessage },
            ),
          );
          setSquareHoleProfile(
            buildSquareHoleProfileFromSession(response.session),
          );
          markPendingDraftFailed('square-hole', response.session.sessionId);
          markDraftFailed(
            'square-hole',
            [
              response.session.draft?.profileId,
              response.session.publishedProfileId,
              response.session.sessionId,
            ],
            errorMessage,
          );
          void refreshSquareHoleShelf().catch(() => undefined);
          if (shouldOpenResult) {
            setSelectionStage('square-hole-result');
          }
        }
        return;
      }

      try {
        const { item } = await getSquareHoleWorkDetail(profileId);
        const shouldOpenResult = shouldOpenSquareHoleResult();
        setSquareHoleProfile(item);
        setSquareHoleGenerationState((current) =>
          resolveFinishedMiniGameDraftGenerationState(
            current ?? createMiniGameDraftGenerationState('square-hole'),
            'ready',
            {
              completedAssetCount:
                item.shapeOptions.length + item.holeOptions.length + 2,
              totalAssetCount:
                item.shapeOptions.length + item.holeOptions.length + 2,
              error: null,
            },
          ),
        );
        await refreshSquareHoleShelf().catch(() => undefined);
        markPendingDraftReady(
          'square-hole',
          response.session.sessionId,
          shouldOpenResult,
        );
        markDraftReady(
          'square-hole',
          [profileId, response.session.sessionId],
          shouldOpenResult,
        );
        if (shouldOpenResult) {
          setSelectionStage('square-hole-result');
        }
      } catch {
        const shouldOpenResult = shouldOpenSquareHoleResult();
        setSquareHoleProfile(
          buildSquareHoleProfileFromSession(response.session),
        );
        markPendingDraftReady(
          'square-hole',
          response.session.sessionId,
          shouldOpenResult,
        );
        markDraftReady(
          'square-hole',
          [profileId, response.session.sessionId],
          shouldOpenResult,
        );
        if (shouldOpenResult) {
          setSelectionStage('square-hole-result');
        }
      }
    },
    onActionError: ({ payload, errorMessage, session }) => {
      if (
        payload.action === 'square_hole_compile_draft' ||
        payload.action === 'square_hole_generate_visual_assets'
      ) {
        setSquareHoleGenerationState((current) =>
          resolveFinishedMiniGameDraftGenerationState(
            current ?? createMiniGameDraftGenerationState('square-hole'),
            'failed',
            { error: errorMessage },
          ),
        );
        if (selectionStageRef.current === 'square-hole-generating') {
          setSelectionStage('square-hole-generating');
        }
        markPendingDraftFailed('square-hole', session.sessionId);
        markDraftFailed(
          'square-hole',
          [session.draft?.profileId, session.publishedProfileId, session.sessionId],
          errorMessage,
        );
        void refreshSquareHoleShelf().catch(() => undefined);
      }
    },
  });

  const puzzleFlow = usePlatformCreationAgentFlowController<
    PuzzleAgentSessionSnapshot,
    CreatePuzzleAgentSessionRequest,
    { session: PuzzleAgentSessionSnapshot },
    SendPuzzleAgentMessageRequest,
    PuzzleAgentActionRequest,
    {
      operation: PuzzleAgentOperationRecord;
      session: PuzzleAgentSessionSnapshot;
    }
  >({
    client: {
      createSession: createPuzzleAgentSession,
      getSession: getPuzzleAgentSession,
      streamMessage: streamPuzzleAgentMessage,
      executeAction: executePuzzleAgentAction,
      selectSession: (response) => response.session,
    },
    createPayload: {},
    workspaceStage: 'puzzle-agent-workspace',
    resultStage: 'puzzle-result',
    platformStage: 'platform',
    isCompileAction: (payload) => payload.action === 'compile_puzzle_draft',
    resolveErrorMessage: resolvePuzzleErrorMessage,
    errorMessages: {
      open: '开启拼图共创工作台失败。',
      restoreMissingSession: '这份拼图草稿缺少会话信息，请重新开始创作。',
      restore: '读取拼图创作草稿失败。',
      submit: '发送拼图共创消息失败。',
      execute: '执行拼图操作失败。',
    },
    enterCreateTab,
    setSelectionStage,
    onSessionOpened: () => {
      sessionController.setCreationTypeError(null);
      setPuzzleCreationError(null);
      setShowCreationTypeModal(false);
    },
    onSessionChanged: (session) => {
      writeCreationUrlState(buildPuzzleCreationUrlState(session));
    },
    onOpenError: ({ errorMessage }) => {
      sessionController.setCreationTypeError(errorMessage);
      setPuzzleCreationError(errorMessage);
    },
    onActionComplete: async ({ payload, response, setSession }) => {
      setPuzzleOperation(response.operation);
      setSession(response.session);
      const formPayload = buildPuzzleFormPayloadFromAction(payload);
      if (formPayload) {
        setPuzzleFormDraftPayload(formPayload);
      }

      if (
        payload.action === 'publish_puzzle_work' ||
        payload.action === 'generate_puzzle_tags' ||
        payload.action === 'compile_puzzle_draft' ||
        payload.action === 'generate_puzzle_images' ||
        payload.action === 'generate_puzzle_ui_background'
      ) {
        refreshPlatformDashboardSilently();
        await Promise.allSettled([
          refreshPuzzleShelf(),
          refreshPuzzleGallery(),
        ]);
      }

      if (payload.action === 'compile_puzzle_draft') {
        const openResult = selectionStageRef.current === 'puzzle-generating';
        setPuzzleGenerationState((current) =>
          current
            ? resolveFinishedMiniGameDraftGenerationState(current, 'ready', {
                completedAssetCount: 1,
                totalAssetCount: 1,
              })
            : current,
        );
        const profileId =
          response.session.publishedProfileId ??
          buildPuzzleResultProfileId(response.session.sessionId);
        markPendingDraftReady('puzzle', response.session.sessionId, openResult);
        markDraftReady(
          'puzzle',
          [
            response.session.sessionId,
            buildPuzzleResultWorkId(response.session.sessionId),
            profileId,
          ],
          openResult,
        );
        void refreshPuzzleShelf();
        if (openResult && response.session.draft) {
          const draft = response.session.draft;
          const draftProfileId =
            response.session.publishedProfileId ??
            buildPuzzleResultProfileId(response.session.sessionId);
          if (!draft.coverImageSrc || !draftProfileId) {
            setPuzzleError(
              !draft.coverImageSrc
                ? '请先选择一张正式拼图图片。'
                : '这份拼图草稿缺少会话信息，请重新开始创作。',
            );
            setSelectionStage('puzzle-result');
            return { openResult: false };
          }

          try {
            const { item } = await updatePuzzleWork(
              draftProfileId,
              buildPuzzleWorkUpdatePayloadFromDraft(draft),
            );
            const run = startLocalPuzzleRun(item);
            setSelectedPuzzleDetail(item);
            setPuzzleRun(run);
            setPuzzleRuntimeAuthMode('default');
            setPuzzleRuntimeReturnStage('puzzle-result');
            openPuzzleRuntimeStage(
              setSelectionStage,
              buildPuzzleDraftRuntimeUrlState(item, null),
            );
          } catch (error) {
            setPuzzleError(
              resolvePuzzleErrorMessage(error, '启动拼图试玩失败。'),
            );
            setSelectionStage('puzzle-result');
          }
          return { openResult: false };
        }
        return { openResult };
      }

      if (
        payload.action === 'publish_puzzle_work' &&
        response.session.publishedProfileId
      ) {
        const galleryDetail = await getPuzzleGalleryDetail(
          response.session.publishedProfileId,
        );
        setSelectedPuzzleDetail(galleryDetail.item);
        const detailEntry = mapPuzzleWorkToPublicWorkDetail(galleryDetail.item);
        setSelectedPublicWorkDetail(detailEntry);
        setPublicWorkDetailError(null);
        setSelectionStage('work-detail');
        pushAppHistoryPath(
          buildPublicWorkStagePath(
            'work-detail',
            buildPuzzlePublicWorkCode(galleryDetail.item.profileId),
          ),
        );
        openPublishShareModal({
          title: galleryDetail.item.workTitle || galleryDetail.item.levelName,
          publicWorkCode: buildPuzzlePublicWorkCode(
            galleryDetail.item.profileId,
          ),
          stage: 'puzzle-gallery-detail',
        });
      }
    },
    beforeExecuteAction: ({ payload, session }) => {
      const formPayload = buildPuzzleFormPayloadFromAction(payload);
      if (formPayload) {
        setPuzzleFormDraftPayload(formPayload);
      }

      if (payload.action !== 'compile_puzzle_draft') {
        return;
      }
      markDraftGenerating('puzzle', [
        session.sessionId,
        buildPuzzleResultWorkId(session.sessionId),
        session.publishedProfileId,
        buildPuzzleResultProfileId(session.sessionId),
      ]);
      markPendingDraftGenerating(
        'puzzle',
        session.sessionId,
        buildPendingPuzzleDraftMetadata(
          formPayload ?? buildPuzzleFormPayloadFromSession(session),
        ),
      );
      selectionStageRef.current = 'puzzle-generating';
      activePuzzleGenerationSessionIdRef.current = session.sessionId;
      setSelectionStage('puzzle-generating');
      const nextGenerationState = createPuzzleDraftGenerationStateFromPayload(
        formPayload ?? buildPuzzleFormPayloadFromSession(session),
        session,
      );
      setPuzzleGenerationState(nextGenerationState);
      setPuzzleBackgroundCompileTasks((current) => ({
        ...current,
        [session.sessionId]: {
          session,
          payload: formPayload ?? buildPuzzleFormPayloadFromSession(session),
          generationState: nextGenerationState,
          error: null,
        },
      }));
    },
    onActionError: async ({ payload, errorMessage, session, setSession }) => {
      if (payload.action !== 'compile_puzzle_draft') {
        return;
      }
      refreshPlatformDashboardSilently();
      const formPayload =
        buildPuzzleFormPayloadFromAction(payload) ??
        puzzleBackgroundCompileTasks[session.sessionId]?.payload ??
        buildPuzzleFormPayloadFromSession(session);
      const generationState =
        puzzleBackgroundCompileTasks[session.sessionId]?.generationState ??
        puzzleGenerationState ??
        createPuzzleDraftGenerationStateFromPayload(formPayload, session);
      const recovered = await recoverCompletedPuzzleDraftGeneration({
        sessionId: session.sessionId,
        payload: formPayload,
        generationState,
        setSession,
      });
      if (recovered) {
        return;
      }
      const failedGenerationState = resolveFinishedMiniGameDraftGenerationState(
        generationState,
        'failed',
        { error: errorMessage },
      );
      setPuzzleBackgroundCompileTasks((current) => ({
        ...current,
        [session.sessionId]: {
          session,
          payload: formPayload,
          generationState: failedGenerationState,
          error: errorMessage,
        },
      }));
      markPendingDraftFailed('puzzle', session.sessionId);
      markDraftFailed(
        'puzzle',
        [
          session.sessionId,
          buildPuzzleResultWorkId(session.sessionId),
          session.publishedProfileId,
          buildPuzzleResultProfileId(session.sessionId),
        ],
        errorMessage,
      );
      void refreshPuzzleShelf();
      setPuzzleGenerationState((current) =>
        current ? failedGenerationState : current,
      );
    },
  });

  const visualNovelFlow = usePlatformCreationAgentFlowController<
    VisualNovelAgentSessionSnapshot,
    CreateVisualNovelSessionRequest,
    VisualNovelSessionResponse,
    SendVisualNovelMessageRequest,
    ExecuteVisualNovelAgentActionRequest,
    VisualNovelSessionResponse
  >({
    client: {
      createSession: createVisualNovelSession,
      getSession: getVisualNovelSession,
      streamMessage: streamVisualNovelMessage,
      executeAction: executeVisualNovelAction,
      selectSession: (response) => response.session,
    },
    createPayload: {
      sourceMode: 'idea',
      seedText: null,
      sourceAssetIds: [],
    },
    workspaceStage: 'visual-novel-agent-workspace',
    resultStage: 'visual-novel-result',
    platformStage: 'platform',
    isCompileAction: (payload) => payload.kind === 'compile_work_profile',
    resolveErrorMessage: resolvePuzzleErrorMessage,
    errorMessages: {
      open: '开启视觉小说共创工作台失败。',
      restoreMissingSession: '这份视觉小说草稿缺少会话信息，请重新开始创作。',
      restore: '读取视觉小说创作草稿失败。',
      submit: '发送视觉小说共创消息失败。',
      execute: '执行视觉小说操作失败。',
    },
    enterCreateTab,
    setSelectionStage,
    onSessionOpened: () => {
      setShowCreationTypeModal(false);
    },
    onSessionChanged: (session) => {
      writeCreationUrlState(buildVisualNovelCreationUrlState(session));
    },
    onActionComplete: ({ response, setSession }) => {
      setSession(response.session);
      const openResult =
        selectionStageRef.current === 'visual-novel-generating';
      markDraftReady(
        'visual-novel',
        [response.session.draft?.profileId, response.session.sessionId],
        openResult,
      );
      void refreshVisualNovelShelf();
      return { openResult };
    },
  });

  const bigFishSession = bigFishFlow.session;
  const bigFishError = bigFishFlow.error;
  const setBigFishError = bigFishFlow.setError;
  bigFishErrorSetterRef.current = setBigFishError;
  const isBigFishBusy = bigFishFlow.isBusy;
  const streamingBigFishReplyText = bigFishFlow.streamingReplyText;
  const isStreamingBigFishReply = bigFishFlow.isStreamingReply;

  const match3dSession = match3dFlow.session;
  const match3dError = match3dFlow.error;
  const setMatch3DSession = match3dFlow.setSession;
  const setMatch3DError = match3dFlow.setError;
  match3DErrorSetterRef.current = setMatch3DError;
  const isMatch3DBusy = match3dFlow.isBusy;
  const setStreamingMatch3DReplyText = match3dFlow.setStreamingReplyText;
  const isStreamingMatch3DReply = match3dFlow.isStreamingReply;
  const setIsStreamingMatch3DReply = match3dFlow.setIsStreamingReply;

  const squareHoleSession = squareHoleFlow.session;
  const squareHoleError = squareHoleFlow.error;
  const setSquareHoleSession = squareHoleFlow.setSession;
  const setSquareHoleError = squareHoleFlow.setError;
  squareHoleErrorSetterRef.current = setSquareHoleError;
  const isSquareHoleBusy = squareHoleFlow.isBusy;
  const streamingSquareHoleReplyText = squareHoleFlow.streamingReplyText;
  const setStreamingSquareHoleReplyText = squareHoleFlow.setStreamingReplyText;
  const isStreamingSquareHoleReply = squareHoleFlow.isStreamingReply;
  const setIsStreamingSquareHoleReply = squareHoleFlow.setIsStreamingReply;

  const puzzleSession = puzzleFlow.session;
  const puzzleError = puzzleFlow.error;
  const setPuzzleSession = puzzleFlow.setSession;
  const setPuzzleError = puzzleFlow.setError;
  puzzleErrorSetterRef.current = setPuzzleError;
  const isPuzzleBusy = puzzleFlow.isBusy;
  const setIsPuzzleBusy = puzzleFlow.setIsBusy;
  const isStreamingPuzzleReply = puzzleFlow.isStreamingReply;
  const visualNovelSession = visualNovelFlow.session;
  const visualNovelError = visualNovelFlow.error;
  const setVisualNovelSession = visualNovelFlow.setSession;
  const setVisualNovelError = visualNovelFlow.setError;
  visualNovelErrorSetterRef.current = setVisualNovelError;
  const isVisualNovelBusy = visualNovelFlow.isBusy;
  const setIsVisualNovelBusy = visualNovelFlow.setIsBusy;
  const isVisualNovelStreamingReply = visualNovelFlow.isStreamingReply;
  const resetRpgSessionViewState = sessionController.resetSessionViewState;
  const setRpgGeneratedCustomWorldProfile =
    sessionController.setGeneratedCustomWorldProfile;
  const setRpgCustomWorldError = sessionController.setCustomWorldError;
  const persistRpgAgentUiState = sessionController.persistAgentUiState;
  const resetAutoSaveTrackingToIdle =
    autosaveCoordinator.resetAutoSaveTrackingToIdle;
  const preflightPuzzleDraftGeneration = useCallback(async () => {
    setPuzzleCreationError(null);
    setPuzzleError(null);
    return ensureEnoughDraftGenerationPointsFromServer(
      PUZZLE_DRAFT_GENERATION_POINT_COST,
    );
  }, [ensureEnoughDraftGenerationPointsFromServer]);
  const preflightMatch3DDraftGeneration = useCallback(async () => {
    setMatch3DError(null);
    return ensureEnoughDraftGenerationPointsFromServer(
      MATCH3D_DRAFT_GENERATION_POINT_COST,
    );
  }, [ensureEnoughDraftGenerationPointsFromServer]);
  const preflightBarkBattleDraftGeneration = useCallback(async () => {
    setBarkBattleError(null);
    return ensureEnoughDraftGenerationPointsFromServer(
      BARK_BATTLE_DRAFT_GENERATION_POINT_COST,
    );
  }, [ensureEnoughDraftGenerationPointsFromServer]);
  const draftGenerationPointNoticeDescription = draftGenerationPointNotice
    ? draftGenerationPointNotice.title === '读取泥点余额失败'
      ? '当前表单不会丢失，关闭后可继续编辑，稍后再试。'
      : '当前表单不会丢失，关闭后可继续编辑或补足泥点再继续。'
    : undefined;
  const recoverCompletedPuzzleDraftGeneration = useCallback(
    async ({
      sessionId,
      payload,
      generationState,
      setSession,
    }: {
      sessionId: string;
      payload: CreatePuzzleAgentSessionRequest;
      generationState: MiniGameDraftGenerationState;
      setSession?: (session: PuzzleAgentSessionSnapshot) => void;
    }) => {
      let latestSession: PuzzleAgentSessionSnapshot;
      try {
        const response = await getPuzzleAgentSession(sessionId);
        latestSession = normalizeRecoveredPuzzleDraftSession(response.session);
      } catch {
        return null;
      }

      if (!hasRecoverableGeneratedPuzzleDraft(latestSession)) {
        return null;
      }

      const readyGenerationState = resolveFinishedMiniGameDraftGenerationState(
        generationState,
        'ready',
        {
          completedAssetCount: 1,
          totalAssetCount: 1,
          error: null,
        },
      );
      const openResult = isViewingPuzzleGeneration(sessionId);
      const profileId =
        latestSession.publishedProfileId ??
        buildPuzzleResultProfileId(latestSession.sessionId);

      setPuzzleBackgroundCompileTasks((current) => ({
        ...current,
        [sessionId]: {
          session: latestSession,
          payload,
          generationState: readyGenerationState,
          error: null,
        },
      }));

      setSession?.(latestSession);
      setPuzzleFormDraftPayload(payload);
      setPuzzleOperation(null);
      puzzleErrorSetterRef.current(null);
      if (isViewingPuzzleGeneration(sessionId)) {
        setPuzzleGenerationState(readyGenerationState);
      }

      markPendingDraftReady('puzzle', latestSession.sessionId, openResult);
      markDraftReady(
        'puzzle',
        [
          latestSession.sessionId,
          buildPuzzleResultWorkId(latestSession.sessionId),
          profileId,
        ],
        openResult,
      );
      await refreshPuzzleShelf().catch(() => undefined);

      if (!openResult) {
        return { openResult };
      }

      const draft = latestSession.draft;
      if (!draft?.coverImageSrc || !profileId) {
        puzzleErrorSetterRef.current(
          !draft?.coverImageSrc
            ? '请先选择一张正式拼图图片。'
            : '这份拼图草稿缺少会话信息，请重新开始创作。',
        );
        setSelectionStage('puzzle-result');
        return { openResult: false };
      }

      try {
        const { item } = await updatePuzzleWork(
          profileId,
          buildPuzzleWorkUpdatePayloadFromDraft(draft),
        );
        const run = startLocalPuzzleRun(item);
        setSelectedPuzzleDetail(item);
        setPuzzleRun(run);
        setPuzzleRuntimeAuthMode('default');
        setPuzzleRuntimeReturnStage('puzzle-result');
        openPuzzleRuntimeStage(
          setSelectionStage,
          buildPuzzleDraftRuntimeUrlState(item, null),
        );
      } catch (error) {
        puzzleErrorSetterRef.current(
          resolvePuzzleErrorMessage(error, '启动拼图试玩失败。'),
        );
        setSelectionStage('puzzle-result');
      }

      return { openResult: false };
    },
    [
      isViewingPuzzleGeneration,
      markDraftReady,
      markPendingDraftReady,
      refreshPuzzleShelf,
      resolvePuzzleErrorMessage,
      setSelectionStage,
    ],
  );

  const activeMatch3DGenerationSessionId =
    selectionStage === 'match3d-generating'
      ? (activeMatch3DGenerationSessionIdRef.current ??
        match3dSession?.sessionId ??
        null)
      : null;
  const activeMatch3DBackgroundCompileTask = getMatch3DBackgroundCompileTask(
    activeMatch3DGenerationSessionId,
  );
  const match3dGenerationViewState =
    activeMatch3DBackgroundCompileTask?.generationState ??
    match3dGenerationState;
  const match3dGenerationViewSession =
    activeMatch3DBackgroundCompileTask?.session ?? match3dSession;
  const match3dGenerationViewPayload =
    activeMatch3DBackgroundCompileTask?.payload ?? match3dFormDraftPayload;
  const match3dGenerationViewError =
    activeMatch3DBackgroundCompileTask?.error ?? match3dError;
  const isMatch3DGenerationViewBusy =
    isMatch3DBusy ||
    isMiniGameDraftGenerating(
      activeMatch3DBackgroundCompileTask?.generationState ?? null,
    );
  const activePuzzleGenerationSessionId =
    selectionStage === 'puzzle-generating'
      ? (activePuzzleGenerationSessionIdRef.current ??
        puzzleSession?.sessionId ??
        null)
      : null;
  const activePuzzleBackgroundCompileTask = getPuzzleBackgroundCompileTask(
    activePuzzleGenerationSessionId,
  );
  const puzzleGenerationViewState =
    activePuzzleBackgroundCompileTask?.generationState ?? puzzleGenerationState;
  const puzzleGenerationViewSession =
    activePuzzleBackgroundCompileTask?.session ?? puzzleSession;
  const puzzleGenerationViewPayload =
    activePuzzleBackgroundCompileTask?.payload ?? puzzleFormDraftPayload;
  const puzzleGenerationViewError =
    activePuzzleBackgroundCompileTask?.error ?? puzzleError;
  const isPuzzleGenerationViewBusy =
    isPuzzleBusy ||
    isMiniGameDraftGenerating(
      activePuzzleBackgroundCompileTask?.generationState ?? null,
    );
  const [dismissedPlatformErrorDialogKey, setDismissedPlatformErrorDialogKey] =
    useState<string | null>(null);
  const [
    dismissedPlatformTaskCompletionDialogKey,
    setDismissedPlatformTaskCompletionDialogKey,
  ] = useState<string | null>(null);
  const currentPlatformErrorDialog =
    useMemo<PlatformErrorDialogState | null>(() => {
      const candidates: PlatformDialogCandidate[] = [
        {
          key: pendingPlatformTaskFailureDialog?.key ?? 'draft-failure',
          source: pendingPlatformTaskFailureDialog?.source ?? '创作草稿',
          message: pendingPlatformTaskFailureDialog?.message,
        },
        {
          key: 'creation-entry-config',
          source: '创作入口配置',
          message: creationEntryConfigError,
        },
        {
          key: 'platform-bootstrap',
          source: '平台首页',
          message: platformBootstrap.platformError,
        },
        {
          key: 'rpg-creation-type',
          source: '创作入口',
          message: sessionController.creationTypeError,
        },
        {
          key: 'rpg-restore',
          source: '创作作品架',
          message: sessionController.agentWorkspaceRestoreError,
        },
        {
          key: 'rpg-result',
          source: formatPlatformDialogSource(
            'RPG 草稿',
            sessionController.agentSession?.sessionId ??
              sessionController.generatedCustomWorldProfile?.id,
          ),
          message: resultViewError,
        },
        {
          key: 'public-work-detail',
          source: formatPlatformDialogSource(
            '作品详情',
            selectedPublicWorkDetail
              ? resolvePlatformPublicWorkCode(selectedPublicWorkDetail)
              : selectedDetailEntry?.profileId,
          ),
          message: publicWorkDetailError ?? detailNavigation.detailError,
        },
        {
          key: 'big-fish',
          source: formatPlatformDialogSource(
            selectionStage === 'big-fish-runtime'
              ? '大鱼吃小鱼游玩'
              : '大鱼草稿',
            bigFishRun?.runId ?? bigFishSession?.sessionId,
          ),
          message: bigFishError,
        },
        {
          key: 'match3d',
          source: formatPlatformDialogSource(
            selectionStage === 'match3d-runtime' ? '抓大鹅游玩' : '抓大鹅草稿',
            match3dRun?.runId ??
              match3dGenerationViewSession?.sessionId ??
              match3dSession?.sessionId,
          ),
          message: match3dGenerationViewError ?? match3dError,
        },
        {
          key: 'square-hole',
          source: formatPlatformDialogSource(
            selectionStage === 'square-hole-runtime'
              ? '方洞挑战游玩'
              : '方洞挑战草稿',
            squareHoleRun?.runId ?? squareHoleSession?.sessionId,
          ),
          message: squareHoleError,
        },
        {
          key: 'jump-hop',
          source: formatPlatformDialogSource(
            selectionStage === 'jump-hop-runtime' ? '跳一跳游玩' : '跳一跳草稿',
            jumpHopRun?.runId ?? jumpHopSession?.sessionId,
          ),
          message: jumpHopError,
        },
        {
          key: 'wooden-fish',
          source: formatPlatformDialogSource(
            selectionStage === 'wooden-fish-runtime'
              ? '敲木鱼游玩'
              : '敲木鱼草稿',
            woodenFishRun?.runId ?? woodenFishSession?.sessionId,
          ),
          message: woodenFishError,
        },
        {
          key: 'puzzle',
          source: formatPlatformDialogSource(
            selectionStage === 'puzzle-runtime' ? '拼图游玩' : '拼图草稿',
            puzzleRun?.runId ??
              puzzleGenerationViewSession?.sessionId ??
              puzzleSession?.sessionId,
          ),
          message:
            puzzleGenerationViewError ?? puzzleCreationError ?? puzzleError,
        },
        {
          key: 'puzzle-onboarding',
          source: '拼图首次创作',
          message: puzzleOnboardingError,
        },
        {
          key: 'puzzle-shelf',
          source: '拼图作品架',
          message: puzzleShelfError,
        },
        {
          key: 'visual-novel',
          source: formatPlatformDialogSource(
            selectionStage === 'visual-novel-runtime'
              ? '视觉小说游玩'
              : '视觉小说草稿',
            visualNovelRun?.runId ?? visualNovelSession?.sessionId,
          ),
          message: visualNovelError,
        },
        {
          key: 'baby-object-match',
          source: formatPlatformDialogSource(
            selectionStage === 'baby-object-match-runtime'
              ? '宝贝识物游玩'
              : '宝贝识物草稿',
            babyObjectMatchDraft?.profileId,
          ),
          message: babyObjectMatchError,
        },
        {
          key: 'bark-battle',
          source: formatPlatformDialogSource(
            selectionStage === 'bark-battle-runtime'
              ? '汪汪声浪游玩'
              : '汪汪声浪草稿',
            barkBattlePublishedConfig?.workId ?? barkBattleDraftConfig?.workId,
          ),
          message: barkBattleError,
        },
        {
          key: 'creative-agent',
          source: formatPlatformDialogSource(
            '智能创作 Agent',
            creativeAgentSession?.sessionId,
          ),
          message: creativeAgentError,
        },
        {
          key: 'rpg-generation',
          source: formatPlatformDialogSource(
            'RPG 草稿生成',
            sessionController.agentSession?.sessionId,
          ),
          message: sessionController.activeGenerationError,
        },
      ];

      return resolvePlatformErrorDialog(candidates);
    }, [
      babyObjectMatchDraft?.profileId,
      babyObjectMatchError,
      barkBattleDraftConfig?.workId,
      barkBattleError,
      barkBattlePublishedConfig?.workId,
      bigFishError,
      bigFishRun?.runId,
      bigFishSession?.sessionId,
      creationEntryConfigError,
      creativeAgentError,
      creativeAgentSession?.sessionId,
      detailNavigation.detailError,
      jumpHopError,
      jumpHopRun?.runId,
      jumpHopSession?.sessionId,
      match3dError,
      match3dGenerationViewError,
      match3dGenerationViewSession?.sessionId,
      match3dRun?.runId,
      match3dSession?.sessionId,
      pendingPlatformTaskFailureDialog,
      platformBootstrap.platformError,
      publicWorkDetailError,
      puzzleCreationError,
      puzzleError,
      puzzleGenerationViewError,
      puzzleGenerationViewSession?.sessionId,
      puzzleOnboardingError,
      puzzleRun?.runId,
      puzzleSession?.sessionId,
      puzzleShelfError,
      resultViewError,
      selectedDetailEntry?.profileId,
      selectedPublicWorkDetail,
      selectionStage,
      sessionController.activeGenerationError,
      sessionController.agentSession?.sessionId,
      sessionController.agentWorkspaceRestoreError,
      sessionController.creationTypeError,
      sessionController.generatedCustomWorldProfile?.id,
      squareHoleError,
      squareHoleRun?.runId,
      squareHoleSession?.sessionId,
      visualNovelError,
      visualNovelRun?.runId,
      visualNovelSession?.sessionId,
      woodenFishError,
      woodenFishRun?.runId,
      woodenFishSession?.sessionId,
    ]);
  const currentPlatformTaskCompletionDialog =
    useMemo<PlatformTaskCompletionDialogState | null>(
      () => pendingPlatformTaskCompletionDialog,
      [pendingPlatformTaskCompletionDialog],
    );
  const activePlatformTaskCompletionDialog = resolveActivePlatformDialog(
    currentPlatformTaskCompletionDialog,
    dismissedPlatformTaskCompletionDialogKey,
    buildPlatformTaskCompletionDialogDismissKey,
  );
  const activePlatformErrorDialog = resolveActivePlatformDialog(
    currentPlatformErrorDialog,
    dismissedPlatformErrorDialogKey,
    buildPlatformErrorDialogDismissKey,
  );
  const closePlatformErrorDialog = useCallback(() => {
    if (!currentPlatformErrorDialog) {
      return;
    }

    const dismissKey = buildPlatformErrorDialogDismissKey(
      currentPlatformErrorDialog,
    );
    if (dismissKey) {
      setDismissedPlatformErrorDialogKey(dismissKey);
    }

    if (currentPlatformErrorDialog.key === 'creation-entry-config') {
      setCreationEntryConfigError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'platform-bootstrap') {
      platformBootstrap.setPlatformError(null);
      return;
    }
    if (currentPlatformErrorDialog.key.startsWith('draft-failure:')) {
      setPendingPlatformTaskFailureDialog(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'rpg-creation-type') {
      sessionController.setCreationTypeError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'rpg-restore') {
      return;
    }
    if (
      currentPlatformErrorDialog.key === 'rpg-result' ||
      currentPlatformErrorDialog.key === 'rpg-generation'
    ) {
      autosaveCoordinator.setCustomWorldAutoSaveError(null);
      sessionController.setCustomWorldError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'public-work-detail') {
      setPublicWorkDetailError(null);
      detailNavigation.setDetailError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'big-fish') {
      setBigFishError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'match3d') {
      setMatch3DError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'square-hole') {
      setSquareHoleError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'jump-hop') {
      setJumpHopError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'wooden-fish') {
      setWoodenFishError(null);
      return;
    }
    if (
      currentPlatformErrorDialog.key === 'puzzle' ||
      currentPlatformErrorDialog.key === 'puzzle-onboarding' ||
      currentPlatformErrorDialog.key === 'puzzle-shelf'
    ) {
      setPuzzleCreationError(null);
      setPuzzleOnboardingError(null);
      setPuzzleShelfError(null);
      setPuzzleError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'visual-novel') {
      setVisualNovelError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'baby-object-match') {
      setBabyObjectMatchError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'bark-battle') {
      setBarkBattleError(null);
      return;
    }
    if (currentPlatformErrorDialog.key === 'creative-agent') {
      setCreativeAgentError(null);
    }
  }, [
    autosaveCoordinator,
    currentPlatformErrorDialog,
    detailNavigation,
    platformBootstrap,
    sessionController,
    setBigFishError,
    setMatch3DError,
    setPendingPlatformTaskFailureDialog,
    setPuzzleError,
    setSquareHoleError,
    setVisualNovelError,
  ]);
  const closePlatformTaskCompletionDialog = useCallback(() => {
    if (!currentPlatformTaskCompletionDialog) {
      return;
    }

    const dismissKey = buildPlatformTaskCompletionDialogDismissKey(
      currentPlatformTaskCompletionDialog,
    );
    if (dismissKey) {
      setDismissedPlatformTaskCompletionDialogKey(dismissKey);
    }
    setPendingPlatformTaskCompletionDialog(null);
  }, [currentPlatformTaskCompletionDialog]);
  const shouldPollPuzzleGenerationSession =
    selectionStage === 'puzzle-generating' &&
    activePuzzleGenerationSessionId != null &&
    isMiniGameDraftGenerating(puzzleGenerationViewState);

  useEffect(() => {
    if (
      !shouldPollPuzzleGenerationSession ||
      !activePuzzleGenerationSessionId
    ) {
      return undefined;
    }

    let isDisposed = false;

    const pollPuzzleDraftGenerationSession = async () => {
      try {
        const { session: latestSession } = await getPuzzleAgentSession(
          activePuzzleGenerationSessionId,
        );
        if (isDisposed) {
          return;
        }

        setPuzzleSession(latestSession);
        setPuzzleBackgroundCompileTasks((current) => {
          const task = current[activePuzzleGenerationSessionId];
          if (!task) {
            return current;
          }

          return {
            ...current,
            [activePuzzleGenerationSessionId]: {
              ...task,
              session: latestSession,
              generationState: mergePuzzleSessionProgressIntoGenerationState(
                task.generationState,
                latestSession,
              ),
            },
          };
        });
        setPuzzleGenerationState((current) =>
          current
            ? mergePuzzleSessionProgressIntoGenerationState(
                current,
                latestSession,
              )
            : current,
        );
      } catch {
        // 中文注释：拼图长 action 仍以主请求结果为准；轮询失败只保留当前进度展示。
      }
    };

    void pollPuzzleDraftGenerationSession();
    const timerId = window.setInterval(() => {
      void pollPuzzleDraftGenerationSession();
    }, 3_000);

    return () => {
      isDisposed = true;
      window.clearInterval(timerId);
    };
  }, [
    activePuzzleGenerationSessionId,
    shouldPollPuzzleGenerationSession,
    setPuzzleSession,
  ]);

  const match3DGeneratingSessionId =
    selectionStage === 'match3d-generating' ? match3dSession?.sessionId : null;

  useEffect(() => {
    puzzleRunRef.current = puzzleRun;
  }, [puzzleRun]);

  useEffect(() => {
    if (
      selectionStage !== 'match3d-generating' ||
      !isMatch3DBusy ||
      !match3DGeneratingSessionId
    ) {
      return undefined;
    }

    let isDisposed = false;

    const pollMatch3DDraftAssets = async () => {
      try {
        const { session: latestSession } =
          await match3dCreationClient.getSession(match3DGeneratingSessionId);
        if (isDisposed) {
          return;
        }

        setMatch3DSession(latestSession);
        const profileId =
          latestSession.draft?.profileId ?? latestSession.publishedProfileId;
        if (!profileId) {
          return;
        }

        const { item } = await getMatch3DWorkDetail(profileId);
        if (isDisposed) {
          return;
        }

        const normalizedItem = normalizeMatch3DWorkForRuntimeUi(item);
        setMatch3DProfile(normalizedItem);
        setMatch3DGenerationState((current) =>
          mergeMatch3DGeneratedAssetsIntoGenerationState(
            current,
            normalizedItem.generatedItemAssets,
          ),
        );
      } catch {
        // 中文注释：生成长 action 仍在执行，轮询只是进度旁路；失败时保留主请求结果。
      }
    };

    void pollMatch3DDraftAssets();
    const timerId = window.setInterval(() => {
      void pollMatch3DDraftAssets();
    }, 3_000);

    return () => {
      isDisposed = true;
      window.clearInterval(timerId);
    };
  }, [
    isMatch3DBusy,
    match3DGeneratingSessionId,
    selectionStage,
    setMatch3DSession,
    setMatch3DProfile,
    setMatch3DGenerationState,
  ]);

  const openBigFishAgentWorkspace = useCallback(async () => {
    markCreationFlowReturnToCreate();
    setBigFishRun(null);
    await bigFishFlow.openWorkspace();
  }, [bigFishFlow, markCreationFlowReturnToCreate]);

  const openSquareHoleAgentWorkspace = useCallback(async () => {
    markCreationFlowReturnToCreate();
    setSquareHoleSession(null);
    setSquareHoleProfile(null);
    setSquareHoleRun(null);
    setSquareHoleError(null);
    setSquareHoleGenerationState(null);
    setSquareHoleRuntimeReturnStage('square-hole-result');
    setStreamingSquareHoleReplyText('');
    setIsStreamingSquareHoleReply(false);
    await squareHoleFlow.openWorkspace();
  }, [
    setIsStreamingSquareHoleReply,
    setSquareHoleError,
    setSquareHoleProfile,
    setSquareHoleRun,
    setSquareHoleSession,
    setStreamingSquareHoleReplyText,
    squareHoleFlow,
    markCreationFlowReturnToCreate,
  ]);

  const openMatch3DWorkspace = useCallback(() => {
    markCreationFlowReturnToCreate();
    setMatch3DRun(null);
    setMatch3DProfile(null);
    setMatch3DRuntimeProfile(null);
    setMatch3DGenerationState(null);
    setMatch3DError(null);
    setStreamingMatch3DReplyText('');
    setIsStreamingMatch3DReply(false);
    enterCreateTab();
    setShowCreationTypeModal(false);
    setSelectionStage('match3d-agent-workspace');
  }, [
    enterCreateTab,
    setIsStreamingMatch3DReply,
    setMatch3DError,
    setSelectionStage,
    setStreamingMatch3DReplyText,
    markCreationFlowReturnToCreate,
  ]);

  const openJumpHopWorkspace = useCallback(() => {
    markCreationFlowReturnToCreate();
    setJumpHopError(null);
    setJumpHopSession(null);
    setJumpHopWork(null);
    setJumpHopRun(null);
    setJumpHopGenerationState(null);
    enterCreateTab();
    setShowCreationTypeModal(false);
    setSelectionStage('jump-hop-workspace');
  }, [enterCreateTab, markCreationFlowReturnToCreate, setSelectionStage]);

  const openWoodenFishWorkspace = useCallback(() => {
    markCreationFlowReturnToCreate();
    setWoodenFishError(null);
    setWoodenFishSession(null);
    setWoodenFishWork(null);
    setWoodenFishRun(null);
    setWoodenFishGenerationState(null);
    enterCreateTab();
    setShowCreationTypeModal(false);
    setSelectionStage('wooden-fish-workspace');
  }, [enterCreateTab, markCreationFlowReturnToCreate, setSelectionStage]);

  const openPuzzleWorkspace = useCallback(() => {
    markCreationFlowReturnToCreate();
    setPuzzleSession(null);
    setPuzzleFormDraftPayload(null);
    setPuzzleOperation(null);
    setPuzzleGenerationState(null);
    setPuzzleRun(null);
    setSelectedPuzzleDetail(null);
    setPuzzleRuntimeAuthMode('default');
    activePuzzleGenerationSessionIdRef.current = null;
    enterCreateTab();
    setShowCreationTypeModal(false);
    setPuzzleCreationError(null);
    setPuzzleError(null);
    setSelectionStage('puzzle-agent-workspace');
  }, [
    enterCreateTab,
    setPuzzleSession,
    setPuzzleCreationError,
    setPuzzleError,
    setSelectionStage,
    markCreationFlowReturnToCreate,
  ]);

  const openBarkBattleWorkspace = useCallback(() => {
    markCreationFlowReturnToCreate();
    setBarkBattleDraftConfig(null);
    setBarkBattlePublishedConfig(null);
    setBarkBattleRuntimeMode('draft');
    setBarkBattleRuntimeReturnStage('platform');
    setBarkBattleError(null);
    setBarkBattleGenerationPartialFailed(false);
    setIsBarkBattleBusy(false);
    enterCreateTab();
    setShowCreationTypeModal(false);
    selectionStageRef.current = 'bark-battle-workspace';
    setSelectionStage('bark-battle-workspace');
  }, [enterCreateTab, markCreationFlowReturnToCreate, setSelectionStage]);

  const openVisualNovelWorkspace = useCallback(() => {
    markCreationFlowReturnToCreate();
    enterCreateTab();
    setShowCreationTypeModal(false);
    setVisualNovelError(null);
    setSelectionStage('visual-novel-agent-workspace');
  }, [
    enterCreateTab,
    markCreationFlowReturnToCreate,
    setSelectionStage,
    setVisualNovelError,
  ]);

  const openBabyObjectMatchWorkspace = useCallback(() => {
    if (!isBabyObjectMatchVisible) {
      sessionController.setCreationTypeError(EDUTAINMENT_HIDDEN_MESSAGE);
      return;
    }

    markCreationFlowReturnToCreate();
    enterCreateTab();
    setShowCreationTypeModal(false);
    setBabyObjectMatchError(null);
    setSelectionStage('baby-object-match-workspace');
  }, [
    enterCreateTab,
    isBabyObjectMatchVisible,
    markCreationFlowReturnToCreate,
    sessionController,
    setBabyObjectMatchError,
    setSelectionStage,
  ]);

  const leaveCreativeAgentWorkspace = useCallback(() => {
    const sessionId = creativeAgentSession?.sessionId?.trim();
    if (sessionId && creativeAgentSession?.stage !== 'target_ready') {
      void cancelCreativeAgentSession(sessionId).catch(() => undefined);
    }
    setCreativeAgentSession(null);
    setCreativeAgentEvents([]);
    setActiveCreativeAgentSessionId(null);
    setCreativeAgentError(null);
    setIsCreativeAgentBusy(false);
    setIsCreativeAgentStreaming(false);
    setCreativeDraftEditError(null);
    setIsCreativeDraftEditBusy(false);
    markCreationFlowReturnToCreate();
    enterCreateTab();
    setSelectionStage('platform');
  }, [
    creativeAgentSession,
    enterCreateTab,
    markCreationFlowReturnToCreate,
    setSelectionStage,
  ]);

  const openCreativeAgentWorkspace = useCallback(async () => {
    if (isCreativeAgentBusy || isCreativeAgentStreaming) {
      return;
    }

    setPuzzleRun(null);
    markCreationFlowReturnToCreate();
    setPuzzleRuntimeAuthMode('default');
    setPuzzleOperation(null);
    setPuzzleGenerationState(null);
    setPuzzleFormDraftPayload(null);
    setCreativeAgentError(null);
    setCreativeAgentEvents([]);
    setIsCreativeAgentBusy(true);

    try {
      const response = await createCreativeAgentSession({
        entryContext: 'creation_home',
      });
      setCreativeAgentSession(response.session);
      setActiveCreativeAgentSessionId(response.session.sessionId);
      enterCreateTab();
      setShowCreationTypeModal(false);
      setSelectionStage('creative-agent-workspace');
    } catch (error) {
      setCreativeAgentError(
        resolvePuzzleErrorMessage(error, '开启智能创作工作区失败。'),
      );
    } finally {
      setIsCreativeAgentBusy(false);
    }
  }, [
    enterCreateTab,
    isCreativeAgentBusy,
    isCreativeAgentStreaming,
    markCreationFlowReturnToCreate,
    resolvePuzzleErrorMessage,
    setSelectionStage,
  ]);

  const createPuzzleDraftFromForm = useCallback(
    async (payload: CreatePuzzleAgentSessionRequest) => {
      setPuzzleFormDraftPayload(payload);
      setPuzzleCreationError(null);
      setPuzzleError(null);
      const shouldConsumePuzzleDraftPoints = payload.aiRedraw !== false;

      if (
        shouldConsumePuzzleDraftPoints &&
        !(await preflightPuzzleDraftGeneration())
      ) {
        return;
      }

      let nextSession: PuzzleAgentSessionSnapshot;
      try {
        const response = await createPuzzleAgentSession(payload);
        nextSession = response.session;
      } catch (error) {
        const errorMessage = resolvePuzzleErrorMessage(
          error,
          '开启拼图创作工作台失败。',
        );
        setPuzzleCreationError(errorMessage);
        setPuzzleError(errorMessage);
        return;
      }

      const generationState = createPuzzleDraftGenerationStateFromPayload(
        payload,
        nextSession,
      );
      setPuzzleBackgroundCompileTasks((current) => ({
        ...current,
        [nextSession.sessionId]: {
          session: nextSession,
          payload,
          generationState,
          error: null,
        },
      }));
      puzzleFlow.setSession(nextSession);
      setPuzzleGenerationState(generationState);
      markDraftGenerating('puzzle', [
        nextSession.sessionId,
        buildPuzzleResultWorkId(nextSession.sessionId),
        nextSession.publishedProfileId,
        buildPuzzleResultProfileId(nextSession.sessionId),
      ]);
      markPendingDraftGenerating(
        'puzzle',
        nextSession.sessionId,
        buildPendingPuzzleDraftMetadata(payload),
      );
      if (shouldConsumePuzzleDraftPoints) {
        adjustProfileWalletBalanceLocally(-PUZZLE_DRAFT_GENERATION_POINT_COST);
      }
      selectionStageRef.current = 'puzzle-generating';
      activePuzzleGenerationSessionIdRef.current = nextSession.sessionId;
      setSelectionStage('puzzle-generating');

      try {
        const actionPayload = buildPuzzleCompileActionFromFormPayload(payload);
        const response = await executePuzzleAgentAction(
          nextSession.sessionId,
          actionPayload,
        );
        setPuzzleOperation(response.operation);
        const openResult = isViewingPuzzleGeneration(nextSession.sessionId);
        const readyGenerationState =
          resolveFinishedMiniGameDraftGenerationState(
            generationState,
            'ready',
            {
              completedAssetCount: 1,
              totalAssetCount: 1,
            },
          );
        setPuzzleBackgroundCompileTasks((current) => ({
          ...current,
          [nextSession.sessionId]: {
            session: response.session,
            payload,
            generationState: readyGenerationState,
            error: null,
          },
        }));
        if (isViewingPuzzleGeneration(nextSession.sessionId)) {
          puzzleFlow.setSession(response.session);
          setPuzzleGenerationState(readyGenerationState);
        }

        const profileId =
          response.session.publishedProfileId ??
          buildPuzzleResultProfileId(response.session.sessionId);
        markPendingDraftReady('puzzle', response.session.sessionId, openResult);
        markDraftReady(
          'puzzle',
          [
            response.session.sessionId,
            buildPuzzleResultWorkId(response.session.sessionId),
            profileId,
          ],
          openResult,
        );
        void refreshPuzzleShelf();

        if (openResult && response.session.draft) {
          const draft = response.session.draft;
          const draftProfileId =
            response.session.publishedProfileId ??
            buildPuzzleResultProfileId(response.session.sessionId);
          if (!draft.coverImageSrc || !draftProfileId) {
            setPuzzleError(
              !draft.coverImageSrc
                ? '请先选择一张正式拼图图片。'
                : '这份拼图草稿缺少会话信息，请重新开始创作。',
            );
            setSelectionStage('puzzle-result');
            return;
          }

          try {
            const { item } = await updatePuzzleWork(
              draftProfileId,
              buildPuzzleWorkUpdatePayloadFromDraft(draft),
            );
            const run = startLocalPuzzleRun(item);
            setSelectedPuzzleDetail(item);
            setPuzzleRun(run);
            setPuzzleRuntimeAuthMode('default');
            setPuzzleRuntimeReturnStage('puzzle-result');
            openPuzzleRuntimeStage(
              setSelectionStage,
              buildPuzzleDraftRuntimeUrlState(item, null),
            );
          } catch (error) {
            setPuzzleError(
              resolvePuzzleErrorMessage(error, '启动拼图试玩失败。'),
            );
            setSelectionStage('puzzle-result');
          }
        }
      } catch (error) {
        const errorMessage = resolvePuzzleErrorMessage(
          error,
          '执行拼图操作失败。',
        );
        const recovered = await recoverCompletedPuzzleDraftGeneration({
          sessionId: nextSession.sessionId,
          payload,
          generationState,
          setSession: puzzleFlow.setSession,
        });
        if (recovered) {
          return;
        }
        if (shouldConsumePuzzleDraftPoints) {
          adjustProfileWalletBalanceLocally(PUZZLE_DRAFT_GENERATION_POINT_COST);
        }
        const failedGenerationState =
          resolveFinishedMiniGameDraftGenerationState(
            generationState,
            'failed',
            { error: errorMessage },
          );
        const openFailure = isViewingPuzzleGeneration(nextSession.sessionId);
        setPuzzleBackgroundCompileTasks((current) => ({
          ...current,
          [nextSession.sessionId]: {
            session: nextSession,
            payload,
            generationState: failedGenerationState,
            error: errorMessage,
          },
        }));
        markPendingDraftFailed('puzzle', nextSession.sessionId);
        markDraftFailed(
          'puzzle',
          [
            nextSession.sessionId,
            buildPuzzleResultWorkId(nextSession.sessionId),
            nextSession.publishedProfileId,
            buildPuzzleResultProfileId(nextSession.sessionId),
          ],
          errorMessage,
          !openFailure,
        );
        void refreshPuzzleShelf();
        if (openFailure) {
          setPuzzleError(errorMessage);
          setPuzzleGenerationState(failedGenerationState);
        }
      } finally {
        refreshPlatformDashboardSilently();
      }
    },
    [
      adjustProfileWalletBalanceLocally,
      markDraftGenerating,
      markDraftFailed,
      markDraftReady,
      markPendingDraftFailed,
      markPendingDraftGenerating,
      markPendingDraftReady,
      isViewingPuzzleGeneration,
      preflightPuzzleDraftGeneration,
      puzzleFlow,
      refreshPuzzleShelf,
      recoverCompletedPuzzleDraftGeneration,
      refreshPlatformDashboardSilently,
      resolvePuzzleErrorMessage,
      setPuzzleError,
      setSelectionStage,
    ],
  );

  const createMatch3DDraftFromForm = useCallback(
    async (payload: CreateMatch3DSessionRequest) => {
      setMatch3DFormDraftPayload(payload);
      setMatch3DError(null);
      setStreamingMatch3DReplyText('');
      setIsStreamingMatch3DReply(false);

      if (!(await preflightMatch3DDraftGeneration())) {
        return;
      }

      let nextSession: Match3DAgentSessionSnapshot;
      try {
        const response = await match3dCreationClient.createSession(payload);
        nextSession = response.session;
      } catch (error) {
        setMatch3DError(
          resolveMatch3DErrorMessage(error, '开启抓大鹅共创工作台失败。'),
        );
        return;
      }

      const generationState = createMiniGameDraftGenerationState(
        'match3d',
        resolveMiniGameDraftGenerationStartedAtMs(nextSession.updatedAt),
      );
      setMatch3DBackgroundCompileTasks((current) => ({
        ...current,
        [nextSession.sessionId]: {
          session: nextSession,
          payload,
          generationState,
          error: null,
        },
      }));
      setMatch3DSession(nextSession);
      setMatch3DProfile(null);
      setMatch3DRuntimeProfile(null);
      setMatch3DRun(null);
      setMatch3DGenerationState(generationState);
      markDraftGenerating('match3d', [
        nextSession.draft?.profileId,
        nextSession.publishedProfileId,
        nextSession.sessionId,
      ]);
      markPendingDraftGenerating(
        'match3d',
        nextSession.sessionId,
        buildPendingMatch3DDraftMetadata(payload),
      );
      adjustProfileWalletBalanceLocally(-MATCH3D_DRAFT_GENERATION_POINT_COST);
      selectionStageRef.current = 'match3d-generating';
      activeMatch3DGenerationSessionIdRef.current = nextSession.sessionId;
      setSelectionStage('match3d-generating');

      try {
        const response = await match3dCreationClient.executeAction(
          nextSession.sessionId,
          {
            action: 'match3d_compile_draft',
            generateClickSound: payload.generateClickSound,
          },
        );
        const openResult = isViewingMatch3DGeneration(nextSession.sessionId);
        const readyGenerationState =
          resolveFinishedMiniGameDraftGenerationState(
            generationState,
            'ready',
            {
              completedAssetCount:
                response.session.draft?.generatedItemAssets?.length ?? 5,
              totalAssetCount:
                response.session.draft?.generatedItemAssets?.length ?? 5,
            },
          );
        setMatch3DBackgroundCompileTasks((current) => ({
          ...current,
          [nextSession.sessionId]: {
            session: response.session,
            payload,
            generationState: readyGenerationState,
            error: null,
          },
        }));
        if (isViewingMatch3DGeneration(nextSession.sessionId)) {
          setMatch3DSession(response.session);
          setMatch3DGenerationState(readyGenerationState);
        }

        const profileId = response.session.draft?.profileId;
        if (!profileId) {
          if (isViewingMatch3DGeneration(nextSession.sessionId)) {
            setMatch3DProfile(null);
            setMatch3DRuntimeProfile(null);
          }
          return;
        }

        let runtimeProfile: Match3DWorkProfile | null = null;
        try {
          const { item } = await getMatch3DWorkDetail(profileId);
          runtimeProfile = normalizeMatch3DWorkForRuntimeUi({
            ...item,
            generatedItemAssets: mergeMatch3DGeneratedItemAssetsForRuntime(
              response.session.draft?.generatedItemAssets,
              item.generatedItemAssets,
            ),
          });
          if (isViewingMatch3DGeneration(nextSession.sessionId)) {
            setMatch3DProfile(runtimeProfile);
          }
          await refreshMatch3DShelf().catch(() => undefined);
        } catch {
          runtimeProfile = buildMatch3DProfileFromSession(response.session);
          if (isViewingMatch3DGeneration(nextSession.sessionId)) {
            setMatch3DProfile(runtimeProfile);
          }
        }

        markPendingDraftReady(
          'match3d',
          response.session.sessionId,
          openResult,
        );
        markDraftReady(
          'match3d',
          [profileId, response.session.sessionId],
          openResult,
        );
        if (openResult && runtimeProfile) {
          try {
            await preloadMatch3DGeneratedRuntimeAssets(
              runtimeProfile.generatedItemAssets,
              runtimeProfile.generatedBackgroundAsset,
              { expireSeconds: 300 },
            );
            const { run } = await match3dRuntimeAdapter.startRun(
              runtimeProfile.profileId,
            );
            setMatch3DRuntimeProfile(runtimeProfile);
            setMatch3DRun(run);
            setMatch3DProfile(runtimeProfile);
            setMatch3DRuntimeReturnStage('match3d-result');
            setSelectionStage('match3d-runtime');
          } catch (error) {
            setMatch3DError(
              resolveMatch3DErrorMessage(error, '启动抓大鹅玩法失败。'),
            );
            setSelectionStage('match3d-result');
          }
        }
      } catch (error) {
        const errorMessage = resolveMatch3DErrorMessage(
          error,
          '执行抓大鹅操作失败。',
        );
        if (isBackgroundGenerationStillRunningMessage(errorMessage)) {
          try {
            const { session: latestSession } =
              await match3dCreationClient.getSession(nextSession.sessionId);
            markPendingDraftGenerating('match3d', latestSession.sessionId);
            markDraftGenerating('match3d', [
              latestSession.draft?.profileId,
              latestSession.publishedProfileId,
              latestSession.sessionId,
            ]);
            setMatch3DBackgroundCompileTasks((current) => ({
              ...current,
              [nextSession.sessionId]: {
                session: latestSession,
                payload,
                generationState,
                error: errorMessage,
              },
            }));
            if (isViewingMatch3DGeneration(nextSession.sessionId)) {
              setMatch3DError(errorMessage);
              setMatch3DSession(latestSession);
              setMatch3DGenerationState(generationState);
              const profileId =
                latestSession.draft?.profileId ??
                latestSession.publishedProfileId;
              if (profileId) {
                const { item } = await getMatch3DWorkDetail(profileId);
                setMatch3DProfile(normalizeMatch3DWorkForRuntimeUi(item));
              }
            }
            await refreshMatch3DShelf().catch(() => undefined);
            return;
          } catch {
            await refreshMatch3DShelf().catch(() => undefined);
          }
        }
        adjustProfileWalletBalanceLocally(MATCH3D_DRAFT_GENERATION_POINT_COST);
        const failedGenerationState =
          resolveFinishedMiniGameDraftGenerationState(
            generationState,
            'failed',
            { error: errorMessage },
          );
        const openFailure = isViewingMatch3DGeneration(nextSession.sessionId);
        setMatch3DBackgroundCompileTasks((current) => ({
          ...current,
          [nextSession.sessionId]: {
            session: nextSession,
            payload,
            generationState: failedGenerationState,
            error: errorMessage,
          },
        }));
        markPendingDraftFailed('match3d', nextSession.sessionId);
        markDraftFailed(
          'match3d',
          [
            nextSession.draft?.profileId,
            nextSession.publishedProfileId,
            nextSession.sessionId,
          ],
          errorMessage,
          !openFailure,
        );
        if (openFailure) {
          setMatch3DError(errorMessage);
          setMatch3DGenerationState(failedGenerationState);
        }
        try {
          const { session: latestSession } =
            await match3dCreationClient.getSession(nextSession.sessionId);
          markDraftFailed(
            'match3d',
            [
              latestSession.draft?.profileId,
              latestSession.publishedProfileId,
              latestSession.sessionId,
            ],
            errorMessage,
            !openFailure,
          );
          setMatch3DBackgroundCompileTasks((current) => ({
            ...current,
            [nextSession.sessionId]: {
              session: latestSession,
              payload,
              generationState: failedGenerationState,
              error: errorMessage,
            },
          }));
          if (openFailure) {
            setMatch3DSession(latestSession);
            const profileId =
              latestSession.draft?.profileId ??
              latestSession.publishedProfileId;
            if (profileId) {
              const { item } = await getMatch3DWorkDetail(profileId);
              setMatch3DProfile(normalizeMatch3DWorkForRuntimeUi(item));
            }
          }
          await refreshMatch3DShelf().catch(() => undefined);
        } catch {
          await refreshMatch3DShelf().catch(() => undefined);
        }
      } finally {
        refreshPlatformDashboardSilently();
      }
    },
    [
      adjustProfileWalletBalanceLocally,
      match3dRuntimeAdapter,
      isViewingMatch3DGeneration,
      markDraftGenerating,
      markDraftFailed,
      markDraftReady,
      markPendingDraftFailed,
      markPendingDraftGenerating,
      markPendingDraftReady,
      preflightMatch3DDraftGeneration,
      refreshMatch3DShelf,
      refreshPlatformDashboardSilently,
      resolveMatch3DErrorMessage,
      setIsStreamingMatch3DReply,
      setMatch3DError,
      setMatch3DProfile,
      setMatch3DRun,
      setMatch3DSession,
      setSelectionStage,
      setStreamingMatch3DReplyText,
    ],
  );

  const createVisualNovelDraftFromForm = useCallback(
    async (payload: VisualNovelEntryFormPayload) => {
      setVisualNovelFormDraftPayload(payload);
      setVisualNovelGenerationStartedAtMs(Date.now());
      setVisualNovelGenerationPhase('generating');
      setVisualNovelWork(null);
      setVisualNovelRun(null);
      setVisualNovelRuntimeReturnStage('visual-novel-result');
      setVisualNovelError(null);
      setIsVisualNovelBusy(true);
      setSelectionStage('visual-novel-generating');

      try {
        const createResponse = await createVisualNovelSession({
          sourceMode: payload.sourceMode,
          seedText: payload.seedText,
          sourceAssetIds: payload.sourceAssetIds,
        });
        setVisualNovelSession(createResponse.session);
        markDraftGenerating('visual-novel', [createResponse.session.sessionId]);
        markPendingDraftGenerating(
          'visual-novel',
          createResponse.session.sessionId,
        );
        const nextSession = await streamVisualNovelMessage(
          createResponse.session.sessionId,
          {
            clientMessageId: `visual-novel-entry-${Date.now().toString(36)}`,
            text: payload.seedText,
          },
        );
        setVisualNovelSession(nextSession);
        setVisualNovelGenerationPhase('ready');
        const openResult =
          selectionStageRef.current === 'visual-novel-generating';
        if (
          nextSession.draft?.profileId &&
          nextSession.draft.profileId !== nextSession.sessionId
        ) {
          clearPendingDraftShelfItem('visual-novel', nextSession.sessionId);
        }
        markPendingDraftReady(
          'visual-novel',
          nextSession.draft?.profileId ?? nextSession.sessionId,
          openResult,
        );
        markDraftReady(
          'visual-novel',
          [nextSession.draft?.profileId, nextSession.sessionId],
          openResult,
        );
        void refreshVisualNovelShelf();
        if (openResult) {
          setSelectionStage('visual-novel-result');
        }
      } catch (error) {
        setVisualNovelGenerationPhase('failed');
        setVisualNovelError(
          resolvePuzzleErrorMessage(error, '生成视觉小说草稿失败。'),
        );
      } finally {
        setIsVisualNovelBusy(false);
      }
    },
    [
      markDraftReady,
      markDraftGenerating,
      markPendingDraftGenerating,
      markPendingDraftReady,
      clearPendingDraftShelfItem,
      refreshVisualNovelShelf,
      resolvePuzzleErrorMessage,
      setIsVisualNovelBusy,
      setSelectionStage,
      setVisualNovelError,
      setVisualNovelSession,
    ],
  );

  const createBabyObjectMatchDraftFromForm = useCallback(
    async (payload: CreateBabyObjectMatchDraftRequest) => {
      setBabyObjectMatchFormPayload(payload);
      setBabyObjectMatchDraft(null);
      setBabyObjectMatchError(null);
      setIsBabyObjectMatchBusy(true);
      setBabyObjectMatchGenerationPhase('generating');
      setBabyObjectMatchGenerationState(
        createMiniGameDraftGenerationState('baby-object-match'),
      );
      selectionStageRef.current = 'baby-object-match-generating';
      setSelectionStage('baby-object-match-generating');

      try {
        const response = await createBabyObjectMatchDraft(payload);
        setBabyObjectMatchDraft(response.draft);
        writeCreationUrlState(
          buildBabyObjectMatchCreationUrlState(response.draft),
        );
        void refreshBabyObjectMatchShelf();
        setBabyObjectMatchGenerationPhase('ready');
        setBabyObjectMatchGenerationState((current) =>
          current
            ? resolveFinishedMiniGameDraftGenerationState(current, 'ready', {
                completedAssetCount: response.draft.itemAssets.length,
                totalAssetCount: response.draft.itemAssets.length,
              })
            : current,
        );
        const openResult =
          selectionStageRef.current === 'baby-object-match-generating';
        markDraftReady(
          'baby-object-match',
          [response.draft.profileId, response.draft.draftId],
          openResult,
        );
        if (openResult) {
          setSelectionStage('baby-object-match-result');
        }
      } catch (error) {
        const errorMessage = resolvePuzzleErrorMessage(
          error,
          '生成宝贝识物草稿失败。',
        );
        setBabyObjectMatchGenerationPhase('failed');
        setBabyObjectMatchError(errorMessage);
        setBabyObjectMatchGenerationState((current) =>
          current
            ? resolveFinishedMiniGameDraftGenerationState(current, 'failed', {
                error: errorMessage,
              })
            : current,
        );
      } finally {
        setIsBabyObjectMatchBusy(false);
      }
    },
    [
      markDraftReady,
      refreshBabyObjectMatchShelf,
      resolvePuzzleErrorMessage,
      setSelectionStage,
    ],
  );

  const savePuzzleFormDraft = useCallback(
    async (payload: CreatePuzzleAgentSessionRequest) => {
      const session = puzzleFlow.session;
      if (!session || session.stage !== 'collecting_anchors') {
        return;
      }

      setPuzzleFormDraftPayload(payload);

      try {
        const response = await executePuzzleAgentAction(session.sessionId, {
          action: 'save_puzzle_form_draft',
          promptText: payload.pictureDescription ?? null,
          workTitle: payload.workTitle,
          workDescription:
            payload.workDescription ?? payload.pictureDescription ?? '',
          pictureDescription: payload.pictureDescription ?? '',
          referenceImageSrc: payload.referenceImageSrc ?? null,
          referenceImageSrcs: payload.referenceImageSrcs ?? [],
          referenceImageAssetObjectId:
            payload.referenceImageAssetObjectId ?? null,
          referenceImageAssetObjectIds:
            payload.referenceImageAssetObjectIds ?? [],
          imageModel: payload.imageModel ?? null,
          aiRedraw: payload.aiRedraw ?? true,
        });
        setPuzzleOperation(response.operation);
        puzzleFlow.setSession(response.session);
        setPuzzleError(null);
        void refreshPuzzleShelf();
      } catch (error) {
        setPuzzleError(
          resolvePuzzleErrorMessage(error, '保存拼图表单草稿失败。'),
        );
      }
    },
    [puzzleFlow, refreshPuzzleShelf, resolvePuzzleErrorMessage, setPuzzleError],
  );

  useEffect(() => {
    if (platformBootstrap.canReadProtectedData) {
      hadReadableProtectedDataRef.current = true;
      return;
    }

    if (authUi?.user || !hadReadableProtectedDataRef.current) {
      return;
    }

    hadReadableProtectedDataRef.current = false;

    // 创作中心只展示当前登录用户的私有作品。
    // 一旦退出登录或鉴权上下文被收回，三类作品缓存必须同步清空，不能等刷新页面。
    setShowCreationTypeModal(false);
    setSelectedDetailEntry(null);
    setSelectedPublicWorkDetail(null);
    setPublicWorkDetailError(null);
    setIsPublicWorkDetailBusy(false);
    setBigFishWorks([]);
    setBigFishRun(null);
    setBigFishRuntimeShare(null);
    setBigFishRuntimeWork(null);
    setBigFishRuntimeStartedAt(null);
    setBigFishRuntimeReturnStage('platform');
    setBigFishGenerationState(null);
    setBigFishError(null);
    setMatch3DSession(null);
    setMatch3DProfile(null);
    setMatch3DRuntimeProfile(null);
    setMatch3DFormDraftPayload(null);
    setMatch3DBackgroundCompileTasks({});
    activeMatch3DGenerationSessionIdRef.current = null;
    setMatch3DWorks([]);
    setMatch3DGalleryEntries([]);
    setMatch3DRun(null);
    setMatch3DRuntimeReturnStage('match3d-result');
    setMatch3DError(null);
    setStreamingMatch3DReplyText('');
    setIsStreamingMatch3DReply(false);
    setSquareHoleSession(null);
    setSquareHoleProfile(null);
    setSquareHoleWorks([]);
    setSquareHoleGalleryEntries([]);
    setSquareHoleRun(null);
    setSquareHoleRuntimeReturnStage('square-hole-result');
    setSquareHoleGenerationState(null);
    setSquareHoleError(null);
    setStreamingSquareHoleReplyText('');
    setIsStreamingSquareHoleReply(false);
    setCreativeAgentSession(null);
    setCreativeAgentEvents([]);
    setActiveCreativeAgentSessionId(null);
    setCreativeAgentError(null);
    setIsCreativeAgentBusy(false);
    setIsCreativeAgentStreaming(false);
    setCreativeDraftEditError(null);
    setIsCreativeDraftEditBusy(false);
    setPuzzleOperation(null);
    setPuzzleWorks([]);
    setSelectedPuzzleDetail(null);
    setPuzzleRuntimeReturnStage('puzzle-gallery-detail');
    setPuzzleRun(null);
    setPuzzleRuntimeAuthMode('default');
    setPuzzleGenerationState(null);
    setPuzzleBackgroundCompileTasks({});
    activePuzzleGenerationSessionIdRef.current = null;
    setIsPuzzleNextLevelGenerating(false);
    setPuzzleShelfError(null);
    setPuzzleCreationError(null);
    setPuzzleError(null);
    setVisualNovelSession(null);
    setVisualNovelWork(null);
    setVisualNovelWorks([]);
    setVisualNovelGalleryEntries([]);
    setVisualNovelRun(null);
    setVisualNovelRuntimeReturnStage('visual-novel-result');
    setVisualNovelFormDraftPayload(null);
    setVisualNovelGenerationStartedAtMs(null);
    setVisualNovelGenerationPhase('generating');
    setVisualNovelError(null);
    setBabyObjectMatchDraft(null);
    setBabyObjectMatchDrafts([]);
    setBabyObjectMatchFormPayload(null);
    setBabyObjectMatchGenerationState(null);
    setBabyObjectMatchGenerationPhase('generating');
    setBabyObjectMatchRuntimeReturnStage('baby-object-match-result');
    setBabyObjectMatchError(null);
    setIsBabyObjectMatchBusy(false);
    setDeletingCreationWorkId(null);
    setClaimingPuzzlePointIncentiveProfileId(null);
    setPublishSharePayload(null);
    setProfilePlayStats(null);
    setProfilePlayStatsError(null);
    setIsProfilePlayStatsOpen(false);
    setDraftGenerationNotices({});
    setPendingDraftShelfItems({});
    setPendingPlatformTaskCompletionDialog(null);
    setPendingPlatformTaskFailureDialog(null);
    resetRpgSessionViewState();
    setRpgGeneratedCustomWorldProfile(null);
    setRpgCustomWorldError(null);
    persistRpgAgentUiState(null, null);
    resetAutoSaveTrackingToIdle();

    const nextSelectionStage =
      resolveSelectionStageAfterProtectedDataLoss(selectionStage);
    if (nextSelectionStage !== selectionStage) {
      setSelectionStage(nextSelectionStage);
    }
  }, [
    authUi?.user,
    platformBootstrap.canReadProtectedData,
    persistRpgAgentUiState,
    resetAutoSaveTrackingToIdle,
    resetRpgSessionViewState,
    selectionStage,
    setBigFishError,
    setIsStreamingMatch3DReply,
    setIsStreamingSquareHoleReply,
    setMatch3DError,
    setMatch3DSession,
    setPuzzleError,
    setRpgCustomWorldError,
    setRpgGeneratedCustomWorldProfile,
    setSelectionStage,
    setBabyObjectMatchError,
    setSquareHoleError,
    setSquareHoleSession,
    setStreamingMatch3DReplyText,
    setStreamingSquareHoleReplyText,
    setVisualNovelError,
    setVisualNovelSession,
  ]);

  const handleCreationHubCreateType = useCallback(
    (type: PlatformCreationTypeId) => {
      const intent = resolvePlatformCreationLaunchIntent({
        type,
        isBabyObjectMatchVisible,
      });

      if (!intent.shouldPrepare) {
        return;
      }

      if (!prepareCreationLaunch()) {
        return;
      }

      if (intent.type === 'blocked') {
        sessionController.setCreationTypeError(intent.message);
        return;
      }

      if (intent.type !== 'launch') {
        return;
      }

      const launchers = {
        rpg: () => {
          void sessionController.openRpgAgentWorkspace();
        },
        'big-fish': () => {
          void openBigFishAgentWorkspace();
        },
        match3d: () => {
          void openMatch3DWorkspace();
        },
        'square-hole': () => {
          void openSquareHoleAgentWorkspace();
        },
        'jump-hop': () => {
          void openJumpHopWorkspace();
        },
        'wooden-fish': () => {
          void openWoodenFishWorkspace();
        },
        puzzle: () => {
          void openPuzzleWorkspace();
        },
        'bark-battle': () => {
          void openBarkBattleWorkspace();
        },
        'visual-novel': () => {
          void openVisualNovelWorkspace();
        },
        'baby-object-match': () => {
          void openBabyObjectMatchWorkspace();
        },
      } satisfies Record<PlatformCreationLaunchTarget, () => void>;

      runProtectedAction(launchers[intent.target]);
    },
    [
      isBabyObjectMatchVisible,
      openBarkBattleWorkspace,
      openBigFishAgentWorkspace,
      openBabyObjectMatchWorkspace,
      openJumpHopWorkspace,
      openMatch3DWorkspace,
      prepareCreationLaunch,
      openPuzzleWorkspace,
      openSquareHoleAgentWorkspace,
      openVisualNovelWorkspace,
      openWoodenFishWorkspace,
      sessionController,
      runProtectedAction,
    ],
  );

  const leaveBigFishFlow = useCallback(() => {
    setBigFishRun(null);
    setBigFishRuntimeWork(null);
    setBigFishRuntimeStartedAt(null);
    setBigFishRuntimeReturnStage('platform');
    setBigFishGenerationState(null);
    bigFishFlow.leaveFlow();
    returnToCreationFlowSource();
  }, [bigFishFlow, returnToCreationFlowSource]);

  const leaveMatch3DFlow = useCallback(() => {
    setMatch3DRun(null);
    setMatch3DRuntimeProfile(null);
    setMatch3DFormDraftPayload(null);
    setMatch3DGenerationState(null);
    setMatch3DRuntimeReturnStage('match3d-result');
    match3dFlow.leaveFlow();
    returnToCreationFlowSource();
  }, [match3dFlow, returnToCreationFlowSource, setMatch3DFormDraftPayload]);

  const leaveSquareHoleFlow = useCallback(() => {
    setSquareHoleRun(null);
    setSquareHoleRuntimeReturnStage('square-hole-result');
    setSquareHoleGenerationState(null);
    squareHoleFlow.leaveFlow();
    returnToCreationFlowSource();
  }, [returnToCreationFlowSource, squareHoleFlow]);

  const leaveJumpHopFlow = useCallback(() => {
    setJumpHopRun(null);
    setJumpHopWork(null);
    setJumpHopRuntimeReturnStage('jump-hop-result');
    setJumpHopGenerationState(null);
    setJumpHopSession(null);
    setJumpHopError(null);
    returnToCreationFlowSource();
  }, [returnToCreationFlowSource]);

  const leaveWoodenFishFlow = useCallback(() => {
    setWoodenFishRun(null);
    setWoodenFishWork(null);
    setWoodenFishRuntimeReturnStage('wooden-fish-result');
    setWoodenFishGenerationState(null);
    setWoodenFishSession(null);
    setWoodenFishError(null);
    returnToCreationFlowSource();
  }, [returnToCreationFlowSource]);

  const createReadyJumpHopGenerationState = useCallback(
    (state: MiniGameDraftGenerationState) =>
      resolveFinishedMiniGameDraftGenerationState(state, 'ready', {
        completedAssetCount: 2,
        totalAssetCount: 2,
      }),
    [],
  );

  const createReadyWoodenFishGenerationState = useCallback(
    (state: MiniGameDraftGenerationState) =>
      resolveFinishedMiniGameDraftGenerationState(state, 'ready', {
        completedAssetCount: 2,
        totalAssetCount: 2,
      }),
    [],
  );

  const leaveBarkBattleFlow = useCallback(() => {
    setBarkBattleDraftConfig(null);
    setBarkBattlePublishedConfig(null);
    setBarkBattleRuntimeMode('draft');
    setBarkBattleRuntimeReturnStage('platform');
    setBarkBattleError(null);
    setBarkBattleGenerationPartialFailed(false);
    setIsBarkBattleBusy(false);
    returnToCreationFlowSource();
  }, [returnToCreationFlowSource]);

  const createBarkBattleGeneratingDraft = useCallback(
    async (payload: BarkBattleConfigEditorPayload) => {
      setBarkBattleError(null);
      const hasEnoughPoints = await preflightBarkBattleDraftGeneration();
      if (!hasEnoughPoints) {
        return;
      }
      setIsBarkBattleBusy(true);
      setBarkBattleGenerationPartialFailed(false);
      try {
        const draft = await createBarkBattleDraft(payload);
        setBarkBattleDraftConfig(draft);
        writeCreationUrlState(buildBarkBattleCreationUrlState(draft));
        setBarkBattlePublishedConfig(null);
        markDraftGenerating('bark-battle', [draft.workId, draft.draftId]);
        markPendingDraftGenerating(
          'bark-battle',
          draft.workId ?? draft.draftId,
        );
        updateBarkBattleWorkCaches(
          buildBarkBattleWorkSummaryFromDraft(
            draft,
            authUi?.user,
            'pending_assets',
          ),
        );
        void refreshBarkBattleShelf().catch(() => undefined);
        selectionStageRef.current = 'bark-battle-generating';
        setSelectionStage('bark-battle-generating');
      } catch (error) {
        setBarkBattleError(
          resolvePuzzleErrorMessage(error, '生成汪汪声浪草稿失败。'),
        );
      } finally {
        setIsBarkBattleBusy(false);
      }
    },
    [
      authUi?.user,
      markDraftGenerating,
      markPendingDraftGenerating,
      preflightBarkBattleDraftGeneration,
      refreshBarkBattleShelf,
      resolvePuzzleErrorMessage,
      setSelectionStage,
      updateBarkBattleWorkCaches,
    ],
  );

  const handleBarkBattleGenerationComplete = useCallback(
    (draft: BarkBattleDraftConfig, partialFailed: boolean) => {
      setBarkBattleDraftConfig(draft);
      writeCreationUrlState(buildBarkBattleCreationUrlState(draft));
      setBarkBattlePublishedConfig(null);
      setBarkBattleGenerationPartialFailed(partialFailed);
      const generationStatus = resolveBarkBattleDraftGenerationStatus(
        draft,
        partialFailed,
      );
      updateBarkBattleWorkCaches(
        buildBarkBattleWorkSummaryFromDraft(
          draft,
          authUi?.user,
          generationStatus,
        ),
      );
      markPendingDraftReady('bark-battle', draft.workId ?? draft.draftId, true);
      markDraftReady('bark-battle', [draft.workId, draft.draftId], true);
      void refreshBarkBattleShelf().catch(() => undefined);
      selectionStageRef.current = 'bark-battle-result';
      setSelectionStage('bark-battle-result');
    },
    [
      authUi?.user,
      markDraftReady,
      markPendingDraftReady,
      refreshBarkBattleShelf,
      setSelectionStage,
      updateBarkBattleWorkCaches,
    ],
  );

  const handleBarkBattleDraftChange = useCallback(
    async (draft: BarkBattleDraftConfig) => {
      setBarkBattleError(null);
      setBarkBattleGenerationPartialFailed(false);
      setBarkBattleDraftConfig(draft);
      if (!draft.draftId?.trim() || !draft.workId?.trim()) {
        return;
      }
      setIsBarkBattleBusy(true);
      try {
        const persistedDraft = await updateBarkBattleDraftConfig({
          draftId: draft.draftId,
          workId: draft.workId,
          configVersion: draft.configVersion,
          rulesetVersion: draft.rulesetVersion,
          title: draft.title,
          description: draft.description,
          themeDescription: draft.themeDescription,
          playerImageDescription: draft.playerImageDescription,
          opponentImageDescription: draft.opponentImageDescription,
          onomatopoeia: draft.onomatopoeia,
          playerCharacterImageSrc: draft.playerCharacterImageSrc,
          opponentCharacterImageSrc: draft.opponentCharacterImageSrc,
          uiBackgroundImageSrc: draft.uiBackgroundImageSrc,
          difficultyPreset: draft.difficultyPreset,
        });
        const nextDraft = {
          ...persistedDraft,
          playerCharacterImageSrc:
            draft.playerCharacterImageSrc ??
            persistedDraft.playerCharacterImageSrc,
          opponentCharacterImageSrc:
            draft.opponentCharacterImageSrc ??
            persistedDraft.opponentCharacterImageSrc,
          uiBackgroundImageSrc:
            draft.uiBackgroundImageSrc ?? persistedDraft.uiBackgroundImageSrc,
        };
        setBarkBattleDraftConfig(nextDraft);
        writeCreationUrlState(buildBarkBattleCreationUrlState(nextDraft));
        updateBarkBattleWorkCaches(
          buildBarkBattleWorkSummaryFromDraft(
            nextDraft,
            authUi?.user,
            resolveBarkBattleDraftGenerationStatus(nextDraft, false),
          ),
        );
        void refreshBarkBattleShelf().catch(() => undefined);
      } catch (error) {
        setBarkBattleError(
          resolvePuzzleErrorMessage(error, '保存汪汪声浪草稿素材失败。'),
        );
      } finally {
        setIsBarkBattleBusy(false);
      }
    },
    [
      authUi?.user,
      refreshBarkBattleShelf,
      resolvePuzzleErrorMessage,
      updateBarkBattleWorkCaches,
    ],
  );

  const testBarkBattleDraft = useCallback(
    (draft: BarkBattleDraftConfig) => {
      setBarkBattleError(null);
      setBarkBattleRuntimeMode('draft');
      setBarkBattleRuntimeReturnStage('bark-battle-result');
      setBarkBattlePublishedConfig(
        buildBarkBattlePublishedConfigFromDraft(draft),
      );
      selectionStageRef.current = 'bark-battle-runtime';
      setSelectionStage('bark-battle-runtime');
    },
    [setSelectionStage],
  );

  const publishBarkBattleDraft = useCallback(
    async (draft: BarkBattleDraftConfig) => {
      setBarkBattleError(null);
      const workId = draft.workId?.trim();
      if (!workId) {
        setBarkBattleError(
          '这份汪汪声浪草稿缺少作品ID，请重新生成草稿后再发布。',
        );
        return;
      }
      setIsBarkBattleBusy(true);
      try {
        const published = await publishBarkBattleWork({
          draftId: draft.draftId,
          workId,
          publishedSnapshot: buildBarkBattlePublishSnapshot(draft),
        });
        const publishedWithAssets = mergeBarkBattlePublishedConfigAssets(
          published,
          draft,
        );
        const publicWorkCode = buildBarkBattlePublicWorkCode(
          publishedWithAssets.workId,
        );
        setBarkBattlePublishedConfig(publishedWithAssets);
        setBarkBattleRuntimeReturnStage('work-detail');
        const publishedSummary: BarkBattleWorkSummary = {
          ...publishedWithAssets,
          ownerUserId: authUi?.user?.id ?? '',
          authorDisplayName: authUi?.user?.displayName ?? '创作者',
          summary: publishedWithAssets.description ?? '',
          status: 'published',
          generationStatus: 'ready',
          publishReady: true,
          playCount: 0,
          publishedAt: publishedWithAssets.publishedAt,
        };
        updateBarkBattleWorkCaches(publishedSummary);
        setSelectedPublicWorkDetail(
          mapBarkBattleWorkToPublicWorkDetail(publishedSummary),
        );
        selectionStageRef.current = 'work-detail';
        setSelectionStage('work-detail');
        pushAppHistoryPath(
          buildPublicWorkStagePath('work-detail', publicWorkCode),
        );
        void Promise.allSettled([
          refreshBarkBattleShelf(),
          refreshBarkBattleGallery(),
        ]);
        openPublishShareModal({
          title: publishedWithAssets.title,
          publicWorkCode,
          stage: 'work-detail',
        });
      } catch (error) {
        setBarkBattleError(
          resolvePuzzleErrorMessage(error, '发布汪汪声浪大作战作品失败。'),
        );
      } finally {
        setIsBarkBattleBusy(false);
      }
    },
    [
      authUi?.user?.displayName,
      authUi?.user?.id,
      openPublishShareModal,
      refreshBarkBattleGallery,
      refreshBarkBattleShelf,
      resolvePuzzleErrorMessage,
      setSelectionStage,
      updateBarkBattleWorkCaches,
    ],
  );

  const leavePuzzleFlow = useCallback(() => {
    setPuzzleOperation(null);
    puzzleRunRef.current = null;
    setPuzzleRun(null);
    setPuzzleRuntimeAuthMode('default');
    setPuzzleGenerationState(null);
    setIsPuzzleNextLevelGenerating(false);
    setActiveCreativeAgentSessionId(null);
    setCreativeDraftEditError(null);
    resetRecommendRuntimeSelection();
    clearPuzzleRuntimeUrlState();
    puzzleFlow.leaveFlow();
    returnToCreationFlowSource();
  }, [puzzleFlow, resetRecommendRuntimeSelection, returnToCreationFlowSource]);

  const leaveVisualNovelFlow = useCallback(() => {
    setVisualNovelWork(null);
    setVisualNovelRun(null);
    setVisualNovelRuntimeReturnStage('visual-novel-result');
    setVisualNovelFormDraftPayload(null);
    setVisualNovelGenerationStartedAtMs(null);
    setVisualNovelGenerationPhase('generating');
    visualNovelFlow.leaveFlow();
    returnToCreationFlowSource();
  }, [returnToCreationFlowSource, visualNovelFlow]);

  const leaveBabyObjectMatchFlow = useCallback(() => {
    setBabyObjectMatchDraft(null);
    setBabyObjectMatchFormPayload(null);
    setBabyObjectMatchGenerationState(null);
    setBabyObjectMatchGenerationPhase('generating');
    setBabyObjectMatchError(null);
    returnToCreationFlowSource();
  }, [returnToCreationFlowSource]);

  const saveBabyObjectMatchResultDraft = useCallback(
    async (draft: BabyObjectMatchDraft) => {
      setBabyObjectMatchError(null);
      setIsBabyObjectMatchBusy(true);
      try {
        const response = await saveBabyObjectMatchDraft({ draft });
        setBabyObjectMatchDraft(response.draft);
        writeCreationUrlState(
          buildBabyObjectMatchCreationUrlState(response.draft),
        );
        void refreshBabyObjectMatchShelf();
      } catch (error) {
        setBabyObjectMatchError(
          resolvePuzzleErrorMessage(error, '保存宝贝识物草稿失败。'),
        );
      } finally {
        setIsBabyObjectMatchBusy(false);
      }
    },
    [refreshBabyObjectMatchShelf, resolvePuzzleErrorMessage],
  );

  const ensureBabyObjectMatchGeneratedAssets = useCallback(
    async (draft: BabyObjectMatchDraft) => {
      if (!hasBabyObjectMatchPlaceholderAssets(draft)) {
        return draft;
      }

      const response = await regenerateBabyObjectMatchDraftAssets(draft);
      setBabyObjectMatchDraft(response.draft);
      void refreshBabyObjectMatchShelf();

      return response.draft;
    },
    [refreshBabyObjectMatchShelf],
  );

  const regenerateBabyObjectMatchResultAssets = useCallback(
    async (draft: BabyObjectMatchDraft) => {
      setBabyObjectMatchError(null);
      setIsBabyObjectMatchBusy(true);
      try {
        await ensureBabyObjectMatchGeneratedAssets(draft);
      } catch (error) {
        setBabyObjectMatchError(
          resolvePuzzleErrorMessage(error, '重新生成宝贝识物素材失败。'),
        );
      } finally {
        setIsBabyObjectMatchBusy(false);
      }
    },
    [ensureBabyObjectMatchGeneratedAssets, resolvePuzzleErrorMessage],
  );

  const publishBabyObjectMatchResultDraft = useCallback(
    async (draft: BabyObjectMatchDraft) => {
      setBabyObjectMatchError(null);
      setIsBabyObjectMatchBusy(true);
      try {
        const generatedDraft =
          await ensureBabyObjectMatchGeneratedAssets(draft);
        const response = await publishBabyObjectMatchWork({
          draft: generatedDraft,
        });
        setBabyObjectMatchDraft(response.draft);
        void refreshBabyObjectMatchShelf();
        openPublishShareModal({
          title: response.draft.workTitle,
          publicWorkCode:
            response.publicWorkCode ||
            buildBabyObjectMatchPublicWorkCode(response.draft.profileId),
          stage: 'work-detail',
        });
      } catch (error) {
        setBabyObjectMatchError(
          resolvePuzzleErrorMessage(
            error,
            '生成宝贝识物素材失败，请重试后再发布。',
          ),
        );
      } finally {
        setIsBabyObjectMatchBusy(false);
      }
    },
    [
      ensureBabyObjectMatchGeneratedAssets,
      openPublishShareModal,
      refreshBabyObjectMatchShelf,
      resolvePuzzleErrorMessage,
    ],
  );

  const startBabyObjectMatchRuntimeFromDraft = useCallback(
    async (
      draft: BabyObjectMatchDraft,
      returnStage: BabyObjectMatchRuntimeReturnStage = 'baby-object-match-result',
      options: { embedded?: boolean } = {},
    ) => {
      setBabyObjectMatchError(null);
      setIsBabyObjectMatchBusy(true);
      try {
        const generatedDraft =
          await ensureBabyObjectMatchGeneratedAssets(draft);
        setBabyObjectMatchDraft(generatedDraft);
        setBabyObjectMatchFormPayload({
          itemAName: generatedDraft.itemNames[0],
          itemBName: generatedDraft.itemNames[1],
        });
        setBabyObjectMatchRuntimeReturnStage(returnStage);
        if (!options.embedded) {
          setSelectionStage('baby-object-match-runtime');
          const publicWorkCode =
            generatedDraft.publicationStatus === 'published'
              ? buildBabyObjectMatchPublicWorkCode(generatedDraft.profileId)
              : null;
          if (publicWorkCode) {
            pushAppHistoryPath(
              buildPublicWorkStagePath(
                'baby-object-match-runtime',
                publicWorkCode,
              ),
            );
          }
        }
        return true;
      } catch (error) {
        const message = resolvePuzzleErrorMessage(
          error,
          '生成宝贝识物素材失败，请重试后再试玩。',
        );
        setBabyObjectMatchError(message);
        if (options.embedded) {
          setActiveRecommendRuntimeError(message);
        }
        return false;
      } finally {
        setIsBabyObjectMatchBusy(false);
      }
    },
    [
      ensureBabyObjectMatchGeneratedAssets,
      resolvePuzzleErrorMessage,
      setSelectionStage,
    ],
  );

  const startBabyLoveDrawingRuntime = useCallback(() => {
    setSelectionStage('baby-love-drawing-runtime');
    pushAppHistoryPath('/runtime/baby-love-drawing');
  }, [setSelectionStage]);

  const startChildMotionDemo = useCallback(() => {
    window.location.assign('/child-motion-demo');
  }, []);

  const resolveBabyObjectMatchRuntimeDraft = useCallback(
    async (entry: PlatformPublicGalleryCard) => {
      if (!isEdutainmentGalleryEntry(entry)) {
        return null;
      }

      return (
        babyObjectMatchDrafts.find(
          (draft) => draft.profileId === entry.profileId,
        ) ??
        (await listLocalBabyObjectMatchDrafts()).find(
          (draft) => draft.profileId === entry.profileId,
        ) ??
        null
      );
    },
    [babyObjectMatchDrafts],
  );

  const startBabyObjectMatchRuntimeFromEntry = useCallback(
    async (
      entry: PlatformPublicGalleryCard,
      returnStage: BabyObjectMatchRuntimeReturnStage = 'work-detail',
      options: { embedded?: boolean } = {},
    ) => {
      const draft = await resolveBabyObjectMatchRuntimeDraft(entry);
      if (!draft) {
        setPublicWorkDetailError(
          '当前宝贝识物作品缺少本地草稿，暂时无法进入玩法。',
        );
        return false;
      }

      return await startBabyObjectMatchRuntimeFromDraft(
        draft,
        returnStage,
        options,
      );
    },
    [resolveBabyObjectMatchRuntimeDraft, startBabyObjectMatchRuntimeFromDraft],
  );

  const saveVisualNovelDraft = useCallback(
    async (draft: VisualNovelResultDraft) => {
      const currentSession = visualNovelSession;
      if (!currentSession || !currentSession.sessionId.trim()) {
        return;
      }

      setVisualNovelError(null);
      const now = new Date().toISOString();
      // 中文注释：VN-07 的保存草稿先保证结果页编辑不会丢失；
      // 后端 work profile 编译仍由“编译草稿”显式触发，避免把本地保存伪装成正式持久化。
      setVisualNovelSession({
        ...currentSession,
        draft,
        status: draft.publishReady ? 'ready' : currentSession.status,
        updatedAt: now,
      });
      if (!visualNovelWork) {
        return;
      }

      setIsVisualNovelBusy(true);
      try {
        const response = await updateVisualNovelWork(
          visualNovelWork.summary.profileId,
          { draft },
        );
        setVisualNovelWork(response.work);
      } catch (error) {
        setVisualNovelError(
          resolvePuzzleErrorMessage(error, '保存视觉小说草稿失败。'),
        );
      } finally {
        setIsVisualNovelBusy(false);
      }
    },
    [
      resolvePuzzleErrorMessage,
      setIsVisualNovelBusy,
      setVisualNovelError,
      setVisualNovelSession,
      visualNovelSession,
      visualNovelWork,
    ],
  );

  const compileVisualNovelDraft = useCallback(
    async (draft: VisualNovelResultDraft) => {
      const sessionId = visualNovelSession?.sessionId?.trim();
      if (!sessionId) {
        return;
      }

      setVisualNovelError(null);
      setIsVisualNovelBusy(true);
      try {
        const response = await compileVisualNovelWorkProfile(sessionId, {
          draft,
        });
        setVisualNovelSession(response.session);
        setVisualNovelWork(response.work);
        clearPendingDraftShelfItem('visual-novel', sessionId);
        setSelectionStage('visual-novel-result');
      } catch (error) {
        setVisualNovelError(
          resolvePuzzleErrorMessage(error, '编译视觉小说草稿失败。'),
        );
      } finally {
        setIsVisualNovelBusy(false);
      }
    },
    [
      clearPendingDraftShelfItem,
      resolvePuzzleErrorMessage,
      setIsVisualNovelBusy,
      setSelectionStage,
      setVisualNovelError,
      setVisualNovelSession,
      visualNovelSession?.sessionId,
    ],
  );

  const publishVisualNovelDraft = useCallback(
    async (draft: VisualNovelResultDraft) => {
      const profileId = draft.profileId?.trim();
      if (!profileId) {
        return;
      }

      setVisualNovelError(null);
      setIsVisualNovelBusy(true);
      try {
        const { work } = await updateVisualNovelWork(profileId, {
          draft,
        });
        setVisualNovelWork(work);
        const publishedResponse = await publishVisualNovelWork(profileId);
        setVisualNovelWork(publishedResponse.work);
        setSelectedPublicWorkDetail(
          mapVisualNovelWorkToPublicWorkDetail(publishedResponse.work.summary),
        );
        await Promise.allSettled([
          refreshVisualNovelShelf(),
          refreshVisualNovelGallery(),
        ]);
        openPublishShareModal({
          title: publishedResponse.work.summary.title,
          publicWorkCode: buildVisualNovelPublicWorkCode(
            publishedResponse.work.summary.profileId,
          ),
          stage: 'work-detail',
        });
      } catch (error) {
        setVisualNovelError(
          resolvePuzzleErrorMessage(error, '发布视觉小说作品失败。'),
        );
      } finally {
        setIsVisualNovelBusy(false);
      }
    },
    [
      openPublishShareModal,
      refreshVisualNovelGallery,
      refreshVisualNovelShelf,
      resolvePuzzleErrorMessage,
      setIsVisualNovelBusy,
      setVisualNovelError,
    ],
  );

  const startVisualNovelTestRunFromDraft = useCallback(
    async (draft: VisualNovelResultDraft) => {
      const profileId =
        visualNovelWork?.summary.profileId?.trim() ?? draft.profileId?.trim();
      if (!profileId) {
        const run = createMockVisualNovelRunFromDraft(draft);
        setVisualNovelRun(run);
        setVisualNovelRuntimeReturnStage('visual-novel-result');
        setSelectionStage('visual-novel-runtime');
        return;
      }

      setVisualNovelError(null);
      setIsVisualNovelBusy(true);
      try {
        const { run } = await startVisualNovelRun(profileId, {
          profileId,
          mode: 'test',
        });
        setVisualNovelRun(run);
        setVisualNovelRuntimeReturnStage('visual-novel-result');
        setSelectionStage('visual-novel-runtime');
      } catch (error) {
        // 中文注释：VN-07 只要求结果页进入测试运行时；真实 runtime 接口未就绪时，
        // 使用当前 draft 生成本地 test run，不扩展到正式玩家运行链路。
        setVisualNovelRun(createMockVisualNovelRunFromDraft(draft));
        setVisualNovelRuntimeReturnStage('visual-novel-result');
        setSelectionStage('visual-novel-runtime');
        setVisualNovelError(
          resolvePuzzleErrorMessage(
            error,
            '已进入本地试玩，真实运行接口暂不可用。',
          ),
        );
      } finally {
        setIsVisualNovelBusy(false);
      }
    },
    [
      resolvePuzzleErrorMessage,
      setIsVisualNovelBusy,
      setVisualNovelError,
      setSelectionStage,
      visualNovelWork?.summary.profileId,
    ],
  );

  const startVisualNovelRunFromProfile = useCallback(
    async (
      profileId: string,
      returnStage: VisualNovelRuntimeReturnStage = 'work-detail',
      options: { embedded?: boolean } = {},
    ) => {
      const targetProfileId = profileId.trim();
      if (!targetProfileId) {
        return false;
      }

      setVisualNovelError(null);
      setIsVisualNovelBusy(true);

      try {
        let workDetail =
          visualNovelWork?.summary.profileId === targetProfileId
            ? visualNovelWork
            : null;
        if (!workDetail) {
          const response = await getVisualNovelWorkDetail(
            targetProfileId,
            options.embedded ? RECOMMEND_RUNTIME_BACKGROUND_AUTH_OPTIONS : {},
          );
          workDetail = response.work;
        }
        const startRunPayload = {
          profileId: targetProfileId,
          mode: 'play' as const,
        };
        const runtimeGuestOptions = await buildRecommendRuntimeAuthOptions(
          authUi,
          options.embedded,
        );
        const { run } = options.embedded
          ? await startVisualNovelRun(
              targetProfileId,
              startRunPayload,
              runtimeGuestOptions,
            )
          : await startVisualNovelRun(targetProfileId, startRunPayload);
        setVisualNovelWork(workDetail);
        setVisualNovelRun(run);
        setVisualNovelRuntimeReturnStage(returnStage);
        if (!options.embedded) {
          setSelectionStage('visual-novel-runtime');
          pushAppHistoryPath(
            buildPublicWorkStagePath(
              'visual-novel-runtime',
              buildVisualNovelPublicWorkCode(targetProfileId),
            ),
          );
        }
        return true;
      } catch (error) {
        setVisualNovelError(
          resolvePuzzleErrorMessage(error, '启动视觉小说试玩失败。'),
        );
        return false;
      } finally {
        setIsVisualNovelBusy(false);
      }
    },
    [
      authUi,
      resolvePuzzleErrorMessage,
      setIsVisualNovelBusy,
      setSelectionStage,
      setVisualNovelError,
      visualNovelWork,
    ],
  );

  const submitVisualNovelRuntimeAction = useCallback(
    async (payload: VisualNovelRuntimeActionRequest) => {
      if (!visualNovelRun || isVisualNovelBusy) {
        return;
      }

      if (visualNovelRun.runId.startsWith('vn-run-local')) {
        return;
      }

      setVisualNovelError(null);
      setIsVisualNovelBusy(true);
      try {
        const runtimeGuestOptions =
          activeRecommendRuntimeKind === 'visual-novel'
            ? await buildRecommendRuntimeAuthOptions(authUi, true)
            : {};
        const nextRun = await streamVisualNovelRuntimeAction(
          visualNovelRun.runId,
          payload,
          runtimeGuestOptions,
        );
        setVisualNovelRun(nextRun);
      } catch (error) {
        setVisualNovelError(
          resolvePuzzleErrorMessage(error, '推进视觉小说运行失败。'),
        );
      } finally {
        setIsVisualNovelBusy(false);
      }
    },
    [
      activeRecommendRuntimeKind,
      authUi,
      isVisualNovelBusy,
      resolvePuzzleErrorMessage,
      setIsVisualNovelBusy,
      setVisualNovelError,
      visualNovelRun,
    ],
  );

  const streamCreativeAgentPayloadForSession = useCallback(
    async (
      session: CreativeAgentSessionSnapshot,
      payload: StreamCreativeAgentMessageRequest,
    ) => {
      setCreativeAgentError(null);
      setIsCreativeAgentStreaming(true);
      setCreativeAgentEvents([]);
      setCreativeAgentSession((current) =>
        current
          ? {
              ...current,
              messages: [
                ...current.messages,
                {
                  id: payload.clientMessageId,
                  role: 'user',
                  kind: 'chat',
                  text: payload.content
                    .map((part) =>
                      part.type === 'input_text' ? part.text.trim() : '参考图',
                    )
                    .filter(Boolean)
                    .join(' / '),
                  createdAt: new Date().toISOString(),
                },
              ],
            }
          : current,
      );

      try {
        const nextSession = await streamCreativeAgentMessage(
          session.sessionId,
          payload,
          {
            onEvent: (event) => {
              setCreativeAgentEvents((current) => [...current, event]);
              if (event.event === 'stage') {
                setCreativeAgentSession((current) =>
                  current
                    ? {
                        ...current,
                        stage: event.data.stage,
                        updatedAt: new Date().toISOString(),
                      }
                    : current,
                );
              }
              if (event.event === 'session') {
                setCreativeAgentSession(event.data.session);
              }
            },
          },
        );
        setCreativeAgentSession(nextSession);
        if (nextSession.targetBinding) {
          setActiveCreativeAgentSessionId(nextSession.sessionId);
        }
      } catch (error) {
        setCreativeAgentError(
          resolvePuzzleErrorMessage(error, '发送智能创作消息失败。'),
        );
      } finally {
        setIsCreativeAgentStreaming(false);
      }
    },
    [resolvePuzzleErrorMessage],
  );

  const submitCreativeAgentMessage = useCallback(
    async (payload: StreamCreativeAgentMessageRequest) => {
      if (!creativeAgentSession || isCreativeAgentStreaming) {
        return;
      }

      await streamCreativeAgentPayloadForSession(creativeAgentSession, payload);
    },
    [
      creativeAgentSession,
      isCreativeAgentStreaming,
      streamCreativeAgentPayloadForSession,
    ],
  );

  const confirmCreativeTemplateSelection = useCallback(
    async (selection: PuzzleCreativeTemplateSelection) => {
      const sessionId = creativeAgentSession?.sessionId?.trim();
      if (!sessionId || isCreativeAgentBusy || isCreativeAgentStreaming) {
        return;
      }

      setIsCreativeAgentBusy(true);
      setCreativeAgentError(null);
      try {
        const response = await confirmCreativePuzzleTemplate(sessionId, {
          selection,
        });
        setCreativeAgentSession(response.session);
        if (response.session.targetBinding) {
          setActiveCreativeAgentSessionId(response.session.sessionId);
        }
      } catch (error) {
        setCreativeAgentError(
          resolvePuzzleErrorMessage(error, '确认拼图模板失败。'),
        );
      } finally {
        setIsCreativeAgentBusy(false);
      }
    },
    [
      creativeAgentSession?.sessionId,
      isCreativeAgentBusy,
      isCreativeAgentStreaming,
      resolvePuzzleErrorMessage,
    ],
  );

  const submitBigFishMessage = bigFishFlow.submitMessage;

  const submitSquareHoleMessage = squareHoleFlow.submitMessage;

  const submitPuzzleMessage = puzzleFlow.submitMessage;

  const executeBigFishAction = bigFishFlow.executeAction;

  const executeMatch3DAction = match3dFlow.executeAction;

  const executeSquareHoleAction = squareHoleFlow.executeAction;

  const retryMatch3DDraftGeneration = useCallback(() => {
    if (match3dFormDraftPayload && !match3dSession?.draft?.profileId) {
      void createMatch3DDraftFromForm(match3dFormDraftPayload);
      return;
    }

    void executeMatch3DAction({
      action: 'match3d_compile_draft',
      generateClickSound: match3dFormDraftPayload?.generateClickSound,
    });
  }, [
    createMatch3DDraftFromForm,
    executeMatch3DAction,
    match3dFormDraftPayload,
    match3dSession?.draft?.profileId,
  ]);

  const retrySquareHoleAssetGeneration = useCallback(() => {
    const session = squareHoleSession;
    if (!session?.draft?.profileId) {
      void executeSquareHoleAction({
        action: 'square_hole_compile_draft',
      });
      return;
    }

    void executeSquareHoleAction({
      action: 'square_hole_generate_visual_assets',
    });
  }, [executeSquareHoleAction, squareHoleSession]);

  const compileJumpHopSession = useCallback(
    async (
      created: JumpHopSessionResponse,
      payload?: JumpHopWorkspaceCreateRequest,
    ) => {
      const generationState = createMiniGameDraftGenerationState(
        'jump-hop',
        resolveMiniGameDraftGenerationStartedAtMs(created.session.updatedAt),
      );
      setJumpHopError(null);
      setJumpHopSession(created.session);
      writeCreationUrlState(
        buildJumpHopCreationUrlState({ session: created.session }),
      );
      setJumpHopWork(null);
      setJumpHopRun(null);
      setJumpHopGenerationState(generationState);
      setIsJumpHopBusy(true);
      setSelectionStage('jump-hop-generating');
      markDraftGenerating('jump-hop', [
        created.session.sessionId,
        created.session.draft?.profileId,
      ]);
      markPendingDraftGenerating('jump-hop', created.session.sessionId);

      try {
        const response = await jumpHopClient.executeAction(
          created.session.sessionId,
          {
            actionType: 'compile-draft',
            workTitle: payload?.workTitle ?? created.session.draft?.workTitle,
            workDescription:
              payload?.workDescription ??
              created.session.draft?.workDescription,
            themeTags: payload?.themeTags ?? created.session.draft?.themeTags,
            difficulty:
              payload?.difficulty ?? created.session.draft?.difficulty,
            stylePreset:
              payload?.stylePreset ?? created.session.draft?.stylePreset,
            characterPrompt:
              payload?.characterPrompt ??
              created.session.draft?.characterPrompt,
            tilePrompt:
              payload?.tilePrompt ?? created.session.draft?.tilePrompt,
            endMoodPrompt:
              payload?.endMoodPrompt ?? created.session.draft?.endMoodPrompt,
          },
        );
        const readyState = createReadyJumpHopGenerationState(generationState);
        setJumpHopSession(response.session);
        setJumpHopWork(response.work ?? null);
        writeCreationUrlState(
          buildJumpHopCreationUrlState({
            session: response.session,
            work: response.work,
          }),
        );
        setJumpHopGenerationState(readyState);
        if (response.work) {
          setJumpHopWorks((current) => [
            response.work!.summary,
            ...current.filter(
              (item) => item.workId !== response.work!.summary.workId,
            ),
          ]);
          markPendingDraftReady('jump-hop', created.session.sessionId, false);
          markDraftReady(
            'jump-hop',
            [
              created.session.sessionId,
              response.work.summary.workId,
              response.work.summary.profileId,
            ],
            false,
          );
          void refreshJumpHopShelf().catch(() => undefined);
        }
        setSelectionStage('jump-hop-result');
      } catch (error) {
        const errorMessage = resolveRpgCreationErrorMessage(
          error,
          '生成跳一跳草稿失败。',
        );
        setJumpHopError(errorMessage);
        setJumpHopGenerationState(
          resolveFinishedMiniGameDraftGenerationState(
            generationState,
            'failed',
            { error: errorMessage },
          ),
        );
        markPendingDraftFailed('jump-hop', created.session.sessionId);
        markDraftFailed(
          'jump-hop',
          [created.session.sessionId, created.session.draft?.profileId],
          errorMessage,
        );
        void refreshJumpHopShelf().catch(() => undefined);
        try {
          const latest = await jumpHopClient.getSession(
            created.session.sessionId,
          );
          markDraftFailed(
            'jump-hop',
            [latest.session.sessionId, latest.session.draft?.profileId],
            errorMessage,
          );
          setJumpHopSession(latest.session);
          setJumpHopWork(null);
          writeCreationUrlState(
            buildJumpHopCreationUrlState({ session: latest.session }),
          );
        } catch {
          setJumpHopSession(created.session);
          setJumpHopWork(null);
          writeCreationUrlState(
            buildJumpHopCreationUrlState({ session: created.session }),
          );
        }
      } finally {
        setIsJumpHopBusy(false);
      }
    },
    [
      createReadyJumpHopGenerationState,
      markDraftFailed,
      markDraftGenerating,
      markPendingDraftFailed,
      markPendingDraftGenerating,
      refreshJumpHopShelf,
      setSelectionStage,
    ],
  );

  const retryJumpHopDraftGeneration = useCallback(() => {
    if (!jumpHopSession) {
      setSelectionStage('jump-hop-workspace');
      return;
    }

    void compileJumpHopSession({ session: jumpHopSession });
  }, [compileJumpHopSession, jumpHopSession, setSelectionStage]);

  const regenerateJumpHopAsset = useCallback(
    async (actionType: 'regenerate-character' | 'regenerate-tiles') => {
      if (!jumpHopSession?.sessionId) {
        setSelectionStage('jump-hop-workspace');
        return;
      }

      const generationState = createMiniGameDraftGenerationState('jump-hop');
      setJumpHopError(null);
      setJumpHopGenerationState(generationState);
      setIsJumpHopBusy(true);
      setSelectionStage('jump-hop-generating');
      try {
        const response = await jumpHopClient.executeAction(
          jumpHopSession.sessionId,
          {
            actionType,
            workTitle: jumpHopSession.draft?.workTitle,
            workDescription: jumpHopSession.draft?.workDescription,
            themeTags: jumpHopSession.draft?.themeTags,
            difficulty: jumpHopSession.draft?.difficulty,
            stylePreset: jumpHopSession.draft?.stylePreset,
            characterPrompt: jumpHopSession.draft?.characterPrompt,
            tilePrompt: jumpHopSession.draft?.tilePrompt,
            endMoodPrompt: jumpHopSession.draft?.endMoodPrompt,
          },
        );
        setJumpHopSession(response.session);
        setJumpHopWork(response.work ?? jumpHopWork);
        writeCreationUrlState(
          buildJumpHopCreationUrlState({
            session: response.session,
            work: response.work ?? jumpHopWork,
          }),
        );
        setJumpHopGenerationState(
          createReadyJumpHopGenerationState(generationState),
        );
        setSelectionStage('jump-hop-result');
      } catch (error) {
        const errorMessage = resolveRpgCreationErrorMessage(
          error,
          actionType === 'regenerate-character'
            ? '重新生成跳一跳角色失败。'
            : '重新生成跳一跳地块失败。',
        );
        setJumpHopError(errorMessage);
        setJumpHopGenerationState(
          resolveFinishedMiniGameDraftGenerationState(
            generationState,
            'failed',
            { error: errorMessage },
          ),
        );
      } finally {
        setIsJumpHopBusy(false);
      }
    },
    [
      createReadyJumpHopGenerationState,
      jumpHopSession?.draft,
      jumpHopSession?.sessionId,
      jumpHopWork,
      setSelectionStage,
    ],
  );

  const publishJumpHopDraft = useCallback(async () => {
    const profileId = jumpHopWork?.summary.profileId?.trim();
    if (!profileId) {
      setJumpHopError('跳一跳草稿尚未生成可发布作品。');
      setSelectionStage('jump-hop-result');
      return;
    }

    setIsJumpHopBusy(true);
    setJumpHopError(null);
    try {
      const response = await jumpHopClient.publishWork(profileId);
      setJumpHopWork(response.item);
      setJumpHopWorks((current) => [
        response.item.summary,
        ...current.filter(
          (item) => item.workId !== response.item.summary.workId,
        ),
      ]);
      void refreshJumpHopShelf().catch(() => undefined);
      openPublishShareModal({
        title: response.item.summary.workTitle || '跳一跳',
        publicWorkCode: buildJumpHopPublicWorkCode(
          response.item.summary.profileId,
        ),
        stage: 'work-detail',
      });
    } catch (error) {
      setJumpHopError(
        resolveRpgCreationErrorMessage(error, '发布跳一跳作品失败。'),
      );
      setSelectionStage('jump-hop-result');
    } finally {
      setIsJumpHopBusy(false);
    }
  }, [
    jumpHopWork?.summary.profileId,
    openPublishShareModal,
    setSelectionStage,
  ]);

  const startJumpHopTestRunFromProfile = useCallback(async () => {
    const profileId = jumpHopWork?.summary.profileId?.trim();
    if (!profileId) {
      setJumpHopError('跳一跳草稿尚未生成可试玩作品。');
      setSelectionStage('jump-hop-result');
      return;
    }

    setIsJumpHopBusy(true);
    setJumpHopError(null);
    setJumpHopRuntimeReturnStage('jump-hop-result');
    try {
      const response = await jumpHopClient.startRun(profileId);
      setJumpHopRun(response.run);
      setSelectionStage('jump-hop-runtime');
    } catch (error) {
      setJumpHopError(
        error instanceof Error ? error.message : '启动跳一跳试玩失败。',
      );
      setSelectionStage('jump-hop-result');
    } finally {
      setIsJumpHopBusy(false);
    }
  }, [jumpHopWork?.summary.profileId, setSelectionStage]);

  const startJumpHopRunFromProfile = useCallback(
    async (
      profileId: string,
      options: {
        embedded?: boolean;
        returnStage?: 'work-detail' | 'platform';
      } = {},
    ) => {
      const normalizedProfileId = profileId.trim();
      if (!normalizedProfileId) {
        setJumpHopError('当前跳一跳作品信息不完整，暂时无法进入玩法。');
        return false;
      }

      setIsJumpHopBusy(true);
      setJumpHopError(null);
      setJumpHopRuntimeReturnStage(options.returnStage ?? 'work-detail');
      try {
        const runtimeGuestOptions = await buildRecommendRuntimeAuthOptions(
          authUi,
          options.embedded,
        );
        const [detail, runResponse] = await Promise.all([
          jumpHopClient.getWorkDetail(normalizedProfileId).catch(() => null),
          jumpHopClient.startRun(normalizedProfileId, runtimeGuestOptions),
        ]);
        if (detail?.item) {
          setJumpHopWork(detail.item);
        }
        setJumpHopRun(runResponse.run);
        if (!options.embedded) {
          setSelectionStage('jump-hop-runtime');
          pushAppHistoryPath(
            buildPublicWorkStagePath(
              'jump-hop-runtime',
              buildJumpHopPublicWorkCode(normalizedProfileId),
            ),
          );
        }
        return true;
      } catch (error) {
        setJumpHopError(
          resolveRpgCreationErrorMessage(error, '启动跳一跳玩法失败。'),
        );
        return false;
      } finally {
        setIsJumpHopBusy(false);
      }
    },
    [authUi, setSelectionStage],
  );

  const restartJumpHopRuntimeRun = useCallback(async () => {
    const runId = jumpHopRun?.runId;
    if (!runId) {
      await startJumpHopTestRunFromProfile();
      return;
    }

    setIsJumpHopBusy(true);
    setJumpHopError(null);
    try {
      const response = await jumpHopClient.restartRun(runId);
      setJumpHopRun(response.run);
    } catch (error) {
      setJumpHopError(
        resolveRpgCreationErrorMessage(error, '重新开始跳一跳失败。'),
      );
    } finally {
      setIsJumpHopBusy(false);
    }
  }, [jumpHopRun?.runId, startJumpHopTestRunFromProfile]);

  const submitJumpHopJumpAction = useCallback(
    async (payload: { chargeMs: number }) => {
      const runId = jumpHopRun?.runId;
      if (!runId) {
        return;
      }
      try {
        const response = await jumpHopClient.submitJump(runId, payload);
        setJumpHopRun(response.run);
      } catch (error) {
        setJumpHopError(
          resolveRpgCreationErrorMessage(error, '提交跳一跳失败。'),
        );
      }
    },
    [jumpHopRun?.runId],
  );

  const compileWoodenFishSession = useCallback(
    async (
      created: WoodenFishSessionResponse,
      payload?: WoodenFishWorkspaceCreateRequest,
    ) => {
      const generationState = createMiniGameDraftGenerationState(
        'wooden-fish',
        resolveMiniGameDraftGenerationStartedAtMs(
          created.session.updatedAt ?? created.session.createdAt,
        ),
      );
      setWoodenFishError(null);
      setWoodenFishSession(created.session);
      writeCreationUrlState(
        buildWoodenFishCreationUrlState({ session: created.session }),
      );
      setWoodenFishWork(null);
      setWoodenFishRun(null);
      setWoodenFishGenerationState(generationState);
      setIsWoodenFishBusy(true);
      setSelectionStage('wooden-fish-generating');
      markDraftGenerating('wooden-fish', [created.session.sessionId]);
      markPendingDraftGenerating('wooden-fish', created.session.sessionId);
      const createdAt = created.session.updatedAt ?? created.session.createdAt;
      setWoodenFishWorks((current) => [
        {
          runtimeKind: 'wooden-fish',
          workId: created.session.sessionId,
          profileId: created.session.sessionId,
          ownerUserId: created.session.ownerUserId,
          sourceSessionId: created.session.sessionId,
          workTitle:
            payload?.workTitle ?? created.session.draft?.workTitle ?? '敲木鱼',
          workDescription:
            payload?.workDescription ??
            created.session.draft?.workDescription ??
            '',
          themeTags: payload?.themeTags ??
            created.session.draft?.themeTags ?? ['敲木鱼'],
          coverImageSrc: created.session.draft?.coverImageSrc ?? null,
          publicationStatus: 'draft',
          playCount: 0,
          updatedAt: createdAt,
          publishedAt: null,
          publishReady: false,
          generationStatus: 'generating',
        },
        ...current.filter(
          (item) => item.sourceSessionId !== created.session.sessionId,
        ),
      ]);

      try {
        const response = await woodenFishClient.executeAction(
          created.session.sessionId,
          {
            actionType: 'compile-draft',
            workTitle: payload?.workTitle ?? created.session.draft?.workTitle,
            workDescription:
              payload?.workDescription ??
              created.session.draft?.workDescription,
            themeTags: payload?.themeTags ?? created.session.draft?.themeTags,
            hitObjectPrompt:
              payload?.hitObjectPrompt ??
              created.session.draft?.hitObjectPrompt,
            hitObjectReferenceImageSrc:
              payload?.hitObjectReferenceImageSrc ??
              created.session.draft?.hitObjectReferenceImageSrc,
            hitSoundAsset:
              payload?.hitSoundAsset ?? created.session.draft?.hitSoundAsset,
            floatingWords:
              payload?.floatingWords ?? created.session.draft?.floatingWords,
          },
        );
        setWoodenFishSession(response.session);
        setWoodenFishWork(response.work ?? null);
        writeCreationUrlState(
          buildWoodenFishCreationUrlState({
            session: response.session,
            work: response.work,
          }),
        );
        setWoodenFishGenerationState(
          createReadyWoodenFishGenerationState(generationState),
        );
        if (response.work) {
          setWoodenFishWorks((current) => [
            response.work!.summary,
            ...current.filter(
              (item) =>
                item.workId !== response.work!.summary.workId &&
                item.sourceSessionId !== response.work!.summary.sourceSessionId,
            ),
          ]);
          markPendingDraftReady(
            'wooden-fish',
            created.session.sessionId,
            false,
          );
          markDraftReady(
            'wooden-fish',
            [
              created.session.sessionId,
              response.work.summary.workId,
              response.work.summary.profileId,
              response.work.summary.sourceSessionId,
            ],
            false,
          );
          void refreshWoodenFishShelf().catch(() => undefined);
        }
        setSelectionStage('wooden-fish-result');
      } catch (error) {
        const errorMessage = resolveRpgCreationErrorMessage(
          error,
          '生成敲木鱼草稿失败。',
        );
        setWoodenFishError(errorMessage);
        setWoodenFishGenerationState(
          resolveFinishedMiniGameDraftGenerationState(
            generationState,
            'failed',
            { error: errorMessage },
          ),
        );
        markPendingDraftFailed('wooden-fish', created.session.sessionId);
        markDraftFailed(
          'wooden-fish',
          [created.session.sessionId, created.session.draft?.profileId],
          errorMessage,
        );
        setWoodenFishWorks((current) =>
          current.map((item) =>
            item.sourceSessionId === created.session.sessionId
              ? {
                  ...item,
                  generationStatus: 'failed',
                  updatedAt: new Date().toISOString(),
                }
              : item,
          ),
        );
        void refreshWoodenFishShelf().catch(() => undefined);
        try {
          const latest = await woodenFishClient.getSession(
            created.session.sessionId,
          );
          markDraftFailed(
            'wooden-fish',
            [latest.session.sessionId, latest.session.draft?.profileId],
            errorMessage,
          );
          setWoodenFishSession(latest.session);
          setWoodenFishWork(null);
          writeCreationUrlState(
            buildWoodenFishCreationUrlState({ session: latest.session }),
          );
        } catch {
          setWoodenFishSession(created.session);
          setWoodenFishWork(null);
          writeCreationUrlState(
            buildWoodenFishCreationUrlState({ session: created.session }),
          );
        }
      } finally {
        setIsWoodenFishBusy(false);
      }
    },
    [
      createReadyWoodenFishGenerationState,
      markDraftFailed,
      markDraftGenerating,
      markDraftReady,
      markPendingDraftFailed,
      markPendingDraftGenerating,
      markPendingDraftReady,
      refreshWoodenFishShelf,
      setSelectionStage,
    ],
  );

  const retryWoodenFishDraftGeneration = useCallback(() => {
    if (!woodenFishSession) {
      setSelectionStage('wooden-fish-workspace');
      return;
    }

    void compileWoodenFishSession({ session: woodenFishSession });
  }, [compileWoodenFishSession, setSelectionStage, woodenFishSession]);

  const regenerateWoodenFishAsset = useCallback(
    async (actionType: 'regenerate-hit-object') => {
      if (!woodenFishSession?.sessionId) {
        setSelectionStage('wooden-fish-workspace');
        return;
      }

      const generationState = createMiniGameDraftGenerationState(
        'wooden-fish',
        resolveMiniGameDraftGenerationStartedAtMs(woodenFishSession.updatedAt),
      );
      setWoodenFishError(null);
      setWoodenFishGenerationState(generationState);
      setIsWoodenFishBusy(true);
      setSelectionStage('wooden-fish-generating');
      try {
        const response = await woodenFishClient.executeAction(
          woodenFishSession.sessionId,
          {
            actionType,
            workTitle: woodenFishSession.draft?.workTitle,
            workDescription: woodenFishSession.draft?.workDescription,
            themeTags: woodenFishSession.draft?.themeTags,
            hitObjectPrompt: woodenFishSession.draft?.hitObjectPrompt,
            hitObjectReferenceImageSrc:
              woodenFishSession.draft?.hitObjectReferenceImageSrc,
            hitSoundAsset: woodenFishSession.draft?.hitSoundAsset,
            floatingWords: woodenFishSession.draft?.floatingWords,
          },
        );
        setWoodenFishSession(response.session);
        setWoodenFishWork(response.work ?? woodenFishWork);
        writeCreationUrlState(
          buildWoodenFishCreationUrlState({
            session: response.session,
            work: response.work ?? woodenFishWork,
          }),
        );
        setWoodenFishGenerationState(
          createReadyWoodenFishGenerationState(generationState),
        );
        setSelectionStage('wooden-fish-result');
      } catch (error) {
        const errorMessage = resolveRpgCreationErrorMessage(
          error,
          '重新生成敲击物图案失败。',
        );
        setWoodenFishError(errorMessage);
        setWoodenFishGenerationState(
          resolveFinishedMiniGameDraftGenerationState(
            generationState,
            'failed',
            { error: errorMessage },
          ),
        );
      } finally {
        setIsWoodenFishBusy(false);
      }
    },
    [
      createReadyWoodenFishGenerationState,
      setSelectionStage,
      woodenFishSession?.draft,
      woodenFishSession?.sessionId,
      woodenFishWork,
    ],
  );

  const updateWoodenFishWorkMeta = useCallback(
    async (payload: {
      workTitle: string;
      workDescription: string;
      themeTags: string[];
    }) => {
      const sessionId = woodenFishSession?.sessionId?.trim();
      const profileId =
        woodenFishWork?.summary.profileId?.trim() ||
        woodenFishSession?.draft?.profileId?.trim() ||
        '';
      if (!sessionId || !profileId) {
        setWoodenFishError('敲木鱼草稿尚未生成可保存作品信息。');
        setSelectionStage('wooden-fish-result');
        return false;
      }

      setIsWoodenFishBusy(true);
      setWoodenFishError(null);
      try {
        const response = await woodenFishClient.executeAction(sessionId, {
          actionType: 'update-work-meta',
          profileId,
          workTitle: payload.workTitle,
          workDescription: payload.workDescription,
          themeTags: payload.themeTags,
        });
        setWoodenFishSession(response.session);
        setWoodenFishWork(response.work ?? woodenFishWork);
        writeCreationUrlState(
          buildWoodenFishCreationUrlState({
            session: response.session,
            work: response.work ?? woodenFishWork,
          }),
        );
        return true;
      } catch (error) {
        setWoodenFishError(
          resolveRpgCreationErrorMessage(error, '保存敲木鱼作品信息失败。'),
        );
        setSelectionStage('wooden-fish-result');
        return false;
      } finally {
        setIsWoodenFishBusy(false);
      }
    },
    [
      setSelectionStage,
      woodenFishSession?.draft?.profileId,
      woodenFishSession?.sessionId,
      woodenFishWork,
    ],
  );

  const publishWoodenFishDraft = useCallback(async () => {
    const profileId = woodenFishWork?.summary.profileId?.trim();
    if (!profileId) {
      setWoodenFishError('敲木鱼草稿尚未生成可发布作品。');
      setSelectionStage('wooden-fish-result');
      return;
    }

    setIsWoodenFishBusy(true);
    setWoodenFishError(null);
    try {
      const response = await woodenFishClient.publishWork(profileId);
      setWoodenFishWork(response.item);
      void refreshWoodenFishShelf();
      void refreshWoodenFishGallery();
      openPublishShareModal({
        title: response.item.summary.workTitle || '敲木鱼',
        publicWorkCode: buildWoodenFishPublicWorkCode(
          response.item.summary.profileId,
        ),
        stage: 'work-detail',
      });
    } catch (error) {
      setWoodenFishError(
        resolveRpgCreationErrorMessage(error, '发布敲木鱼作品失败。'),
      );
      setSelectionStage('wooden-fish-result');
    } finally {
      setIsWoodenFishBusy(false);
    }
  }, [
    openPublishShareModal,
    refreshWoodenFishGallery,
    refreshWoodenFishShelf,
    setSelectionStage,
    woodenFishWork?.summary.profileId,
  ]);

  const startWoodenFishTestRunFromProfile = useCallback(async () => {
    const profileId = woodenFishWork?.summary.profileId?.trim();
    if (!profileId) {
      setWoodenFishError('敲木鱼草稿尚未生成可试玩作品。');
      setSelectionStage('wooden-fish-result');
      return;
    }

    setIsWoodenFishBusy(true);
    setWoodenFishError(null);
    setWoodenFishRuntimeReturnStage('wooden-fish-result');
    try {
      const response = await woodenFishClient.startRun(profileId);
      setWoodenFishRun(response.run);
      setSelectionStage('wooden-fish-runtime');
    } catch (error) {
      setWoodenFishError(
        error instanceof Error ? error.message : '启动敲木鱼试玩失败。',
      );
      setSelectionStage('wooden-fish-result');
    } finally {
      setIsWoodenFishBusy(false);
    }
  }, [setSelectionStage, woodenFishWork?.summary.profileId]);

  const startWoodenFishRunFromProfile = useCallback(
    async (
      profileId: string,
      options: {
        embedded?: boolean;
        returnStage?: 'work-detail' | 'platform';
      } = {},
    ) => {
      const normalizedProfileId = profileId.trim();
      if (!normalizedProfileId) {
        setWoodenFishError('当前敲木鱼作品信息不完整，暂时无法进入玩法。');
        return false;
      }

      setIsWoodenFishBusy(true);
      setWoodenFishError(null);
      setWoodenFishRuntimeReturnStage(options.returnStage ?? 'work-detail');
      try {
        const runtimeGuestOptions = await buildRecommendRuntimeAuthOptions(
          authUi,
          options.embedded,
        );
        const [detail, runResponse] = await Promise.all([
          woodenFishClient.getWorkDetail(normalizedProfileId).catch(() => null),
          options.embedded
            ? woodenFishClient.startRun(
                normalizedProfileId,
                runtimeGuestOptions,
              )
            : woodenFishClient.startRun(normalizedProfileId),
        ]);
        if (detail?.item) {
          setWoodenFishWork(detail.item);
        }
        setWoodenFishRun(runResponse.run);
        if (!options.embedded) {
          setSelectionStage('wooden-fish-runtime');
          pushAppHistoryPath(
            buildPublicWorkStagePath(
              'wooden-fish-runtime',
              buildWoodenFishPublicWorkCode(normalizedProfileId),
            ),
          );
        }
        return true;
      } catch (error) {
        setWoodenFishError(
          resolveRpgCreationErrorMessage(error, '启动敲木鱼玩法失败。'),
        );
        return false;
      } finally {
        setIsWoodenFishBusy(false);
      }
    },
    [authUi, setSelectionStage],
  );

  const checkpointWoodenFishRuntimeRun = useCallback(
    async (payload: {
      totalTapCount: number;
      wordCounters: WoodenFishRunResponse['run']['wordCounters'];
    }) => {
      const runId = woodenFishRun?.runId;
      if (!runId) {
        return;
      }
      const response = await woodenFishClient.checkpointRun(runId, payload);
      setWoodenFishRun(response.run);
    },
    [woodenFishRun?.runId],
  );

  const executePuzzleAction = puzzleFlow.executeAction;

  const executePuzzleBackgroundAction = useCallback(
    async (payload: PuzzleAgentActionRequest) => {
      const targetSession = puzzleSession;
      if (!targetSession) {
        return;
      }

      const formPayload = buildPuzzleFormPayloadFromAction(payload);
      if (formPayload) {
        setPuzzleFormDraftPayload(formPayload);
      }

      setPuzzleError(null);
      try {
        const response = await executePuzzleAgentAction(
          targetSession.sessionId,
          payload,
        );
        setPuzzleOperation(response.operation);
        puzzleFlow.setSession(response.session);
      } catch (error) {
        setPuzzleError(resolvePuzzleErrorMessage(error, '执行拼图操作失败。'));
      } finally {
        if (
          payload.action === 'generate_puzzle_images' ||
          payload.action === 'generate_puzzle_ui_background'
        ) {
          refreshPlatformDashboardSilently();
        }
      }
    },
    [
      puzzleFlow,
      puzzleSession,
      refreshPlatformDashboardSilently,
      resolvePuzzleErrorMessage,
      setPuzzleError,
    ],
  );

  const retryPuzzleDraftGeneration = useCallback(() => {
    if (puzzleFormDraftPayload) {
      void createPuzzleDraftFromForm(puzzleFormDraftPayload);
      return;
    }

    void executePuzzleAction(
      buildPuzzleCompileActionFromFormPayload(puzzleFormDraftPayload),
    );
  }, [createPuzzleDraftFromForm, executePuzzleAction, puzzleFormDraftPayload]);

  const retryVisualNovelDraftGeneration = useCallback(() => {
    if (!visualNovelFormDraftPayload) {
      setSelectionStage('visual-novel-agent-workspace');
      return;
    }

    void createVisualNovelDraftFromForm(visualNovelFormDraftPayload);
  }, [
    createVisualNovelDraftFromForm,
    setSelectionStage,
    visualNovelFormDraftPayload,
  ]);

  const retryBabyObjectMatchDraftGeneration = useCallback(() => {
    if (!babyObjectMatchFormPayload) {
      setSelectionStage('baby-object-match-workspace');
      return;
    }

    void createBabyObjectMatchDraftFromForm(babyObjectMatchFormPayload);
  }, [
    babyObjectMatchFormPayload,
    createBabyObjectMatchDraftFromForm,
    setSelectionStage,
  ]);

  const executePuzzleWorkspaceAction = useCallback(
    (payload: PuzzleAgentActionRequest) => {
      if (
        payload.action === 'compile_puzzle_draft' &&
        isEmptyPuzzleFormOnlyDraft(puzzleSession)
      ) {
        const formPayload = buildPuzzleFormPayloadFromAction(payload);
        if (formPayload) {
          void createPuzzleDraftFromForm(formPayload);
          return;
        }
      }

      if (
        payload.action === 'generate_puzzle_images' ||
        payload.action === 'generate_puzzle_ui_background'
      ) {
        void executePuzzleBackgroundAction(payload);
        return;
      }

      void executePuzzleAction(payload);
    },
    [
      createPuzzleDraftFromForm,
      executePuzzleAction,
      executePuzzleBackgroundAction,
      puzzleSession,
    ],
  );

  const openCreativeAgentTarget = useCallback(async () => {
    const binding = creativeAgentSession?.targetBinding;
    if (!binding || isPuzzleBusy) {
      return;
    }

    setIsPuzzleBusy(true);
    setPuzzleError(null);
    try {
      const response = await getPuzzleAgentSession(binding.targetSessionId);
      puzzleFlow.setSession(response.session);
      setPuzzleOperation(null);
      setPuzzleRun(null);
      setPuzzleRuntimeAuthMode('default');
      enterCreateTab();
      setActiveCreativeAgentSessionId(creativeAgentSession.sessionId);
      setCreativeDraftEditError(null);
      setSelectionStage(
        resolveCreativeAgentTargetSelectionStage(binding.targetStage),
      );
    } catch (error) {
      setCreativeAgentError(
        resolvePuzzleErrorMessage(error, '打开拼图草稿失败。'),
      );
    } finally {
      setIsPuzzleBusy(false);
    }
  }, [
    creativeAgentSession,
    enterCreateTab,
    isPuzzleBusy,
    puzzleFlow,
    resolvePuzzleErrorMessage,
    setIsPuzzleBusy,
    setPuzzleError,
    setSelectionStage,
  ]);

  const submitCreativeDraftEdit = useCallback(
    async ({
      instruction,
      currentDraft,
    }: {
      instruction: string;
      currentDraft: PuzzleResultDraft;
    }): Promise<CreativeDraftEditResult | null> => {
      const creativeSessionId =
        activeCreativeAgentSessionId ?? creativeAgentSession?.sessionId ?? null;
      const targetPuzzleSessionId = puzzleSession?.sessionId?.trim();
      if (
        !creativeSessionId ||
        !targetPuzzleSessionId ||
        isCreativeDraftEditBusy
      ) {
        return null;
      }

      setIsCreativeDraftEditBusy(true);
      setCreativeDraftEditError(null);
      try {
        const result = await streamCreativeDraftEdit(creativeSessionId, {
          clientMessageId: `creative-edit-${Date.now().toString(36)}`,
          instruction,
          targetPuzzleSessionId,
          currentDraft,
        });

        if ('puzzleSession' in result) {
          puzzleFlow.setSession(result.puzzleSession);
          setCreativeAgentSession(result.session);
          setActiveCreativeAgentSessionId(result.session.sessionId);
          return result;
        }

        setCreativeAgentSession(result);
        setActiveCreativeAgentSessionId(result.sessionId);
        const response = await getPuzzleAgentSession(targetPuzzleSessionId);
        puzzleFlow.setSession(response.session);
        return null;
      } catch (error) {
        setCreativeDraftEditError(
          resolvePuzzleErrorMessage(error, '智能修订拼图草稿失败。'),
        );
        return null;
      } finally {
        setIsCreativeDraftEditBusy(false);
      }
    },
    [
      activeCreativeAgentSessionId,
      creativeAgentSession?.sessionId,
      isCreativeDraftEditBusy,
      puzzleFlow,
      puzzleSession?.sessionId,
      resolvePuzzleErrorMessage,
    ],
  );

  useEffect(() => {
    const nextSelectionStage = resolveSelectionStageAfterMissingCreationState({
      stage: selectionStage,
      bigFish: {
        hasSession: Boolean(bigFishSession),
        hasSessionDraft: Boolean(bigFishSession?.draft),
        hasRun: Boolean(bigFishRun),
      },
      match3d: {
        hasSession: Boolean(match3dSession),
        hasSessionDraft: Boolean(match3dSession?.draft),
        hasRun: Boolean(match3dRun),
      },
      squareHole: {
        hasSession: Boolean(squareHoleSession),
        hasSessionDraft: Boolean(squareHoleSession?.draft),
        hasRun: Boolean(squareHoleRun),
      },
      visualNovel: {
        hasSession: Boolean(visualNovelSession),
        hasSessionDraft: Boolean(visualNovelSession?.draft),
        hasWork: Boolean(visualNovelWork),
        hasWorkDraft: Boolean(visualNovelWork?.draft),
        hasRun: Boolean(visualNovelRun),
      },
      babyObjectMatch: {
        hasDraft: Boolean(babyObjectMatchDraft),
        hasFormPayload: Boolean(babyObjectMatchFormPayload),
      },
    });

    if (nextSelectionStage !== selectionStage) {
      setSelectionStage(nextSelectionStage);
    }
  }, [
    babyObjectMatchDraft,
    babyObjectMatchFormPayload,
    bigFishRun,
    bigFishSession,
    match3dRun,
    match3dSession,
    selectionStage,
    setSelectionStage,
    squareHoleRun,
    squareHoleSession,
    visualNovelRun,
    visualNovelSession,
    visualNovelWork,
  ]);

  const startBigFishRun = useCallback(async () => {
    if (!bigFishSession) {
      return;
    }

    const sessionId = bigFishSession.sessionId;
    setBigFishError(null);
    setBigFishRuntimeShare(null);
    setBigFishRuntimeWork(null);
    setBigFishRuntimeStartedAt(null);
    setBigFishRun(null);
    try {
      const { run } = await startBigFishRuntimeRun(sessionId);
      setBigFishRuntimeStartedAt(Date.now());
      setBigFishRuntimeSessionSource('draft');
      setBigFishRuntimeReturnStage('big-fish-result');
      setBigFishRun(run);
      setSelectionStage('big-fish-runtime');
      void recordBigFishPlay(sessionId, { elapsedMs: 0 }).catch((error) => {
        setBigFishError(
          resolveBigFishErrorMessage(error, '记录大鱼吃小鱼游玩失败。'),
        );
      });
      void refreshBigFishShelf();
    } catch (error) {
      setBigFishError(
        resolveBigFishErrorMessage(error, '启动大鱼吃小鱼玩法失败。'),
      );
    }
  }, [
    bigFishSession,
    refreshBigFishShelf,
    resolveBigFishErrorMessage,
    setBigFishError,
    setSelectionStage,
  ]);

  const restartBigFishRun = useCallback(async () => {
    if (!bigFishSession && !bigFishRun) {
      return;
    }

    const sessionId = bigFishSession?.sessionId ?? bigFishRun?.sessionId;
    if (!sessionId) {
      return;
    }

    setBigFishError(null);
    if (bigFishSession) {
      setBigFishRuntimeShare(null);
      setBigFishRuntimeReturnStage('big-fish-result');
    }
    setBigFishRuntimeStartedAt(null);
    setBigFishRun(null);
    try {
      const { run } = await startBigFishRuntimeRun(sessionId);
      setBigFishRuntimeStartedAt(Date.now());
      setBigFishRuntimeSessionSource(bigFishSession ? 'draft' : 'work');
      setBigFishRuntimeReturnStage(
        bigFishSession ? 'big-fish-result' : bigFishRuntimeReturnStage,
      );
      setBigFishRun(run);
      setSelectionStage('big-fish-runtime');
      void recordBigFishPlay(sessionId, { elapsedMs: 0 }).catch((error) => {
        setBigFishError(
          resolveBigFishErrorMessage(error, '记录大鱼吃小鱼游玩失败。'),
        );
      });
    } catch (error) {
      setBigFishError(
        resolveBigFishErrorMessage(error, '启动大鱼吃小鱼玩法失败。'),
      );
    }
  }, [
    bigFishRun,
    bigFishRuntimeReturnStage,
    bigFishSession,
    resolveBigFishErrorMessage,
    setBigFishError,
    setSelectionStage,
  ]);

  const startPuzzleRunFromProfile = useCallback(
    async (
      profileId: string,
      returnStage: PuzzleRuntimeReturnStage = 'work-detail',
      detailItem?: PuzzleWorkSummary,
      mirrorErrorToPublicDetail = false,
      levelId?: string | null,
      options: { embedded?: boolean; authMode?: PuzzleRuntimeAuthMode } = {},
    ) => {
      const normalizedLevelId = levelId?.trim() ?? '';
      const startKey = `${profileId}:${normalizedLevelId}`;
      if (isPuzzleBusy || puzzleStartInFlightKeyRef.current === startKey) {
        return false;
      }

      puzzleStartInFlightKeyRef.current = startKey;
      setIsPuzzleBusy(true);
      setPuzzleError(null);

      try {
        const item =
          detailItem ?? (await getPuzzleGalleryDetail(profileId)).item;
        const startRunPayload = {
          profileId: item.profileId,
          levelId: normalizedLevelId || null,
        };
        const authPlan = resolveCurrentRecommendRuntimeAuthPlan(authUi, {
          embedded: options.embedded,
          allowRuntimeGuestAuth:
            options.embedded || options.authMode === 'isolated',
        });
        const runtimeGuestOptions =
          authPlan.requestKind === 'runtime-guest'
            ? await buildRecommendRuntimeGuestOptions()
            : {};
        const authMode = authPlan.puzzleRuntimeAuthMode;
        const runtimeAuthOptions =
          authPlan.requestKind === 'runtime-guest'
            ? runtimeGuestOptions
            : authPlan.requestKind === 'background'
              ? RECOMMEND_PUZZLE_BACKGROUND_AUTH_OPTIONS
              : {};
        const { run } =
          authMode === 'isolated'
            ? await startPuzzleRun(startRunPayload, runtimeGuestOptions)
            : await startPuzzleRun(startRunPayload, runtimeAuthOptions);
        setSelectedPuzzleDetail(item);
        setPuzzleRun(run);
        setPuzzleRuntimeAuthMode(authMode);
        setPuzzleRuntimeReturnStage(returnStage);
        if (!options.embedded) {
          openPuzzleRuntimeStage(
            setSelectionStage,
            authMode === 'isolated'
              ? buildPuzzlePublishedRuntimeUrlState(item, levelId)
              : buildPuzzleDraftRuntimeUrlState(item, levelId),
          );
        }
        return true;
      } catch (error) {
        if (isMissingPuzzleWorkError(error)) {
          setSelectedPuzzleDetail(null);
          setPuzzleDetailReturnTarget(null);
          setPuzzleRun(null);
          setPuzzleRuntimeAuthMode('default');
          setPuzzleGalleryEntries((current) =>
            current.filter((entry) => entry.profileId !== profileId),
          );
          setPuzzleError(null);
          setPublicWorkDetailError(null);
          returnPlatformHomeAfterMissingWork();
          return false;
        }

        const message = resolvePuzzleErrorMessage(error, '启动拼图玩法失败。');
        setPuzzleError(message);
        if (mirrorErrorToPublicDetail) {
          setPublicWorkDetailError(message);
        }
        return false;
      } finally {
        if (puzzleStartInFlightKeyRef.current === startKey) {
          puzzleStartInFlightKeyRef.current = null;
        }
        setIsPuzzleBusy(false);
      }
    },
    [
      isPuzzleBusy,
      authUi,
      resolvePuzzleErrorMessage,
      returnPlatformHomeAfterMissingWork,
      setIsPuzzleBusy,
      setPuzzleError,
      setSelectionStage,
    ],
  );

  const startMatch3DRunFromProfile = useCallback(
    async (
      profile: Match3DWorkProfile | Match3DWorkSummary,
      returnStage: 'match3d-result' | 'work-detail' = 'match3d-result',
      mirrorErrorToPublicDetail = false,
      options: { embedded?: boolean; itemTypeCountOverride?: number } = {},
    ) => {
      if (isMatch3DBusy) {
        return false;
      }

      match3dFlow.setIsBusy(true);
      setMatch3DError(null);

      try {
        let runtimeProfile: Match3DWorkProfile | Match3DWorkSummary = profile;
        if (
          !hasMatch3DRuntimeAsset(profile.generatedItemAssets) ||
          !hasMatch3DRuntimeBackgroundAsset(profile)
        ) {
          try {
            const { item } = await getMatch3DWorkDetail(profile.profileId);
            runtimeProfile = normalizeMatch3DWorkForRuntimeUi({
              ...item,
              generatedItemAssets: mergeMatch3DGeneratedItemAssetsForRuntime(
                item.generatedItemAssets,
                profile.generatedItemAssets,
              ),
            });
          } catch {
            // 中文注释：详情补读只为拿完整生成素材；失败时继续按摘要开局，避免推荐流卡死。
          }
        }
        runtimeProfile = promoteMatch3DGeneratedBackgroundAsset({
          ...runtimeProfile,
          generatedItemAssets: normalizeMatch3DGeneratedItemAssetsForRuntime(
            runtimeProfile.generatedItemAssets,
          ),
        });
        await preloadMatch3DGeneratedRuntimeAssets(
          runtimeProfile.generatedItemAssets,
          runtimeProfile.generatedBackgroundAsset,
          { expireSeconds: 300 },
        );
        const runtimeGuestOptions = await buildRecommendRuntimeAuthOptions(
          authUi,
          options.embedded,
        );
        const runtimeOptions = {
          ...runtimeGuestOptions,
          ...(typeof options.itemTypeCountOverride === 'number'
            ? { itemTypeCountOverride: options.itemTypeCountOverride }
            : {}),
        };
        const activeRuntimeAdapter = resolveMatch3DRuntimeAdapter(
          runtimeProfile.profileId,
        );
        const { run } = await activeRuntimeAdapter.startRun(
          runtimeProfile.profileId,
          runtimeOptions,
        );
        // 中文注释：运行态必须锁定本次启动时的完整 profile，避免首次切屏渲染读到旧草稿 state。
        setMatch3DRuntimeProfile(runtimeProfile);
        setMatch3DRun(run);
        setMatch3DProfile(runtimeProfile);
        setMatch3DRuntimeReturnStage(returnStage);
        if (!options.embedded) {
          setSelectionStage('match3d-runtime');
        }
        if (
          !options.embedded &&
          runtimeProfile.publicationStatus === 'published'
        ) {
          pushAppHistoryPath(
            buildPublicWorkStagePath(
              'work-detail',
              buildMatch3DPublicWorkCode(runtimeProfile.profileId),
            ),
          );
        }
        return true;
      } catch (error) {
        const message = resolveMatch3DErrorMessage(
          error,
          '启动抓大鹅玩法失败。',
        );
        setMatch3DError(message);
        if (mirrorErrorToPublicDetail) {
          setPublicWorkDetailError(message);
        }
        return false;
      } finally {
        match3dFlow.setIsBusy(false);
      }
    },
    [
      isMatch3DBusy,
      authUi,
      match3dFlow,
      resolveMatch3DErrorMessage,
      resolveMatch3DRuntimeAdapter,
      setMatch3DError,
      setSelectionStage,
    ],
  );

  const startSquareHoleRunFromProfile = useCallback(
    async (
      profile: SquareHoleWorkProfile | SquareHoleWorkSummary,
      returnStage: SquareHoleRuntimeReturnStage = 'square-hole-result',
      mirrorErrorToPublicDetail = false,
      options: { embedded?: boolean } = {},
    ) => {
      if (isSquareHoleBusy) {
        return false;
      }

      squareHoleFlow.setIsBusy(true);
      setSquareHoleError(null);

      try {
        const runtimeGuestOptions = await buildRecommendRuntimeAuthOptions(
          authUi,
          options.embedded,
        );
        const { run } = options.embedded
          ? await startSquareHoleRun(profile.profileId, runtimeGuestOptions)
          : await startSquareHoleRun(profile.profileId);
        setSquareHoleRun(run);
        setSquareHoleRuntimeReturnStage(returnStage);
        if (!options.embedded) {
          setSelectionStage('square-hole-runtime');
        }
        if (!options.embedded && profile.publicationStatus === 'published') {
          pushAppHistoryPath(
            buildPublicWorkStagePath(
              'work-detail',
              buildSquareHolePublicWorkCode(profile.profileId),
            ),
          );
        }
        return true;
      } catch (error) {
        const message = resolveSquareHoleErrorMessage(
          error,
          '启动方洞挑战玩法失败。',
        );
        setSquareHoleError(message);
        if (mirrorErrorToPublicDetail) {
          setPublicWorkDetailError(message);
        }
        return false;
      } finally {
        squareHoleFlow.setIsBusy(false);
      }
    },
    [
      isSquareHoleBusy,
      authUi,
      resolveSquareHoleErrorMessage,
      setSelectionStage,
      setSquareHoleError,
      squareHoleFlow,
    ],
  );

  const _buildPuzzleTestWork = useCallback(
    (draft: PuzzleResultDraft) => {
      const profileId =
        puzzleSession?.publishedProfileId ??
        `draft-${puzzleSession?.sessionId ?? 'puzzle'}-test`;
      const now = new Date().toISOString();

      return {
        workId: `test-${profileId}`,
        profileId,
        ownerUserId: authUi?.user?.id ?? 'current-user',
        sourceSessionId: puzzleSession?.sessionId ?? null,
        authorDisplayName: authUi?.user?.displayName ?? '玩家',
        workTitle: draft.workTitle || draft.levelName,
        workDescription: draft.workDescription || draft.summary,
        levelName: draft.levelName,
        summary: draft.summary,
        themeTags: draft.themeTags,
        coverImageSrc: draft.coverImageSrc,
        coverAssetId: draft.coverAssetId,
        publicationStatus: 'draft',
        updatedAt: now,
        publishedAt: null,
        playCount: 0,
        remixCount: 0,
        likeCount: 0,
        pointIncentiveTotalHalfPoints: 0,
        pointIncentiveClaimedPoints: 0,
        pointIncentiveTotalPoints: 0,
        pointIncentiveClaimablePoints: 0,
        publishReady: Boolean(puzzleSession?.resultPreview?.publishReady),
        levels: draft.levels,
      } satisfies PuzzleWorkSummary;
    },
    [
      authUi?.user?.displayName,
      authUi?.user?.id,
      puzzleSession?.publishedProfileId,
      puzzleSession?.resultPreview?.publishReady,
      puzzleSession?.sessionId,
    ],
  );

  const startPuzzleTestRunFromDraft = useCallback(
    async (
      draft: PuzzleResultDraft,
      options: { levelId?: string | null } = {},
    ) => {
      if (isPuzzleBusy) {
        return false;
      }
      if (!draft.coverImageSrc) {
        setPuzzleError('请先选择一张正式拼图图片。');
        return false;
      }
      const profileId =
        puzzleSession?.publishedProfileId ??
        buildPuzzleResultProfileId(puzzleSession?.sessionId);
      if (!profileId) {
        setPuzzleError('这份拼图草稿缺少会话信息，请重新开始创作。');
        return false;
      }

      setIsPuzzleBusy(true);
      setPuzzleError(null);
      try {
        const { item } = await updatePuzzleWork(
          profileId,
          buildPuzzleWorkUpdatePayloadFromDraft(draft),
        );
        const run = startLocalPuzzleRun(item, options.levelId ?? null);
        setSelectedPuzzleDetail(item);
        setPuzzleRun(run);
        setPuzzleRuntimeAuthMode('default');
        setPuzzleRuntimeReturnStage('puzzle-result');
        openPuzzleRuntimeStage(
          setSelectionStage,
          buildPuzzleDraftRuntimeUrlState(item, options.levelId ?? null),
        );
        return true;
      } catch (error) {
        setPuzzleError(resolvePuzzleErrorMessage(error, '启动拼图试玩失败。'));
        return false;
      } finally {
        setIsPuzzleBusy(false);
      }
    },
    [
      isPuzzleBusy,
      puzzleSession?.publishedProfileId,
      puzzleSession?.sessionId,
      resolvePuzzleErrorMessage,
      setIsPuzzleBusy,
      setPuzzleError,
      setSelectionStage,
    ],
  );

  const submitBigFishInput = useCallback(
    async (payload: SubmitBigFishInputRequest) => {
      if (
        !bigFishRun ||
        bigFishRun.status !== 'running' ||
        bigFishInputInFlightRef.current
      ) {
        return;
      }

      bigFishInputInFlightRef.current = true;
      try {
        const runtimeGuestOptions =
          activeRecommendRuntimeKind === 'big-fish'
            ? await buildRecommendRuntimeAuthOptions(authUi, true)
            : {};
        const { run } = await submitBigFishRuntimeInput(
          bigFishRun.runId,
          payload,
          runtimeGuestOptions,
        );
        setBigFishRun(run);
      } catch (error) {
        setBigFishError(
          resolveBigFishErrorMessage(error, '同步大鱼吃小鱼输入失败。'),
        );
      } finally {
        bigFishInputInFlightRef.current = false;
      }
    },
    [
      activeRecommendRuntimeKind,
      authUi,
      bigFishRun,
      resolveBigFishErrorMessage,
      setBigFishError,
    ],
  );

  const reportBigFishObservedPlayTime = useCallback(() => {
    const sessionId = bigFishRun?.sessionId?.trim();
    if (!sessionId || !bigFishRuntimeStartedAt) {
      return;
    }

    const elapsedMs = Math.max(1_000, Date.now() - bigFishRuntimeStartedAt);
    setBigFishRuntimeStartedAt(null);
    const reportPromise =
      activeRecommendRuntimeKind === 'big-fish'
        ? buildRecommendRuntimeAuthOptions(authUi, true).then(
            (runtimeAuthOptions) =>
              recordBigFishPlay(sessionId, { elapsedMs }, runtimeAuthOptions),
          )
        : recordBigFishPlay(sessionId, { elapsedMs });
    void reportPromise.catch((error) => {
      setBigFishError(
        resolveBigFishErrorMessage(error, '记录大鱼吃小鱼游玩时长失败。'),
      );
    });
  }, [
    activeRecommendRuntimeKind,
    authUi,
    bigFishRun?.sessionId,
    bigFishRuntimeStartedAt,
    resolveBigFishErrorMessage,
    setBigFishError,
  ]);

  const swapPuzzlePiecesInRun = useCallback(
    async (payload: { firstPieceId: string; secondPieceId: string }) => {
      if (!puzzleRun || isPuzzleBusy) {
        return;
      }

      setIsPuzzleBusy(true);
      setPuzzleError(null);
      try {
        setPuzzleRun(
          swapLocalPuzzlePieces(
            puzzleRun,
            payload,
            isLocalPuzzleRun(puzzleRun) ? selectedPuzzleDetail : null,
          ),
        );
      } catch (error) {
        setPuzzleError(resolvePuzzleErrorMessage(error, '交换拼图块失败。'));
      } finally {
        setIsPuzzleBusy(false);
      }
    },
    [
      isPuzzleBusy,
      puzzleRun,
      resolvePuzzleErrorMessage,
      selectedPuzzleDetail,
      setIsPuzzleBusy,
      setPuzzleError,
    ],
  );

  const dragPuzzlePiece = useCallback(
    async (payload: {
      pieceId: string;
      targetRow: number;
      targetCol: number;
    }) => {
      if (!puzzleRun || isPuzzleBusy) {
        return;
      }

      setIsPuzzleBusy(true);
      setPuzzleError(null);
      try {
        setPuzzleRun(
          dragLocalPuzzlePiece(
            puzzleRun,
            payload,
            isLocalPuzzleRun(puzzleRun) ? selectedPuzzleDetail : null,
          ),
        );
      } catch (error) {
        setPuzzleError(resolvePuzzleErrorMessage(error, '拖动拼图块失败。'));
      } finally {
        setIsPuzzleBusy(false);
      }
    },
    [
      isPuzzleBusy,
      puzzleRun,
      resolvePuzzleErrorMessage,
      selectedPuzzleDetail,
      setIsPuzzleBusy,
      setPuzzleError,
    ],
  );

  useEffect(() => {
    if (selectionStage !== 'puzzle-runtime' || !puzzleRun?.currentLevel) {
      return;
    }
    if (puzzleRun.currentLevel.status !== 'playing') {
      return;
    }

    const timerId = window.setInterval(() => {
      // 中文注释：拼图运行态的棋盘交互和倒计时展示都在前端即时裁决，超时后只刷新本地失败态。
      setPuzzleRun((currentRun) =>
        currentRun ? refreshLocalPuzzleTimer(currentRun) : currentRun,
      );
    }, 250);

    return () => window.clearInterval(timerId);
  }, [puzzleRun, selectionStage]);

  useEffect(() => {
    if (selectionStage !== 'puzzle-runtime' || puzzleRun) {
      return;
    }
    if (!hasPuzzleRuntimeUrlStateValue(initialPuzzleRuntimeUrlState)) {
      return;
    }
    const runtimeUrlStateKey = buildPuzzleRuntimeUrlStateKey(
      initialPuzzleRuntimeUrlState,
    );
    if (
      handledPuzzleRuntimeUrlStateKeyRef.current === runtimeUrlStateKey ||
      isPuzzleBusy
    ) {
      return;
    }

    handledPuzzleRuntimeUrlStateKeyRef.current = runtimeUrlStateKey;
    let cancelled = false;

    const restorePuzzleRuntime = async () => {
      const runtimeProfileId = normalizeCreationUrlValue(
        initialPuzzleRuntimeUrlState.runtimeProfileId,
      );
      const runtimeSessionId = normalizeCreationUrlValue(
        initialPuzzleRuntimeUrlState.runtimeSessionId,
      );
      const runtimeLevelId = normalizeCreationUrlValue(
        initialPuzzleRuntimeUrlState.runtimeLevelId,
      );
      const publicWorkCode = normalizeCreationUrlValue(
        initialPuzzleRuntimeUrlState.publicWorkCode,
      );
      const runtimeMode = initialPuzzleRuntimeUrlState.mode ?? null;
      const isPublishedRuntime = runtimeMode === 'published';
      if (
        !isPublishedRuntime &&
        (platformBootstrap.isLoadingPlatform ||
          !platformBootstrap.canReadProtectedData)
      ) {
        handledPuzzleRuntimeUrlStateKeyRef.current = null;
        return;
      }
      const fallbackStage: PuzzleRuntimeReturnStage =
        runtimeMode === 'published' ? 'work-detail' : 'puzzle-result';

      const candidateItems = isPublishedRuntime
        ? puzzleGalleryEntries.length > 0
          ? puzzleGalleryEntries
          : await refreshPuzzleGallery()
        : puzzleWorks.length > 0
          ? puzzleWorks
          : (await listPuzzleWorks().catch(() => ({ items: [] }))).items;
      const targetItem =
        runtimeProfileId || runtimeSessionId || publicWorkCode
          ? (candidateItems.find(
              (item) =>
                item.profileId === runtimeProfileId ||
                item.sourceSessionId === runtimeSessionId ||
                (publicWorkCode
                  ? isSamePuzzlePublicWorkCode(publicWorkCode, item.profileId)
                  : false),
            ) ?? null)
          : null;

      if (!targetItem) {
        if (runtimeSessionId) {
          try {
            const { session } = await getPuzzleAgentSession(runtimeSessionId);
            const restoredWork = buildPuzzleRuntimeWorkFromSession(session, {
              userId: authUi?.user?.id ?? 'current-user',
              displayName: authUi?.user?.displayName ?? '玩家',
            });
            if (restoredWork && !cancelled) {
              setSelectedPuzzleDetail(restoredWork);
              setPuzzleRun(
                startLocalPuzzleRun(restoredWork, runtimeLevelId ?? null),
              );
              setPuzzleRuntimeAuthMode('default');
              setPuzzleRuntimeReturnStage(fallbackStage);
              openPuzzleRuntimeStage(
                setSelectionStage,
                buildPuzzleDraftRuntimeUrlState(restoredWork, runtimeLevelId),
              );
              return;
            }
          } catch {
            // 读不到草稿时继续回退到平台页，避免卡在空运行态。
          }
        }

        if (!cancelled) {
          setPuzzleError(
            runtimeMode === 'published'
              ? '这份拼图运行态缺少可恢复作品，请返回作品详情重新进入。'
              : '这份拼图试玩缺少可恢复草稿，请返回结果页重新进入。',
          );
          setPuzzleRuntimeAuthMode('default');
          setPuzzleRun(null);
          setSelectionStage('platform');
          pushAppHistoryPath('/');
        }
        return;
      }

      if (cancelled) {
        return;
      }

      setSelectedPuzzleDetail(targetItem);
      setPuzzleRun(startLocalPuzzleRun(targetItem, runtimeLevelId ?? null));
      setPuzzleRuntimeAuthMode(isPublishedRuntime ? 'isolated' : 'default');
      setPuzzleRuntimeReturnStage(fallbackStage);
      openPuzzleRuntimeStage(
        setSelectionStage,
        isPublishedRuntime
          ? buildPuzzlePublishedRuntimeUrlState(targetItem, runtimeLevelId)
          : buildPuzzleDraftRuntimeUrlState(targetItem, runtimeLevelId),
      );
    };

    void restorePuzzleRuntime();

    return () => {
      cancelled = true;
    };
  }, [
    authUi?.user?.displayName,
    authUi?.user?.id,
    initialPuzzleRuntimeUrlState,
    isPuzzleBusy,
    platformBootstrap.canReadProtectedData,
    platformBootstrap.isLoadingPlatform,
    puzzleGalleryEntries,
    puzzleRun,
    puzzleRuntimeReturnStage,
    puzzleWorks,
    refreshPuzzleGallery,
    selectionStage,
    setSelectionStage,
  ]);

  const setPuzzleRuntimePaused = useCallback(
    async (paused: boolean) => {
      if (!puzzleRun?.currentLevel) {
        return;
      }

      setPuzzleRun((currentRun) =>
        currentRun ? setLocalPuzzlePaused(currentRun, paused) : currentRun,
      );
    },
    [puzzleRun],
  );

  const syncPuzzleRuntimeTimeout = useCallback(async () => {
    if (
      !puzzleRun?.currentLevel ||
      puzzleRun.currentLevel.status === 'cleared'
    ) {
      return;
    }

    setPuzzleRun((currentRun) =>
      currentRun ? refreshLocalPuzzleTimer(currentRun) : currentRun,
    );
  }, [puzzleRun]);

  const usePuzzleProp = useCallback(
    async (propKind: PuzzleRuntimePropKind) => {
      if (!puzzleRun?.currentLevel) {
        return null;
      }
      const canUseProp =
        propKind === 'extendTime'
          ? puzzleRun.currentLevel.status !== 'cleared'
          : puzzleRun.currentLevel.status === 'playing';
      if (!canUseProp) {
        return null;
      }

      const currentRun = puzzleRunRef.current ?? puzzleRun;
      if (!currentRun.currentLevel) {
        return null;
      }
      const nextRun =
        propKind === 'extendTime'
          ? extendLocalPuzzleTime(currentRun)
          : propKind === 'freezeTime'
            ? applyLocalPuzzleFreezeTime(currentRun)
            : setLocalPuzzlePaused(currentRun, propKind === 'reference');
      puzzleRunRef.current = nextRun;
      setPuzzleRun(nextRun);
      return nextRun;
    },
    [puzzleRun],
  );

  const restartPuzzleCurrentLevel = useCallback(async () => {
    const currentRun = puzzleRunRef.current ?? puzzleRun;
    const currentLevel = currentRun?.currentLevel ?? null;
    if (!currentRun || !currentLevel || isPuzzleBusy) {
      return;
    }

    setPuzzleError(null);
    setIsPuzzleBusy(true);
    try {
      if (isLocalPuzzleRun(currentRun)) {
        const nextRun = restartLocalPuzzleLevel(currentRun);
        puzzleRunRef.current = nextRun;
        setPuzzleRun(nextRun);
        return;
      }

      const detailItem =
        selectedPuzzleDetail?.profileId === currentLevel.profileId
          ? selectedPuzzleDetail
          : await getPuzzleGalleryDetail(currentLevel.profileId).then(
              (response) => response.item,
            );
      const startRunPayload = {
        profileId: currentLevel.profileId,
        levelId: resolvePuzzleRestartLevelId(currentRun, detailItem),
      };
      const runtimeGuestOptions =
        puzzleRuntimeAuthMode === 'isolated'
          ? await buildRecommendRuntimeGuestOptions()
          : {};
      const { run } =
        puzzleRuntimeAuthMode === 'isolated'
          ? await startPuzzleRun(startRunPayload, runtimeGuestOptions)
          : await startPuzzleRun(startRunPayload);
      setSelectedPuzzleDetail(detailItem);
      puzzleRunRef.current = run;
      setPuzzleRun(run);
    } catch (error) {
      setPuzzleError(
        resolvePuzzleErrorMessage(error, '重新开始拼图关卡失败。'),
      );
    } finally {
      setIsPuzzleBusy(false);
    }
  }, [
    isPuzzleBusy,
    puzzleRun,
    puzzleRuntimeAuthMode,
    resolvePuzzleErrorMessage,
    selectedPuzzleDetail,
    setIsPuzzleBusy,
    setPuzzleError,
  ]);

  const resumePuzzleSaveArchive = useCallback(
    async (entry: ProfileSaveArchiveSummary) => {
      if (isPuzzleBusy) {
        return;
      }

      setIsPuzzleBusy(true);
      setPuzzleError(null);
      platformBootstrap.setSaveError(null);

      try {
        const resumedArchive = await resumePuzzleProfileSaveArchiveRaw(
          entry.worldKey,
        );
        platformBootstrap.setSaveEntries((currentEntries) =>
          currentEntries.map((currentEntry) =>
            currentEntry.worldKey === resumedArchive.entry.worldKey
              ? resumedArchive.entry
              : currentEntry,
          ),
        );
        const gameState = resumedArchive.snapshot.gameState;
        const profileId =
          typeof gameState.currentProfileId === 'string' &&
          gameState.currentProfileId.trim()
            ? gameState.currentProfileId
            : typeof gameState.entryProfileId === 'string' &&
                gameState.entryProfileId.trim()
              ? gameState.entryProfileId
              : (entry.profileId ?? entry.worldKey.replace(/^puzzle:/u, ''));
        const levelId =
          typeof gameState.currentLevelId === 'string' &&
          gameState.currentLevelId.trim()
            ? gameState.currentLevelId
            : null;
        const item =
          selectedPuzzleDetail?.profileId === profileId
            ? selectedPuzzleDetail
            : await getPuzzleGalleryDetail(profileId).then(
                (response) => response.item,
              );
        await startPuzzleRunFromProfile(
          item.profileId,
          'platform',
          item,
          false,
          levelId,
        );
      } catch (error) {
        platformBootstrap.setSaveError(
          resolvePuzzleErrorMessage(error, '恢复拼图存档失败。'),
        );
      } finally {
        setIsPuzzleBusy(false);
      }
    },
    [
      isPuzzleBusy,
      platformBootstrap,
      selectedPuzzleDetail,
      resolvePuzzleErrorMessage,
      setIsPuzzleBusy,
      setPuzzleError,
      startPuzzleRunFromProfile,
    ],
  );

  useEffect(() => {
    const currentLevel = puzzleRun?.currentLevel ?? null;
    if (!puzzleRun || !currentLevel || currentLevel.status !== 'cleared') {
      return;
    }
    if (currentLevel.elapsedMs === null) {
      return;
    }
    if ((currentLevel.leaderboardEntries ?? []).length > 0) {
      return;
    }

    const submitKey = [
      puzzleRun.runId,
      currentLevel.profileId,
      currentLevel.levelId ?? currentLevel.levelIndex,
      currentLevel.gridSize,
      currentLevel.elapsedMs,
    ].join(':');
    if (submittedPuzzleLeaderboardKeysRef.current.has(submitKey)) {
      return;
    }
    submittedPuzzleLeaderboardKeysRef.current.add(submitKey);
    setIsPuzzleLeaderboardBusy(true);

    const payload: SubmitPuzzleLeaderboardRequest = {
      profileId: currentLevel.profileId,
      gridSize: currentLevel.gridSize,
      elapsedMs: currentLevel.elapsedMs,
      nickname: authUi?.user?.displayName?.trim() || '玩家',
    };

    if (isLocalPuzzleRun(puzzleRun)) {
      setPuzzleRun(submitLocalPuzzleLeaderboard(puzzleRun, payload.nickname));
      setIsPuzzleLeaderboardBusy(false);
      return;
    }

    const submitLeaderboardPromise =
      puzzleRuntimeAuthMode === 'isolated'
        ? buildRecommendRuntimeGuestOptions().then((runtimeGuestOptions) =>
            submitPuzzleLeaderboard(
              puzzleRun.runId,
              payload,
              runtimeGuestOptions,
            ),
          )
        : submitPuzzleLeaderboard(puzzleRun.runId, payload);

    void submitLeaderboardPromise
      .then(({ run }) => {
        setPuzzleRun((currentRun) => {
          if (!currentRun) {
            return currentRun;
          }
          return mergePuzzleServiceRuntimeState(currentRun, run);
        });
        void platformBootstrap.refreshSaveArchives();
      })
      .catch((error) => {
        setPuzzleError(
          resolvePuzzleErrorMessage(error, '提交拼图排行榜失败。'),
        );
      })
      .finally(() => {
        setIsPuzzleLeaderboardBusy(false);
      });
  }, [
    authUi?.user?.displayName,
    platformBootstrap,
    puzzleRun,
    puzzleRuntimeAuthMode,
    resolvePuzzleErrorMessage,
    setPuzzleError,
  ]);

  const advancePuzzleLevel = useCallback(
    async (_target?: { profileId?: string; levelId?: string | null }) => {
      if (!puzzleRun || isPuzzleBusy || isPuzzleLeaderboardBusy) {
        return;
      }
      const currentLevel = puzzleRun.currentLevel;
      if (!currentLevel || currentLevel.status !== 'cleared') {
        return;
      }

      setIsPuzzleBusy(true);
      setIsPuzzleNextLevelGenerating(true);
      setPuzzleError(null);

      try {
        if (isLocalPuzzleRun(puzzleRun)) {
          const nextRun = advanceLocalPuzzleLevel(
            puzzleRun,
            selectedPuzzleDetail,
            _target,
          );
          setPuzzleRun(nextRun);
          return;
        }

        const runtimeGuestOptions =
          puzzleRuntimeAuthMode === 'isolated'
            ? await buildRecommendRuntimeGuestOptions()
            : {};
        const targetProfileId = _target?.profileId?.trim() ?? '';
        const preferSimilarWork =
          activeRecommendRuntimeKind === 'puzzle' &&
          puzzleRuntimeReturnStage === 'platform' &&
          puzzleRun.nextLevelMode === 'sameWork';
        if (puzzleRun.nextLevelMode === 'similarWorks' && targetProfileId) {
          const itemPromise =
            selectedPuzzleDetail?.profileId === targetProfileId
              ? Promise.resolve(selectedPuzzleDetail)
              : getPuzzleGalleryDetail(targetProfileId).then(
                  (response) => response.item,
                );
          const advancePromise =
            puzzleRuntimeAuthMode === 'isolated'
              ? advancePuzzleNextLevel(
                  puzzleRun.runId,
                  {
                    targetProfileId,
                  },
                  runtimeGuestOptions,
                )
              : advancePuzzleNextLevel(puzzleRun.runId, {
                  targetProfileId,
                });
          const [{ run }, item] = await Promise.all([
            advancePromise,
            itemPromise,
          ]);
          setSelectedPuzzleDetail(item);
          setPuzzleRun(run);
          openPuzzleRuntimeStage(
            setSelectionStage,
            buildPuzzlePublishedRuntimeUrlState(
              item,
              run.currentLevel?.levelId ?? null,
            ),
          );
          return;
        }

        const { run } =
          puzzleRuntimeAuthMode === 'isolated'
            ? await advancePuzzleNextLevel(
                puzzleRun.runId,
                preferSimilarWork ? { preferSimilarWork: true } : {},
                runtimeGuestOptions,
              )
            : await advancePuzzleNextLevel(
                puzzleRun.runId,
                preferSimilarWork ? { preferSimilarWork: true } : {},
              );
        const nextProfileId = run.currentLevel?.profileId?.trim() ?? '';
        if (
          nextProfileId &&
          selectedPuzzleDetail?.profileId !== nextProfileId
        ) {
          const item = await getPuzzleGalleryDetail(nextProfileId).then(
            (response) => response.item,
          );
          const nextRecommendEntry = mapPuzzleWorkToPlatformGalleryCard(item);
          setPuzzleGalleryEntries((current) => {
            const nextEntries = current.filter(
              (entry) => entry.profileId !== item.profileId,
            );
            nextEntries.push(item);
            return nextEntries;
          });
          setSelectedPuzzleDetail(item);
          setActiveRecommendEntryKey(
            getPlatformPublicGalleryEntryKey(nextRecommendEntry),
          );
        }
        setPuzzleRun(run);
      } catch (error) {
        setPuzzleError(resolvePuzzleErrorMessage(error, '准备下一关失败。'));
      } finally {
        setIsPuzzleNextLevelGenerating(false);
        setIsPuzzleBusy(false);
      }
    },
    [
      isPuzzleBusy,
      isPuzzleLeaderboardBusy,
      activeRecommendRuntimeKind,
      puzzleRun,
      puzzleRuntimeReturnStage,
      puzzleRuntimeAuthMode,
      setActiveRecommendEntryKey,
      setPuzzleGalleryEntries,
      resolvePuzzleErrorMessage,
      selectedPuzzleDetail,
      setIsPuzzleBusy,
      setPuzzleError,
    ],
  );
  const remodelCurrentPuzzleRuntimeWork = useCallback(
    (profileId: string) => {
      const targetProfileId = profileId.trim();
      if (!targetProfileId || isPublicWorkDetailBusy || isPuzzleBusy) {
        return;
      }

      runProtectedAction(async () => {
        setIsPublicWorkDetailBusy(true);
        setIsPuzzleBusy(true);
        setPuzzleError(null);
        setPublicWorkDetailError(null);

        void remixPuzzleGalleryWork(targetProfileId)
          .then((response) => {
            resetRecommendRuntimeSelection();
            puzzleFlow.setSession(response.session);
            setPuzzleOperation(null);
            setPuzzleRun(null);
            setPuzzleRuntimeAuthMode('default');
            enterCreateTab();
            setSelectionStage('puzzle-result');
          })
          .catch((error) => {
            setPuzzleError(
              resolvePuzzleErrorMessage(error, '改造拼图作品失败。'),
            );
          })
          .finally(() => {
            setIsPublicWorkDetailBusy(false);
            setIsPuzzleBusy(false);
          });
      });
    },
    [
      enterCreateTab,
      isPublicWorkDetailBusy,
      isPuzzleBusy,
      puzzleFlow,
      resolvePuzzleErrorMessage,
      resetRecommendRuntimeSelection,
      runProtectedAction,
      setIsPuzzleBusy,
      setPuzzleError,
      setSelectionStage,
    ],
  );

  const saveAndExitRecommendPuzzleRuntime = useCallback(async () => {
    if (activeRecommendRuntimeKind !== 'puzzle') {
      return;
    }

    const currentRun = puzzleRunRef.current;
    if (!currentRun) {
      setActiveRecommendRuntimeKind(null);
      return;
    }

    // 中文注释：推荐页嵌入拼图的“保存并退出”沿用现有运行态语义；
    // 正式 run 的每次交换/拖动/通关已写回后端，退出时只收口暂停和本地快照。
    const closedRun = currentRun.currentLevel
      ? setLocalPuzzlePaused(currentRun, false)
      : currentRun;
    puzzleRunRef.current = null;
    setPuzzleRun(null);
    setPuzzleRuntimeAuthMode('default');
    setActiveRecommendRuntimeKind(null);

    if (closedRun.currentLevel) {
      setPuzzleError(null);
    }
  }, [activeRecommendRuntimeKind, setPuzzleError]);

  const leaveAgentWorkspace = useCallback(() => {
    sessionController.resetSessionViewState();
    sessionController.setGeneratedCustomWorldProfile(null);
    autosaveCoordinator.resetAutoSaveTrackingToIdle();
    sessionController.persistAgentUiState(
      sessionController.activeAgentSessionId,
      null,
    );
    returnToCreationFlowSource();
  }, [autosaveCoordinator, returnToCreationFlowSource, sessionController]);

  const leaveAgentDraftGeneration = useCallback(() => {
    if (sessionController.isActiveGenerationRunning) {
      return;
    }

    sessionController.setAgentDraftGenerationStartedAt(null);
    sessionController.setCustomWorldGenerationViewSource(null);
    setSelectionStage('agent-workspace');
  }, [sessionController, setSelectionStage]);

  const leaveAgentDraftResult = useCallback(() => {
    sessionController.suppressAgentDraftResultAutoOpen();
    sessionController.setGeneratedCustomWorldProfile(null);
    sessionController.setCustomWorldError(null);
    autosaveCoordinator.resetAutoSaveTrackingToIdle();
    sessionController.setCustomWorldGenerationViewSource(null);
    sessionController.setCustomWorldResultViewSource(null);
    returnToCreationFlowSource();
  }, [autosaveCoordinator, returnToCreationFlowSource, sessionController]);

  const leaveCustomWorldResult = useCallback(() => {
    sessionController.setGeneratedCustomWorldProfile(null);
    sessionController.setCustomWorldError(null);
    autosaveCoordinator.resetAutoSaveTrackingToIdle();
    sessionController.setCustomWorldGenerationViewSource(null);
    sessionController.setCustomWorldResultViewSource(null);
    if (shouldReturnToDraftShelf()) {
      returnToCreationFlowSource();
      return;
    }
    setSelectionStage(selectedDetailEntry ? 'detail' : 'platform');
  }, [
    autosaveCoordinator,
    returnToCreationFlowSource,
    selectedDetailEntry,
    sessionController,
    setSelectionStage,
    shouldReturnToDraftShelf,
  ]);

  const handleStartSelectedWorld = useCallback(() => {
    if (!selectedDetailEntry) {
      return;
    }

    runProtectedAction(() => {
      handleCustomWorldSelect(selectedDetailEntry.profile);
    });
  }, [handleCustomWorldSelect, runProtectedAction, selectedDetailEntry]);

  const handleDeleteLibraryEntry = useCallback(
    (entry: CustomWorldLibraryEntry<CustomWorldProfile>) => {
      if (!entry.profileId || deletingCreationWorkId) {
        return;
      }

      const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
        kind: 'rpg-library',
        entry,
      });
      requestDeleteCreationWork({
        id: deleteModel.id,
        title: deleteModel.title,
        detail: deleteModel.detail,
        run: () => {
          setDeletingCreationWorkId(deleteModel.id);
          platformBootstrap.setPlatformError(null);

          void deleteRpgEntryWorldProfile(entry.profileId)
            .then(async (entries) => {
              platformBootstrap.setSavedCustomWorldEntries(entries);
              await platformBootstrap.refreshCustomWorldWorks().catch(() => []);
              await platformBootstrap.refreshPublishedGallery().catch(() => []);
            })
            .catch((error) => {
              platformBootstrap.setPlatformError(
                resolveRpgCreationErrorMessage(error, '删除自定义世界失败。'),
              );
            })
            .finally(() => {
              setDeletingCreationWorkId(null);
            });
        },
      });
    },
    [deletingCreationWorkId, platformBootstrap, requestDeleteCreationWork],
  );

  const handleDeletePublishedWork = useCallback(
    (work: (typeof creationHubItems)[number]) => {
      if (deletingCreationWorkId) {
        return;
      }
      const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
        kind: 'rpg',
        work,
      });

      requestDeleteCreationWork({
        id: deleteModel.id,
        title: deleteModel.title,
        detail: deleteModel.detail,
        run: () => {
          setDeletingCreationWorkId(deleteModel.id);
          platformBootstrap.setPlatformError(null);

          const deleteTask =
            work.sourceType === 'published_profile' && work.profileId
              ? deleteRpgEntryWorldProfile(work.profileId).then(
                  async (entries) => {
                    platformBootstrap.setSavedCustomWorldEntries(entries);
                    await platformBootstrap
                      .refreshCustomWorldWorks()
                      .catch(() => []);
                  },
                )
              : work.sourceType === 'agent_session' && work.sessionId
                ? deleteRpgCreationAgentSession(work.sessionId).then(
                    (items) => {
                      platformBootstrap.setCustomWorldWorkEntries(items);
                    },
                  )
                : Promise.reject(new Error('当前 RPG 作品缺少可删除 ID。'));

          void deleteTask
            .then(async () => {
              markDraftNoticeSeen(deleteModel.noticeKeys);
              await platformBootstrap.refreshPublishedGallery().catch(() => []);
            })
            .catch((error) => {
              platformBootstrap.setPlatformError(
                resolveRpgCreationErrorMessage(error, '删除自定义世界失败。'),
              );
            })
            .finally(() => {
              setDeletingCreationWorkId(null);
            });
        },
      });
    },
    [
      deletingCreationWorkId,
      markDraftNoticeSeen,
      platformBootstrap,
      requestDeleteCreationWork,
    ],
  );

  const handleDeleteBigFishWork = useCallback(
    (work: BigFishWorkSummary) => {
      if (deletingCreationWorkId) {
        return;
      }
      const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
        kind: 'big-fish',
        work,
      });

      requestDeleteCreationWork({
        id: deleteModel.id,
        title: deleteModel.title,
        detail: deleteModel.detail,
        run: () => {
          setDeletingCreationWorkId(deleteModel.id);
          setBigFishError(null);

          void deleteBigFishWork(work.sourceSessionId)
            .then(async (response) => {
              markDraftNoticeSeen(deleteModel.noticeKeys);
              setBigFishWorks(response.items);
              await refreshBigFishGallery().catch(() => []);
            })
            .catch((error) => {
              setBigFishError(
                resolveBigFishErrorMessage(error, '删除大鱼吃小鱼作品失败。'),
              );
            })
            .finally(() => {
              setDeletingCreationWorkId(null);
            });
        },
      });
    },
    [
      deletingCreationWorkId,
      markDraftNoticeSeen,
      refreshBigFishGallery,
      requestDeleteCreationWork,
      resolveBigFishErrorMessage,
      setBigFishError,
    ],
  );

  const handleDeletePuzzleWork = useCallback(
    (work: PuzzleWorkSummary) => {
      if (deletingCreationWorkId) {
        return;
      }
      const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
        kind: 'puzzle',
        work,
      });
      requestDeleteCreationWork({
        id: deleteModel.id,
        title: deleteModel.title,
        detail: deleteModel.detail,
        run: () => {
          setDeletingCreationWorkId(deleteModel.id);
          setPuzzleFormDraftPayload(null);
          setPuzzleError(null);

          void deletePuzzleWork(work.profileId)
            .then((response) => {
              markDraftNoticeSeen(deleteModel.noticeKeys);
              setPuzzleWorks(response.items);
              void refreshPuzzleGallery();
            })
            .catch((error) => {
              setPuzzleError(
                resolvePuzzleErrorMessage(error, '删除拼图作品失败。'),
              );
            })
            .finally(() => {
              setDeletingCreationWorkId(null);
            });
        },
      });
    },
    [
      deletingCreationWorkId,
      markDraftNoticeSeen,
      refreshPuzzleGallery,
      requestDeleteCreationWork,
      resolvePuzzleErrorMessage,
      setPuzzleError,
    ],
  );

  const handleDeleteMatch3DWork = useCallback(
    (work: Match3DWorkSummary) => {
      if (deletingCreationWorkId) {
        return;
      }
      const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
        kind: 'match3d',
        work,
      });

      requestDeleteCreationWork({
        id: deleteModel.id,
        title: deleteModel.title,
        detail: deleteModel.detail,
        run: () => {
          setDeletingCreationWorkId(deleteModel.id);
          setMatch3DFormDraftPayload(null);
          setMatch3DError(null);

          void deleteMatch3DWork(work.profileId)
            .then((response) => {
              markDraftNoticeSeen(deleteModel.noticeKeys);
              setMatch3DWorks(mapMatch3DWorksForRuntimeUi(response.items));
              void refreshMatch3DGallery();
            })
            .catch((error) => {
              setMatch3DError(
                resolveMatch3DErrorMessage(error, '删除抓大鹅作品失败。'),
              );
            })
            .finally(() => {
              setDeletingCreationWorkId(null);
            });
        },
      });
    },
    [
      deletingCreationWorkId,
      markDraftNoticeSeen,
      refreshMatch3DGallery,
      requestDeleteCreationWork,
      resolveMatch3DErrorMessage,
      setMatch3DFormDraftPayload,
      setMatch3DError,
    ],
  );

  const handleDeleteSquareHoleWork = useCallback(
    (work: SquareHoleWorkSummary) => {
      if (deletingCreationWorkId) {
        return;
      }
      const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
        kind: 'square-hole',
        work,
      });

      requestDeleteCreationWork({
        id: deleteModel.id,
        title: deleteModel.title,
        detail: deleteModel.detail,
        run: () => {
          setDeletingCreationWorkId(deleteModel.id);
          setSquareHoleError(null);

          void deleteSquareHoleWork(work.profileId)
            .then((response) => {
              markDraftNoticeSeen(deleteModel.noticeKeys);
              setSquareHoleWorks(response.items);
              void refreshSquareHoleGallery();
            })
            .catch((error) => {
              setSquareHoleError(
                resolveSquareHoleErrorMessage(error, '删除方洞挑战作品失败。'),
              );
            })
            .finally(() => {
              setDeletingCreationWorkId(null);
            });
        },
      });
    },
    [
      deletingCreationWorkId,
      markDraftNoticeSeen,
      refreshSquareHoleGallery,
      requestDeleteCreationWork,
      resolveSquareHoleErrorMessage,
      setSquareHoleError,
    ],
  );

  const handleDeleteVisualNovelWork = useCallback(
    (work: VisualNovelWorkSummary) => {
      if (deletingCreationWorkId) {
        return;
      }
      const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
        kind: 'visual-novel',
        work,
      });

      requestDeleteCreationWork({
        id: deleteModel.id,
        title: deleteModel.title,
        detail: deleteModel.detail,
        run: () => {
          setDeletingCreationWorkId(deleteModel.id);
          setVisualNovelError(null);

          void deleteVisualNovelWork(work.profileId)
            .then(async (response) => {
              markDraftNoticeSeen(deleteModel.noticeKeys);
              setVisualNovelWorks(response.works);
              await refreshVisualNovelGallery();
            })
            .catch((error) => {
              setVisualNovelError(
                resolvePuzzleErrorMessage(error, '删除视觉小说作品失败。'),
              );
            })
            .finally(() => {
              setDeletingCreationWorkId(null);
            });
        },
      });
    },
    [
      deletingCreationWorkId,
      markDraftNoticeSeen,
      refreshVisualNovelGallery,
      requestDeleteCreationWork,
      resolvePuzzleErrorMessage,
      setVisualNovelError,
    ],
  );

  const handleDeleteBabyObjectMatchWork = useCallback(
    (work: BabyObjectMatchDraft) => {
      if (deletingCreationWorkId) {
        return;
      }
      const deleteModel = resolvePlatformCreationWorkDeleteConfirmationModel({
        kind: 'baby-object-match',
        work,
      });

      requestDeleteCreationWork({
        id: deleteModel.id,
        title: deleteModel.title,
        detail: deleteModel.detail,
        run: () => {
          setDeletingCreationWorkId(deleteModel.id);
          setBabyObjectMatchError(null);

          void deleteLocalBabyObjectMatchDraft(work.profileId)
            .then((nextDrafts) => {
              markDraftNoticeSeen(deleteModel.noticeKeys);
              setBabyObjectMatchDrafts(nextDrafts);
              setBabyObjectMatchDraft((current) =>
                current?.profileId === work.profileId ? null : current,
              );
              if (
                babyObjectMatchDraft?.profileId === work.profileId &&
                (selectionStage === 'baby-object-match-result' ||
                  selectionStage === 'baby-object-match-runtime')
              ) {
                enterCreateTab();
                setSelectionStage('platform');
              }
            })
            .catch((error) => {
              setBabyObjectMatchError(
                resolvePuzzleErrorMessage(error, '删除宝贝识物作品失败。'),
              );
            })
            .finally(() => {
              setDeletingCreationWorkId(null);
            });
        },
      });
    },
    [
      babyObjectMatchDraft?.profileId,
      deletingCreationWorkId,
      enterCreateTab,
      markDraftNoticeSeen,
      requestDeleteCreationWork,
      resolvePuzzleErrorMessage,
      selectionStage,
      setSelectionStage,
    ],
  );

  const clearSelectedPublicWorkAuthor = useCallback(() => {
    publicWorkAuthorRequestKeyRef.current += 1;
    setSelectedPublicWorkAuthor(null);
  }, []);

  const loadSelectedPublicWorkAuthor = useCallback(
    (entry: PlatformPublicGalleryCard) => {
      const requestKey = publicWorkAuthorRequestKeyRef.current + 1;
      publicWorkAuthorRequestKeyRef.current = requestKey;
      setSelectedPublicWorkAuthor(null);

      void resolvePublicWorkAuthorSummary(entry)
        .then((author) => {
          if (publicWorkAuthorRequestKeyRef.current === requestKey) {
            setSelectedPublicWorkAuthor(author);
          }
        })
        .catch(() => {
          if (publicWorkAuthorRequestKeyRef.current === requestKey) {
            setSelectedPublicWorkAuthor(null);
          }
        });
    },
    [],
  );

  const openPublicWorkDetail = useCallback(
    (entry: PlatformPublicGalleryCard) => {
      const decision = resolvePlatformPublicWorkDetailOpenDecision(entry);
      if (decision.type === 'blocked') {
        setSelectedPublicWorkDetail(decision.selectedDetail);
        setPublicWorkDetailError(decision.errorMessage);
        setSelectionStage(decision.selectionStage);
        return;
      }

      setSelectedPublicWorkDetail(decision.selectedDetail);
      setPublicWorkDetailError(decision.errorMessage);
      setSelectionStage(decision.selectionStage);
      if (decision.historyPath) {
        pushAppHistoryPath(decision.historyPath);
      }
    },
    [setSelectionStage],
  );

  const handleClaimPuzzlePointIncentive = useCallback(
    (work: PuzzleWorkSummary) => {
      if (claimingPuzzlePointIncentiveProfileId) {
        return;
      }

      runProtectedAction(() => {
        setClaimingPuzzlePointIncentiveProfileId(work.profileId);
        setPuzzleError(null);

        void claimPuzzleWorkPointIncentive(work.profileId)
          .then((response) => {
            const updatedWork = response.item;
            setPuzzleWorks((current) =>
              current.map((item) => mergePuzzleWorkSummary(item, updatedWork)),
            );
            setPuzzleGalleryEntries((current) =>
              current.map((item) => mergePuzzleWorkSummary(item, updatedWork)),
            );
            setSelectedPuzzleDetail((current) =>
              current ? mergePuzzleWorkSummary(current, updatedWork) : current,
            );
            syncUpdatedPublicWorkDetail(
              mapPuzzleWorkToPublicWorkDetail(updatedWork),
            );
            void platformBootstrap.refreshProfileDashboard();
          })
          .catch((error) => {
            setPuzzleError(
              resolvePuzzleErrorMessage(error, '领取拼图积分激励失败。'),
            );
          })
          .finally(() => {
            setClaimingPuzzlePointIncentiveProfileId(null);
          });
      });
    },
    [
      claimingPuzzlePointIncentiveProfileId,
      platformBootstrap,
      resolvePuzzleErrorMessage,
      runProtectedAction,
      setPuzzleError,
      syncUpdatedPublicWorkDetail,
    ],
  );

  const likePublicWork = useCallback(
    (entry: PlatformPublicGalleryCard) => {
      if (isPublicWorkDetailBusy) {
        return;
      }

      runProtectedAction(() => {
        setIsPublicWorkDetailBusy(true);
        setPublicWorkDetailError(null);

        const intent = resolvePlatformPublicWorkLikeIntent(entry);

        if (intent.type === 'like-big-fish') {
          void likeBigFishGalleryWork(intent.profileId)
            .then((response) => {
              const updatedWork = response.items.find(
                (item) => item.sourceSessionId === intent.profileId,
              );
              if (!updatedWork) {
                return;
              }
              setBigFishGalleryEntries((current) =>
                current.map((item) =>
                  mergeBigFishWorkSummary(item, updatedWork),
                ),
              );
              setBigFishWorks((current) =>
                current.map((item) =>
                  mergeBigFishWorkSummary(item, updatedWork),
                ),
              );
              syncUpdatedPublicWorkDetail(
                mapBigFishWorkToPublicWorkDetail(updatedWork),
              );
              setBigFishRuntimeWork((current) =>
                current
                  ? mergeBigFishWorkSummary(current, updatedWork)
                  : current,
              );
            })
            .catch((error) => {
              setPublicWorkDetailError(
                resolveBigFishErrorMessage(error, '点赞大鱼吃小鱼作品失败。'),
              );
            })
            .finally(() => {
              setIsPublicWorkDetailBusy(false);
            });
          return;
        }

        if (intent.type === 'like-puzzle') {
          void likePuzzleGalleryWork(intent.profileId)
            .then((response) => {
              const updatedWork = response.item;
              setPuzzleGalleryEntries((current) =>
                current.map((item) =>
                  mergePuzzleWorkSummary(item, updatedWork),
                ),
              );
              setPuzzleWorks((current) =>
                current.map((item) =>
                  mergePuzzleWorkSummary(item, updatedWork),
                ),
              );
              setSelectedPuzzleDetail((current) =>
                current
                  ? mergePuzzleWorkSummary(current, updatedWork)
                  : current,
              );
              syncUpdatedPublicWorkDetail(
                mapPuzzleWorkToPublicWorkDetail(updatedWork),
              );
            })
            .catch((error) => {
              setPublicWorkDetailError(
                resolvePuzzleErrorMessage(error, '点赞拼图作品失败。'),
              );
            })
            .finally(() => {
              setIsPublicWorkDetailBusy(false);
            });
          return;
        }

        if (intent.type === 'unsupported') {
          setPublicWorkDetailError(intent.errorMessage);
          setIsPublicWorkDetailBusy(false);
          return;
        }

        void likeRpgEntryWorldGallery(intent.ownerUserId, intent.profileId)
          .then((updatedEntry) => {
            setSelectedDetailEntry((current) =>
              current?.profileId === updatedEntry.profileId
                ? updatedEntry
                : current,
            );
            platformBootstrap.setPublishedGalleryEntries((current) =>
              current.map((item) =>
                item.profileId === updatedEntry.profileId ? updatedEntry : item,
              ),
            );
            syncUpdatedPublicWorkDetail(
              mapRpgGalleryCardToPublicWorkDetail(updatedEntry),
            );
          })
          .catch((error) => {
            setPublicWorkDetailError(
              resolveRpgCreationErrorMessage(error, '点赞 RPG 作品失败。'),
            );
          })
          .finally(() => {
            setIsPublicWorkDetailBusy(false);
          });
      });
    },
    [
      isPublicWorkDetailBusy,
      platformBootstrap,
      resolveBigFishErrorMessage,
      resolvePuzzleErrorMessage,
      runProtectedAction,
      syncUpdatedPublicWorkDetail,
    ],
  );

  useEffect(() => {
    const detailEntry = resolveActivePlatformPublicWorkAuthorEntry({
      selectionStage,
      selectedPublicWorkDetail,
      selectedRpgDetailEntry: selectedDetailEntry,
    });

    if (!detailEntry) {
      clearSelectedPublicWorkAuthor();
      return;
    }

    loadSelectedPublicWorkAuthor(detailEntry);
  }, [
    clearSelectedPublicWorkAuthor,
    loadSelectedPublicWorkAuthor,
    selectedDetailEntry,
    selectedPublicWorkDetail,
    selectionStage,
  ]);

  const openRpgPublicWorkDetail = useCallback(
    async (entry: CustomWorldGalleryCard) => {
      if (!canExposePublicWork(entry)) {
        setSelectedPublicWorkDetail(null);
        setPublicWorkDetailError(EDUTAINMENT_HIDDEN_MESSAGE);
        setSelectionStage('platform');
        return;
      }

      setIsPublicWorkDetailBusy(true);
      setPublicWorkDetailError(null);
      clearSelectedPublicWorkAuthor();
      setSelectedPublicWorkDetail(entry);
      setSelectionStage('work-detail');

      try {
        const detailEntry =
          await detailNavigation.loadGalleryDetailEntry(entry);
        setSelectedDetailEntry(detailEntry);
        const detailCard = mapRpgGalleryCardToPublicWorkDetail(detailEntry);
        if (!canExposePublicWork(detailCard)) {
          setSelectedDetailEntry(null);
          setSelectedPublicWorkDetail(null);
          setPublicWorkDetailError(EDUTAINMENT_HIDDEN_MESSAGE);
          setSelectionStage('platform');
          return;
        }

        setSelectedPublicWorkDetail(detailCard);
        if (detailEntry.publicWorkCode?.trim()) {
          pushAppHistoryPath(
            buildPublicWorkStagePath('work-detail', detailEntry.publicWorkCode),
          );
        }
      } catch (error) {
        setSelectedPublicWorkDetail(entry);
        setPublicWorkDetailError(
          resolveRpgCreationErrorMessage(error, '读取作品详情失败。'),
        );
      } finally {
        setIsPublicWorkDetailBusy(false);
      }
    },
    [
      clearSelectedPublicWorkAuthor,
      detailNavigation,
      setSelectedDetailEntry,
      setSelectionStage,
    ],
  );

  const openPuzzlePublicWorkDetail = useCallback(
    async (
      profileId: string,
      returnTarget: PuzzleDetailReturnTarget = {
        tab: platformBootstrap.platformTab,
      },
    ) => {
      setIsPuzzleBusy(true);
      setIsPublicWorkDetailBusy(true);
      setPuzzleError(null);
      setPublicWorkDetailError(null);
      setSelectionStage('work-detail');

      try {
        const { item } = await getPuzzleGalleryDetail(profileId);
        const detailEntry = mapPuzzleWorkToPublicWorkDetail(item);
        if (!canExposePublicWork(detailEntry)) {
          setSelectedPuzzleDetail(null);
          setPublicWorkDetailError(EDUTAINMENT_HIDDEN_MESSAGE);
          setSelectionStage('platform');
          return;
        }

        setSelectedPuzzleDetail(item);
        setPuzzleDetailReturnTarget(returnTarget);
        openPublicWorkDetail(detailEntry);
      } catch (error) {
        if (isMissingPuzzleWorkError(error)) {
          setSelectedPuzzleDetail(null);
          setPuzzleDetailReturnTarget(null);
          setPuzzleRun(null);
          setPuzzleRuntimeAuthMode('default');
          setPuzzleGalleryEntries((current) =>
            current.filter((entry) => entry.profileId !== profileId),
          );
          setPuzzleError(null);
          setPublicWorkDetailError(null);
          returnPlatformHomeAfterMissingWork();
          return;
        }

        setPublicWorkDetailError(
          resolvePuzzleErrorMessage(error, '读取拼图详情失败。'),
        );
      } finally {
        setIsPuzzleBusy(false);
        setIsPublicWorkDetailBusy(false);
      }
    },
    [
      openPublicWorkDetail,
      platformBootstrap.platformTab,
      resolvePuzzleErrorMessage,
      setIsPuzzleBusy,
      setPuzzleError,
      setSelectionStage,
    ],
  );

  const openMatch3DPublicWorkDetail = useCallback(
    async (profileId: string) => {
      setIsPublicWorkDetailBusy(true);
      setMatch3DError(null);
      setPublicWorkDetailError(null);
      setSelectionStage('work-detail');

      try {
        const entries =
          match3dGalleryEntries.length > 0
            ? match3dGalleryEntries
            : await refreshMatch3DGallery();
        const matchedEntry = entries.find(
          (entry) => entry.profileId === profileId,
        );

        if (!matchedEntry) {
          throw new Error('未找到抓大鹅作品。');
        }

        openPublicWorkDetail(mapMatch3DWorkToPublicWorkDetail(matchedEntry));
      } catch (error) {
        setPublicWorkDetailError(
          resolveMatch3DErrorMessage(error, '读取抓大鹅详情失败。'),
        );
      } finally {
        setIsPublicWorkDetailBusy(false);
      }
    },
    [
      match3dGalleryEntries,
      openPublicWorkDetail,
      refreshMatch3DGallery,
      resolveMatch3DErrorMessage,
      setMatch3DError,
      setSelectionStage,
    ],
  );

  const openSquareHolePublicWorkDetail = useCallback(
    async (profileId: string) => {
      setIsPublicWorkDetailBusy(true);
      setSquareHoleError(null);
      setPublicWorkDetailError(null);
      setSelectionStage('work-detail');

      try {
        const entries =
          squareHoleGalleryEntries.length > 0
            ? squareHoleGalleryEntries
            : await refreshSquareHoleGallery();
        const matchedEntry = entries.find(
          (entry) => entry.profileId === profileId,
        );

        if (!matchedEntry) {
          throw new Error('未找到方洞挑战作品。');
        }

        openPublicWorkDetail(mapSquareHoleWorkToPublicWorkDetail(matchedEntry));
      } catch (error) {
        setPublicWorkDetailError(
          resolveSquareHoleErrorMessage(error, '读取方洞挑战详情失败。'),
        );
      } finally {
        setIsPublicWorkDetailBusy(false);
      }
    },
    [
      openPublicWorkDetail,
      refreshSquareHoleGallery,
      resolveSquareHoleErrorMessage,
      setSelectionStage,
      setSquareHoleError,
      squareHoleGalleryEntries,
    ],
  );

  const openVisualNovelPublicWorkDetail = useCallback(
    async (profileId: string) => {
      setIsPublicWorkDetailBusy(true);
      setVisualNovelError(null);
      setPublicWorkDetailError(null);
      setSelectionStage('work-detail');

      try {
        const entries =
          visualNovelGalleryEntries.length > 0
            ? visualNovelGalleryEntries
            : await refreshVisualNovelGallery();
        const matchedEntry = entries.find(
          (entry) => entry.profileId === profileId,
        );

        if (!matchedEntry) {
          throw new Error('未找到视觉小说作品。');
        }

        openPublicWorkDetail(
          mapVisualNovelWorkToPublicWorkDetail(matchedEntry),
        );
      } catch (error) {
        setPublicWorkDetailError(
          resolvePuzzleErrorMessage(error, '读取视觉小说详情失败。'),
        );
      } finally {
        setIsPublicWorkDetailBusy(false);
      }
    },
    [
      openPublicWorkDetail,
      refreshVisualNovelGallery,
      resolvePuzzleErrorMessage,
      setSelectionStage,
      setVisualNovelError,
      visualNovelGalleryEntries,
    ],
  );

  const openJumpHopPublicWorkDetail = useCallback(
    async (profileId: string) => {
      setIsPublicWorkDetailBusy(true);
      setJumpHopError(null);
      setPublicWorkDetailError(null);
      setSelectionStage('work-detail');

      try {
        const detail = await jumpHopClient.getWorkDetail(profileId);
        setJumpHopWork(detail.item);
        openPublicWorkDetail(mapJumpHopWorkToPublicWorkDetail(detail.item));
      } catch (error) {
        setPublicWorkDetailError(
          resolveRpgCreationErrorMessage(error, '读取跳一跳详情失败。'),
        );
      } finally {
        setIsPublicWorkDetailBusy(false);
      }
    },
    [openPublicWorkDetail, setJumpHopError, setSelectionStage],
  );

  const openJumpHopDraft = useCallback(
    async (item: JumpHopWorkSummaryResponse) => {
      const noticeIds = [item.workId, item.profileId, item.sourceSessionId];
      const hasFailedNotice = isDraftNoticeFailed('jump-hop', noticeIds);
      const sessionId = normalizeCreationUrlValue(item.sourceSessionId);
      markDraftNoticeSeen(collectDraftNoticeKeys('jump-hop', noticeIds));

      if (item.publicationStatus === 'published') {
        void openJumpHopPublicWorkDetail(item.profileId);
        return;
      }

      setJumpHopError(null);
      setPublicWorkDetailError(null);
      setIsJumpHopBusy(true);
      if (
        hasFailedNotice &&
        sessionId === jumpHopSession?.sessionId &&
        jumpHopGenerationState?.phase === 'failed'
      ) {
        enterCreateTab();
        setSelectionStage('jump-hop-generating');
        setIsJumpHopBusy(false);
        return;
      }

      if (item.generationStatus === 'generating' && !hasFailedNotice) {
        const pendingSession = buildJumpHopPendingSession(item);
        setJumpHopSession(pendingSession);
        setJumpHopRun(null);
        setJumpHopWork(null);
        setJumpHopGenerationState(
          createMiniGameDraftGenerationState(
            'jump-hop',
            resolveMiniGameDraftGenerationStartedAtMs(item.updatedAt),
          ),
        );
        writeCreationUrlState(
          buildJumpHopCreationUrlState({ session: pendingSession }),
        );
        enterCreateTab();
        setSelectionStage('jump-hop-generating');
        setIsJumpHopBusy(false);
        return;
      }

      try {
        const detail = await jumpHopClient.getWorkDetail(item.profileId);
        setJumpHopSession(null);
        setJumpHopRun(null);
        setJumpHopWork(detail.item);
        setJumpHopRuntimeReturnStage('jump-hop-result');
        enterCreateTab();
        setSelectionStage('jump-hop-result');
      } catch (error) {
        setJumpHopError(
          resolveRpgCreationErrorMessage(error, '读取跳一跳草稿失败。'),
        );
      } finally {
        setIsJumpHopBusy(false);
      }
    },
    [
      enterCreateTab,
      isDraftNoticeFailed,
      jumpHopGenerationState?.phase,
      jumpHopSession?.sessionId,
      markDraftNoticeSeen,
      openJumpHopPublicWorkDetail,
      setSelectionStage,
      writeCreationUrlState,
    ],
  );

  const openWoodenFishPublicWorkDetail = useCallback(
    async (profileId: string) => {
      setIsPublicWorkDetailBusy(true);
      setWoodenFishError(null);
      setPublicWorkDetailError(null);
      setSelectionStage('work-detail');

      try {
        const detail = await woodenFishClient.getWorkDetail(profileId);
        setWoodenFishWork(detail.item);
        openPublicWorkDetail(mapWoodenFishWorkToPublicWorkDetail(detail.item));
      } catch (error) {
        setPublicWorkDetailError(
          resolveRpgCreationErrorMessage(error, '读取敲木鱼详情失败。'),
        );
      } finally {
        setIsPublicWorkDetailBusy(false);
      }
    },
    [openPublicWorkDetail, setSelectionStage],
  );

  const openWoodenFishDraft = useCallback(
    async (item: WoodenFishWorkSummaryResponse) => {
      const noticeIds = [item.workId, item.profileId, item.sourceSessionId];
      const hasFailedNotice = isDraftNoticeFailed('wooden-fish', noticeIds);
      const sessionId =
        normalizeCreationUrlValue(item.sourceSessionId) ?? item.profileId;
      markDraftNoticeSeen(collectDraftNoticeKeys('wooden-fish', noticeIds));

      if (item.publicationStatus === 'published') {
        void openWoodenFishPublicWorkDetail(item.profileId);
        return;
      }

      setWoodenFishError(null);
      setPublicWorkDetailError(null);
      setIsWoodenFishBusy(true);
      if (
        hasFailedNotice &&
        sessionId === woodenFishSession?.sessionId &&
        woodenFishGenerationState?.phase === 'failed'
      ) {
        enterCreateTab();
        setSelectionStage('wooden-fish-generating');
        setIsWoodenFishBusy(false);
        return;
      }

      if (item.generationStatus === 'generating' && !hasFailedNotice) {
        const pendingSession = buildWoodenFishPendingSession(item);
        setWoodenFishSession(pendingSession);
        setWoodenFishRun(null);
        setWoodenFishWork(null);
        setWoodenFishGenerationState(
          createMiniGameDraftGenerationState(
            'wooden-fish',
            resolveMiniGameDraftGenerationStartedAtMs(item.updatedAt),
          ),
        );
        writeCreationUrlState(
          buildWoodenFishCreationUrlState({ session: pendingSession }),
        );
        enterCreateTab();
        setSelectionStage('wooden-fish-generating');
        setIsWoodenFishBusy(false);
        return;
      }
      try {
        const detail = await woodenFishClient.getWorkDetail(item.profileId);
        const recoveredSession = buildWoodenFishSessionFromWorkDetail(
          detail.item,
          item,
        );
        setWoodenFishSession(recoveredSession);
        setWoodenFishRun(null);
        setWoodenFishWork(detail.item);
        setWoodenFishRuntimeReturnStage('wooden-fish-result');
        writeCreationUrlState(
          buildWoodenFishCreationUrlState({
            session: recoveredSession,
            work: detail.item,
          }),
        );
        enterCreateTab();
        setSelectionStage('wooden-fish-result');
      } catch (error) {
        setWoodenFishError(
          resolveRpgCreationErrorMessage(error, '读取敲木鱼草稿失败。'),
        );
        enterCreateTab();
        setSelectionStage(
          hasFailedNotice ? 'wooden-fish-workspace' : 'wooden-fish-generating',
        );
      } finally {
        setIsWoodenFishBusy(false);
      }
    },
    [
      enterCreateTab,
      isDraftNoticeFailed,
      markDraftNoticeSeen,
      openWoodenFishPublicWorkDetail,
      woodenFishGenerationState?.phase,
      woodenFishSession?.sessionId,
      writeCreationUrlState,
      setSelectionStage,
    ],
  );

  const openPublicGalleryDetail = useCallback(
    (entry: PlatformPublicGalleryCard) => {
      const strategy = resolvePlatformPublicWorkDetailOpenStrategy(entry);
      switch (strategy.type) {
        case 'use-entry':
          openPublicWorkDetail(entry);
          return;
        case 'load-puzzle-detail':
          void openPuzzlePublicWorkDetail(strategy.profileId, {
            tab: platformBootstrap.platformTab,
          });
          return;
        case 'load-jump-hop-detail':
          void openJumpHopPublicWorkDetail(strategy.profileId);
          return;
        case 'load-wooden-fish-detail':
          void openWoodenFishPublicWorkDetail(strategy.profileId);
          return;
        case 'load-visual-novel-detail':
          void openVisualNovelPublicWorkDetail(strategy.profileId);
          return;
        case 'load-rpg-detail':
          void openRpgPublicWorkDetail(strategy.entry);
          return;
        default: {
          const exhaustive: never = strategy;
          return exhaustive;
        }
      }
    },
    [
      openPuzzlePublicWorkDetail,
      openPublicWorkDetail,
      openJumpHopPublicWorkDetail,
      openWoodenFishPublicWorkDetail,
      openRpgPublicWorkDetail,
      openVisualNovelPublicWorkDetail,
      platformBootstrap.platformTab,
    ],
  );

  const openRecommendGalleryDetail = useCallback(
    (entry: PlatformPublicGalleryCard) => {
      runProtectedAction(() => {
        openPublicGalleryDetail(entry);
      });
    },
    [openPublicGalleryDetail, runProtectedAction],
  );
  const openPuzzleDetail = useCallback(
    async (
      profileId: string,
      returnTarget: PuzzleDetailReturnTarget = {
        tab: platformBootstrap.platformTab,
      },
    ) => {
      setIsPuzzleBusy(true);
      setPuzzleError(null);

      try {
        const { item } = await getPuzzleGalleryDetail(profileId);
        setSelectedPuzzleDetail(item);
        setPuzzleDetailReturnTarget(returnTarget);
        setSelectionStage('puzzle-gallery-detail');
        pushAppHistoryPath(
          buildPublicWorkStagePath(
            'puzzle-gallery-detail',
            buildPuzzlePublicWorkCode(item.profileId),
          ),
        );
      } catch (error) {
        if (isMissingPuzzleWorkError(error)) {
          setSelectedPuzzleDetail(null);
          setPuzzleDetailReturnTarget(null);
          setPuzzleRun(null);
          setPuzzleRuntimeAuthMode('default');
          setPuzzleError(null);
          setPublicWorkDetailError(null);
          setPlatformTab('home');
          setSelectionStage('platform');
          if (!maybeAlertWorkNotFoundAndReturnHome()) {
            pushAppHistoryPath('/');
          }
          return;
        }

        setPuzzleError(resolvePuzzleErrorMessage(error, '读取拼图详情失败。'));
      } finally {
        setIsPuzzleBusy(false);
      }
    },
    [
      platformBootstrap.platformTab,
      resolvePuzzleErrorMessage,
      setIsPuzzleBusy,
      setPuzzleError,
      returnPlatformHomeAfterMissingWork,
    ],
  );

  const openPuzzleDraft = useCallback(
    async (item: PuzzleWorkSummary) => {
      const noticeKeys = collectDraftNoticeKeys('puzzle', [
        item.workId,
        item.profileId,
        item.sourceSessionId,
        buildPuzzleResultWorkId(item.sourceSessionId),
        buildPuzzleResultProfileId(item.sourceSessionId),
      ]);
      const failedNotice = getDraftGenerationNotice(
        draftGenerationNotices,
        noticeKeys,
      );
      const isPersistedFailed = isPersistedDraftFailed(item.generationStatus);
      const hasGeneratingNotice = isDraftNoticeGenerating('puzzle', [
        item.workId,
        item.profileId,
        item.sourceSessionId,
        buildPuzzleResultWorkId(item.sourceSessionId),
        buildPuzzleResultProfileId(item.sourceSessionId),
      ]);
      const hasFailedNotice = isDraftNoticeFailed('puzzle', [
        item.workId,
        item.profileId,
        item.sourceSessionId,
        buildPuzzleResultWorkId(item.sourceSessionId),
        buildPuzzleResultProfileId(item.sourceSessionId),
      ]);
      const noticeErrorMessage =
        failedNotice?.status === 'failed'
          ? (failedNotice.message ?? buildDraftFailedShelfSummary('puzzle'))
          : buildDraftFailedShelfSummary('puzzle');
      const isMarkedGenerating =
        !hasFailedNotice &&
        ((hasGeneratingNotice && !resolvePuzzleWorkCoverImageSrc(item)) ||
          isPersistedPuzzleDraftGenerating(item));
      setPuzzleOperation(null);
      setPuzzleRun(null);
      setPuzzleRuntimeAuthMode('default');
      setSelectedPuzzleDetail(null);
      if (!item.sourceSessionId?.trim()) {
        if (item.publicationStatus === 'published') {
          await openPuzzleDetail(item.profileId, { tab: 'create' });
          return;
        }

        setPuzzleError('这份拼图草稿缺少会话信息，请重新开始创作。');
        return;
      }

      const backgroundTask = getPuzzleBackgroundCompileTask(
        item.sourceSessionId,
      );
      const activeGenerationState =
        backgroundTask?.generationState ?? puzzleGenerationViewState;
      const failedGenerationState =
        backgroundTask?.generationState.phase === 'failed'
          ? backgroundTask.generationState
          : item.sourceSessionId === puzzleSession?.sessionId &&
              activeGenerationState?.phase === 'failed'
            ? activeGenerationState
            : hasFailedNotice || isPersistedFailed
              ? createFailedMiniGameDraftGenerationStateForRestoredDraft(
                  'puzzle',
                  item.updatedAt,
                  noticeErrorMessage,
                  { puzzleAiRedraw: true },
                )
              : null;

      if ((hasFailedNotice || isPersistedFailed) && failedGenerationState) {
        let failedSession = backgroundTask?.session ?? null;
        let failedPayload = backgroundTask?.payload ?? null;
        const failedError =
          backgroundTask?.error ?? failedNotice?.message ?? noticeErrorMessage;
        if (!failedSession) {
          try {
            const { session: latestSession } = await getPuzzleAgentSession(
              item.sourceSessionId,
            );
            failedSession = latestSession;
            failedPayload = buildPuzzleFormPayloadFromSession(latestSession);
          } catch {
            failedPayload = buildPuzzleFormPayloadFromWork(item);
          }
        }
        if (!failedPayload) {
          failedPayload = failedSession
            ? buildPuzzleFormPayloadFromSession(failedSession)
            : buildPuzzleFormPayloadFromWork(item);
        }
        if (backgroundTask) {
          puzzleFlow.setSession(backgroundTask.session);
        } else if (failedSession) {
          puzzleFlow.setSession(failedSession);
        }
        setPuzzleFormDraftPayload(failedPayload);
        setPuzzleError(failedError);
        if (failedSession) {
          setPuzzleBackgroundCompileTasks((current) => ({
            ...current,
            [failedSession!.sessionId]: {
              session: failedSession!,
              payload: failedPayload!,
              generationState: failedGenerationState,
              error: failedError,
            },
          }));
        }
        enterCreateTab();
        selectionStageRef.current = 'puzzle-generating';
        activePuzzleGenerationSessionIdRef.current = item.sourceSessionId;
        setPuzzleGenerationState(failedGenerationState);
        setSelectionStage('puzzle-generating');
        return;
      }

      if (
        item.sourceSessionId === puzzleSession?.sessionId &&
        isMiniGameDraftGenerating(activeGenerationState)
      ) {
        if (!activeGenerationState) {
          return;
        }
        const rebasedGenerationState =
          rebaseMiniGameDraftGenerationStateForDisplay(activeGenerationState);
        enterCreateTab();
        selectionStageRef.current = 'puzzle-generating';
        activePuzzleGenerationSessionIdRef.current = item.sourceSessionId;
        setPuzzleGenerationState(rebasedGenerationState);
        if (backgroundTask) {
          setPuzzleBackgroundCompileTasks((current) => ({
            ...current,
            [backgroundTask.session.sessionId]: {
              ...backgroundTask,
              generationState: rebasedGenerationState,
            },
          }));
        }
        setSelectionStage('puzzle-generating');
        return;
      }

      if (
        backgroundTask &&
        isMiniGameDraftGenerating(backgroundTask.generationState)
      ) {
        const rebasedTask =
          rebaseMiniGameDraftBackgroundCompileTaskForDisplay(backgroundTask);
        puzzleFlow.setSession(rebasedTask.session);
        setPuzzleFormDraftPayload(rebasedTask.payload);
        setPuzzleGenerationState(rebasedTask.generationState);
        setPuzzleBackgroundCompileTasks((current) => ({
          ...current,
          [rebasedTask.session.sessionId]: rebasedTask,
        }));
        if (backgroundTask.error) {
          setPuzzleError(backgroundTask.error);
        }
        enterCreateTab();
        selectionStageRef.current = 'puzzle-generating';
        activePuzzleGenerationSessionIdRef.current = item.sourceSessionId;
        setSelectionStage('puzzle-generating');
        return;
      }

      if (isMarkedGenerating) {
        try {
          const { session: latestSession } = await getPuzzleAgentSession(
            item.sourceSessionId,
          );
          const payload = buildPuzzleFormPayloadFromSession(latestSession);
          const startedAtMs = resolveMiniGameDraftGenerationStartedAtMs(
            latestSession.updatedAt,
          );
          const baseGenerationState =
            createMiniGameDraftGenerationStateForRestoredDraft(
              'puzzle',
              {
                puzzleAiRedraw: payload.aiRedraw ?? true,
                puzzleProgressPercent:
                  latestSession.draft && !latestSession.draft.formDraft
                    ? latestSession.progressPercent
                    : undefined,
              },
              startedAtMs,
            );
          const generationState = mergePuzzleSessionProgressIntoGenerationState(
            baseGenerationState,
            latestSession,
          );
          puzzleFlow.setSession(latestSession);
          setPuzzleFormDraftPayload(payload);
          setPuzzleGenerationState(generationState);
          setPuzzleBackgroundCompileTasks((current) => ({
            ...current,
            [latestSession.sessionId]: {
              session: latestSession,
              payload,
              generationState,
              error: null,
            },
          }));
          enterCreateTab();
          selectionStageRef.current = 'puzzle-generating';
          activePuzzleGenerationSessionIdRef.current = item.sourceSessionId;
          setSelectionStage('puzzle-generating');
          return;
        } catch (error) {
          setPuzzleError(
            resolvePuzzleErrorMessage(error, '读取拼图创作草稿失败。'),
          );
          await refreshPuzzleShelf().catch(() => undefined);
          return;
        }
      }

      markDraftNoticeSeen(noticeKeys);

      const restoredSession = await puzzleFlow.restoreDraft(
        item.sourceSessionId,
      );
      if (!restoredSession) {
        await refreshPuzzleShelf().catch(() => undefined);
        return;
      }

      if (isPuzzleFormOnlyDraft(restoredSession)) {
        setPuzzleFormDraftPayload(
          buildPuzzleFormPayloadFromSession(restoredSession),
        );
        setSelectionStage('puzzle-agent-workspace');
      } else {
        setPuzzleFormDraftPayload(null);
      }
    },
    [
      enterCreateTab,
      draftGenerationNotices,
      getPuzzleBackgroundCompileTask,
      isDraftNoticeFailed,
      isDraftNoticeGenerating,
      markDraftNoticeSeen,
      openPuzzleDetail,
      puzzleFlow,
      puzzleGenerationViewState,
      puzzleSession?.sessionId,
      refreshPuzzleShelf,
      resolvePuzzleErrorMessage,
      setPuzzleError,
      setSelectionStage,
    ],
  );

  const openMatch3DDraft = useCallback(
    async (
      item: Match3DWorkSummary,
      options: { forceDraft?: boolean } = {},
    ) => {
      const noticeKeys = collectDraftNoticeKeys('match3d', [
        item.workId,
        item.profileId,
        item.sourceSessionId,
      ]);
      const hasUnreadReadyNotice = isDraftNoticeReadyUnread('match3d', [
        item.workId,
        item.profileId,
        item.sourceSessionId,
      ]);
      setMatch3DRun(null);
      setMatch3DError(null);
      setMatch3DProfile(null);
      setMatch3DRuntimeProfile(null);

      if (item.publicationStatus === 'published' && !options.forceDraft) {
        markDraftNoticeSeen(noticeKeys);
        openPublicWorkDetail(mapMatch3DWorkToPublicWorkDetail(item));
        return;
      }

      if (!item.sourceSessionId?.trim()) {
        markDraftNoticeSeen(noticeKeys);
        setMatch3DError('这份抓大鹅草稿缺少会话信息，请重新开始创作。');
        return;
      }

      const failedNotice = getDraftGenerationNotice(
        draftGenerationNotices,
        noticeKeys,
      );
      const hasFailedNotice = isDraftNoticeFailed('match3d', [
        item.workId,
        item.profileId,
        item.sourceSessionId,
      ]);
      const noticeErrorMessage =
        failedNotice?.status === 'failed'
          ? (failedNotice.message ?? buildDraftFailedShelfSummary('match3d'))
          : buildDraftFailedShelfSummary('match3d');
      const isMarkedGenerating =
        !hasFailedNotice &&
        (isDraftNoticeGenerating('match3d', [
          item.workId,
          item.profileId,
          item.sourceSessionId,
        ]) ||
          isPersistedDraftGenerating(item.generationStatus));

      const backgroundTask = getMatch3DBackgroundCompileTask(
        item.sourceSessionId,
      );
      const activeGenerationState =
        backgroundTask?.generationState ?? match3dGenerationViewState;
      const failedGenerationState =
        backgroundTask?.generationState.phase === 'failed'
          ? backgroundTask.generationState
          : item.sourceSessionId === match3dSession?.sessionId &&
              activeGenerationState?.phase === 'failed'
            ? activeGenerationState
            : hasFailedNotice
              ? createFailedMiniGameDraftGenerationStateForRestoredDraft(
                  'match3d',
                  item.updatedAt,
                  noticeErrorMessage,
                )
              : null;

      if (hasUnreadReadyNotice) {
        try {
          const { session: latestSession } =
            await match3dCreationClient.getSession(item.sourceSessionId);
          setMatch3DSession(latestSession);
          setMatch3DFormDraftPayload(null);
          const profileId = latestSession.draft?.profileId ?? item.profileId;
          const { item: profile } = await getMatch3DWorkDetail(profileId);
          const normalizedProfile = normalizeMatch3DWorkForRuntimeUi(profile);
          match3dFlow.setIsBusy(false);
          const started = await startMatch3DRunFromProfile(
            normalizedProfile,
            'match3d-result',
          );
          if (!started) {
            setMatch3DProfile(normalizedProfile);
            enterCreateTab();
            setSelectionStage('match3d-result');
          }
          markDraftNoticeSeen(noticeKeys);
          return;
        } catch (error) {
          setMatch3DError(
            resolveMatch3DErrorMessage(error, '启动抓大鹅试玩失败。'),
          );
          markDraftNoticeSeen(noticeKeys);
          await refreshMatch3DShelf().catch(() => undefined);
          return;
        }
      }

      if (failedGenerationState) {
        let failedSession = backgroundTask?.session ?? null;
        let failedPayload = backgroundTask?.payload ?? null;
        const failedError =
          backgroundTask?.error ?? failedNotice?.message ?? noticeErrorMessage;
        if (!failedSession) {
          try {
            const { session: latestSession } =
              await match3dCreationClient.getSession(item.sourceSessionId);
            failedSession = latestSession;
            failedPayload = buildMatch3DFormPayloadFromSession(latestSession);
          } catch {
            failedPayload = buildMatch3DFormPayloadFromWork(item);
          }
        }
        if (!failedPayload) {
          failedPayload = failedSession
            ? buildMatch3DFormPayloadFromSession(failedSession)
            : buildMatch3DFormPayloadFromWork(item);
        }
        if (backgroundTask) {
          setMatch3DSession(backgroundTask.session);
        } else if (failedSession) {
          setMatch3DSession(failedSession);
        }
        setMatch3DFormDraftPayload(failedPayload);
        setMatch3DError(failedError);
        if (failedSession) {
          setMatch3DBackgroundCompileTasks((current) => ({
            ...current,
            [failedSession!.sessionId]: {
              session: failedSession!,
              payload: failedPayload!,
              generationState: failedGenerationState,
              error: failedError,
            },
          }));
        }
        enterCreateTab();
        selectionStageRef.current = 'match3d-generating';
        activeMatch3DGenerationSessionIdRef.current = item.sourceSessionId;
        setMatch3DGenerationState(failedGenerationState);
        setSelectionStage('match3d-generating');
        return;
      }

      if (
        item.sourceSessionId === match3dSession?.sessionId &&
        isMiniGameDraftGenerating(activeGenerationState)
      ) {
        if (!activeGenerationState) {
          return;
        }
        const rebasedGenerationState =
          rebaseMiniGameDraftGenerationStateForDisplay(activeGenerationState);
        enterCreateTab();
        selectionStageRef.current = 'match3d-generating';
        activeMatch3DGenerationSessionIdRef.current = item.sourceSessionId;
        setMatch3DGenerationState(rebasedGenerationState);
        if (backgroundTask) {
          setMatch3DBackgroundCompileTasks((current) => ({
            ...current,
            [backgroundTask.session.sessionId]: {
              ...backgroundTask,
              generationState: rebasedGenerationState,
            },
          }));
        }
        setSelectionStage('match3d-generating');
        return;
      }

      if (
        backgroundTask &&
        isMiniGameDraftGenerating(backgroundTask.generationState)
      ) {
        const rebasedTask =
          rebaseMiniGameDraftBackgroundCompileTaskForDisplay(backgroundTask);
        setMatch3DSession(rebasedTask.session);
        setMatch3DFormDraftPayload(rebasedTask.payload);
        setMatch3DGenerationState(rebasedTask.generationState);
        setMatch3DBackgroundCompileTasks((current) => ({
          ...current,
          [rebasedTask.session.sessionId]: rebasedTask,
        }));
        if (backgroundTask.error) {
          setMatch3DError(backgroundTask.error);
        }
        enterCreateTab();
        selectionStageRef.current = 'match3d-generating';
        activeMatch3DGenerationSessionIdRef.current = item.sourceSessionId;
        setSelectionStage('match3d-generating');
        return;
      }

      if (isMarkedGenerating) {
        try {
          const { session: latestSession } =
            await match3dCreationClient.getSession(item.sourceSessionId);
          setMatch3DSession(latestSession);
          setMatch3DFormDraftPayload(null);
          setMatch3DProfile(null);
          const generationState =
            createMiniGameDraftGenerationStateForRestoredDraft(
              'match3d',
              undefined,
              resolveMiniGameDraftGenerationStartedAtMs(
                latestSession.updatedAt,
              ),
            );
          setMatch3DGenerationState(generationState);
          enterCreateTab();
          selectionStageRef.current = 'match3d-generating';
          activeMatch3DGenerationSessionIdRef.current = item.sourceSessionId;
          setSelectionStage('match3d-generating');
          return;
        } catch (error) {
          setMatch3DError(
            resolveMatch3DErrorMessage(error, '读取抓大鹅创作草稿失败。'),
          );
          await refreshMatch3DShelf().catch(() => undefined);
          return;
        }
      }

      markDraftNoticeSeen(noticeKeys);

      const restoredSession = await match3dFlow.restoreDraft(
        item.sourceSessionId,
      );
      if (!restoredSession) {
        await refreshMatch3DShelf().catch(() => undefined);
        return;
      }

      setMatch3DFormDraftPayload(null);

      try {
        const profileId = restoredSession.draft?.profileId ?? item.profileId;
        const { item: profile } = await getMatch3DWorkDetail(profileId);
        setMatch3DProfile(normalizeMatch3DWorkForRuntimeUi(profile));
      } catch (error) {
        setMatch3DProfile(buildMatch3DProfileFromSession(restoredSession));
        setMatch3DError(
          resolveMatch3DErrorMessage(error, '读取抓大鹅作品详情失败。'),
        );
      }
    },
    [
      enterCreateTab,
      draftGenerationNotices,
      getMatch3DBackgroundCompileTask,
      isDraftNoticeFailed,
      isDraftNoticeGenerating,
      isDraftNoticeReadyUnread,
      markDraftNoticeSeen,
      match3dFlow,
      match3dGenerationViewState,
      match3dSession?.sessionId,
      openPublicWorkDetail,
      refreshMatch3DShelf,
      resolveMatch3DErrorMessage,
      setMatch3DFormDraftPayload,
      setMatch3DError,
      setMatch3DSession,
      setSelectionStage,
      startMatch3DRunFromProfile,
    ],
  );

  const openSquareHoleDraft = useCallback(
    async (
      item: SquareHoleWorkSummary,
      options: { forceDraft?: boolean } = {},
    ) => {
      setSquareHoleRun(null);
      setSquareHoleError(null);
      setSquareHoleProfile(null);
      markDraftNoticeSeen(
        collectDraftNoticeKeys('square-hole', [
          item.workId,
          item.profileId,
          item.sourceSessionId,
        ]),
      );

      if (item.publicationStatus === 'published' && !options.forceDraft) {
        openPublicWorkDetail(mapSquareHoleWorkToPublicWorkDetail(item));
        return;
      }

      if (!item.sourceSessionId?.trim()) {
        setSquareHoleError('这份方洞挑战草稿缺少会话信息，请重新开始创作。');
        return;
      }

      if (
        item.sourceSessionId === squareHoleSession?.sessionId &&
        isMiniGameDraftGenerating(squareHoleGenerationState)
      ) {
        enterCreateTab();
        selectionStageRef.current = 'square-hole-generating';
        setSelectionStage('square-hole-generating');
        return;
      }

      if (!isMiniGameDraftReady(squareHoleGenerationState)) {
        setSquareHoleGenerationState(null);
      }
      const restoredSession = await squareHoleFlow.restoreDraft(
        item.sourceSessionId,
      );
      if (!restoredSession) {
        await refreshSquareHoleShelf().catch(() => undefined);
        return;
      }

      try {
        const profileId = restoredSession.draft?.profileId ?? item.profileId;
        const { item: profile } = await getSquareHoleWorkDetail(profileId);
        setSquareHoleProfile(profile);
      } catch (error) {
        setSquareHoleProfile(
          buildSquareHoleProfileFromSession(restoredSession),
        );
        setSquareHoleError(
          resolveSquareHoleErrorMessage(error, '读取方洞挑战作品详情失败。'),
        );
      }
    },
    [
      enterCreateTab,
      markDraftNoticeSeen,
      openPublicWorkDetail,
      refreshSquareHoleShelf,
      resolveSquareHoleErrorMessage,
      setSquareHoleError,
      setSelectionStage,
      squareHoleGenerationState,
      squareHoleFlow,
      squareHoleSession?.sessionId,
    ],
  );

  const openBigFishDraft = useCallback(
    async (item: BigFishWorkSummary) => {
      setBigFishRun(null);
      markDraftNoticeSeen(
        collectDraftNoticeKeys('big-fish', [item.workId, item.sourceSessionId]),
      );
      if (
        item.sourceSessionId === bigFishSession?.sessionId &&
        isMiniGameDraftGenerating(bigFishGenerationState)
      ) {
        enterCreateTab();
        selectionStageRef.current = 'big-fish-generating';
        setSelectionStage('big-fish-generating');
        return;
      }
      const restoredSession = await bigFishFlow.restoreDraft(
        item.sourceSessionId,
      );
      if (!restoredSession) {
        await refreshBigFishShelf().catch(() => undefined);
      }
    },
    [
      bigFishFlow,
      bigFishGenerationState,
      bigFishSession?.sessionId,
      enterCreateTab,
      markDraftNoticeSeen,
      refreshBigFishShelf,
      setSelectionStage,
    ],
  );

  const openBarkBattleDraft = useCallback(
    (item: BarkBattleWorkSummary, options: { forceDraft?: boolean } = {}) => {
      markDraftNoticeSeen(
        collectDraftNoticeKeys('bark-battle', [item.workId, item.draftId]),
      );
      setBarkBattleError(null);
      setBarkBattleGenerationPartialFailed(false);
      setBarkBattlePublishedConfig(null);

      if (item.status === 'published' && !options.forceDraft) {
        openPublicWorkDetail(mapBarkBattleWorkToPublicWorkDetail(item));
        return;
      }

      const nextDraft = buildBarkBattleDraftConfigFromWorkSummary(item);
      setBarkBattleDraftConfig(nextDraft);
      enterCreateTab();
      selectionStageRef.current = isPersistedBarkBattleDraftGenerating(item)
        ? 'bark-battle-generating'
        : 'bark-battle-result';
      setSelectionStage(selectionStageRef.current);
      writeCreationUrlState(buildBarkBattleCreationUrlState(nextDraft));
    },
    [
      enterCreateTab,
      markDraftNoticeSeen,
      openPublicWorkDetail,
      setSelectionStage,
    ],
  );

  const openVisualNovelDraft = useCallback(
    async (
      item: VisualNovelWorkSummary,
      options: { forceDraft?: boolean } = {},
    ) => {
      if (item.publishStatus === 'published' && !options.forceDraft) {
        openPublicWorkDetail(mapVisualNovelWorkToPublicWorkDetail(item));
        return;
      }

      markDraftNoticeSeen(
        collectDraftNoticeKeys('visual-novel', [item.profileId]),
      );
      if (
        item.profileId === visualNovelSession?.sessionId &&
        visualNovelGenerationPhase === 'generating'
      ) {
        enterCreateTab();
        selectionStageRef.current = 'visual-novel-generating';
        setSelectionStage('visual-novel-generating');
        return;
      }
      if (
        item.profileId === visualNovelSession?.sessionId &&
        visualNovelSession.draft
      ) {
        enterCreateTab();
        setSelectionStage('visual-novel-result');
        return;
      }

      setVisualNovelWork(null);
      setVisualNovelRun(null);
      setVisualNovelRuntimeReturnStage('visual-novel-result');
      setVisualNovelError(null);
      setIsVisualNovelBusy(true);

      try {
        const { work } = await getVisualNovelWorkDetail(item.profileId);
        setVisualNovelWork(work);
        setVisualNovelSession(buildVisualNovelSessionFromWorkDetail(work));
        enterCreateTab();
        setSelectionStage('visual-novel-result');
      } catch (error) {
        setVisualNovelError(
          resolvePuzzleErrorMessage(error, '读取视觉小说作品详情失败。'),
        );
      } finally {
        setIsVisualNovelBusy(false);
      }
    },
    [
      enterCreateTab,
      openPublicWorkDetail,
      markDraftNoticeSeen,
      resolvePuzzleErrorMessage,
      setIsVisualNovelBusy,
      setSelectionStage,
      setVisualNovelError,
      setVisualNovelSession,
      visualNovelGenerationPhase,
      visualNovelSession,
    ],
  );

  const openBabyObjectMatchDraft = useCallback(
    (draft: BabyObjectMatchDraft) => {
      markDraftNoticeSeen(
        collectDraftNoticeKeys('baby-object-match', [
          draft.profileId,
          draft.draftId,
        ]),
      );
      setBabyObjectMatchDraft(draft);
      setBabyObjectMatchFormPayload({
        itemAName: draft.itemNames[0],
        itemBName: draft.itemNames[1],
      });
      setBabyObjectMatchGenerationState(null);
      setBabyObjectMatchGenerationPhase('ready');
      setBabyObjectMatchError(null);
      enterCreateTab();
      setSelectionStage('baby-object-match-result');
      writeCreationUrlState(buildBabyObjectMatchCreationUrlState(draft));
    },
    [enterCreateTab, markDraftNoticeSeen, setSelectionStage],
  );

  useEffect(() => {
    const restoreDecision = resolveInitialCreationUrlRestoreDecision({
      handled: handledInitialCreationUrlStateRef.current,
      pathname: window.location.pathname,
      state: initialCreationUrlState,
      isLoadingPlatform: platformBootstrap.isLoadingPlatform,
      canReadProtectedData: platformBootstrap.canReadProtectedData,
    });

    if (restoreDecision.type === 'skip' || restoreDecision.type === 'wait') {
      return;
    }

    if (restoreDecision.type === 'mark-handled') {
      handledInitialCreationUrlStateRef.current = true;
      return;
    }

    handledInitialCreationUrlStateRef.current = true;

    const restoreCreationUrlState = async () => {
      const target = resolveCreationUrlRestoreTarget(
        window.location.pathname,
        initialCreationUrlState,
      );
      if (!target) {
        return;
      }
      const { sessionId, profileId } = target;

      if (target.kind === 'big-fish') {
        const targetSessionId = target.bigFishSessionId;
        if (targetSessionId) {
          const matchedWork =
            (bigFishWorks.length > 0
              ? bigFishWorks
              : (await listBigFishWorks().catch(() => ({ items: [] }))).items
            ).find((item) =>
              matchesBigFishCreationUrlRestoreTarget(item, target),
            ) ?? null;
          if (matchedWork) {
            await openBigFishDraft(matchedWork);
            return;
          }
          await bigFishFlow.restoreDraft(targetSessionId);
        }
        return;
      }

      if (target.kind === 'match3d') {
        const matchedWork =
          (match3dWorks.length > 0
            ? match3dWorks
            : mapMatch3DWorksForRuntimeUi(
                (await listMatch3DWorks().catch(() => ({ items: [] }))).items,
              )
          ).find((item) =>
            matchesSessionProfileWorkCreationUrlRestoreTarget(item, target),
          ) ?? null;
        if (matchedWork) {
          await openMatch3DDraft(matchedWork, { forceDraft: true });
          return;
        }
        if (sessionId) {
          await match3dFlow.restoreDraft(sessionId);
        }
        return;
      }

      if (target.kind === 'square-hole') {
        const matchedWork =
          (squareHoleWorks.length > 0
            ? squareHoleWorks
            : (await listSquareHoleWorks().catch(() => ({ items: [] }))).items
          ).find((item) =>
            matchesSessionProfileWorkCreationUrlRestoreTarget(item, target),
          ) ?? null;
        if (matchedWork) {
          await openSquareHoleDraft(matchedWork, { forceDraft: true });
          return;
        }
        if (sessionId) {
          await squareHoleFlow.restoreDraft(sessionId);
        }
        return;
      }

      if (target.kind === 'puzzle') {
        const matchedWork =
          (puzzleWorks.length > 0
            ? puzzleWorks
            : (await listPuzzleWorks().catch(() => ({ items: [] }))).items
          ).find((item) =>
            matchesSessionProfileWorkCreationUrlRestoreTarget(item, target),
          ) ?? null;
        if (matchedWork) {
          await openPuzzleDraft(matchedWork);
          return;
        }
        if (sessionId) {
          await puzzleFlow.restoreDraft(sessionId);
        }
        return;
      }

      if (target.kind === 'visual-novel') {
        const matchedWork =
          (visualNovelWorks.length > 0
            ? visualNovelWorks
            : (await listVisualNovelWorks().catch(() => ({ works: [] }))).works
          ).find((item) =>
            matchesVisualNovelCreationUrlRestoreTarget(item, target),
          ) ?? null;
        if (matchedWork) {
          await openVisualNovelDraft(matchedWork, { forceDraft: true });
          return;
        }
        if (sessionId) {
          await visualNovelFlow.restoreDraft(sessionId);
        }
        return;
      }

      if (target.kind === 'bark-battle') {
        const matchedWork =
          (barkBattleWorks.length > 0
            ? barkBattleWorks
            : (await listBarkBattleWorks().catch(() => ({ items: [] }))).items
          ).find((item) =>
            matchesBarkBattleCreationUrlRestoreTarget(item, target),
          ) ?? null;
        if (matchedWork) {
          openBarkBattleDraft(matchedWork, { forceDraft: true });
        }
        return;
      }

      if (target.kind === 'baby-object-match') {
        const matchedDraft =
          (babyObjectMatchDrafts.length > 0
            ? babyObjectMatchDrafts
            : await listLocalBabyObjectMatchDrafts().catch(() => [])
          ).find((item) =>
            matchesBabyObjectMatchCreationUrlRestoreTarget(item, target),
          ) ?? null;
        if (matchedDraft) {
          openBabyObjectMatchDraft(matchedDraft);
        }
        return;
      }

      if (target.kind === 'jump-hop') {
        let session: JumpHopSessionSnapshotResponse | null = null;
        let work: JumpHopWorkProfileResponse | null = null;
        try {
          if (profileId) {
            work = (await jumpHopClient.getWorkDetail(profileId)).item;
          }
        } catch {
          work = null;
        }
        try {
          if (sessionId) {
            session = (await jumpHopClient.getSession(sessionId)).session;
          }
        } catch {
          session = null;
        }
        if (!session && !work) {
          return;
        }
        try {
          setJumpHopSession(session);
          setJumpHopWork(work);
          writeCreationUrlState(
            buildJumpHopCreationUrlState({ session, work }),
          );
          enterCreateTab();
          setSelectionStage(
            resolveJumpHopCreationUrlRestoreStage({
              isGeneratingPath: target.isGeneratingPath,
              hasRestoredDraft: Boolean(session?.draft),
              hasRestoredWork: Boolean(work),
            }),
          );
        } catch (error) {
          setJumpHopError(
            resolveRpgCreationErrorMessage(error, '读取跳一跳创作草稿失败。'),
          );
        }
        return;
      }

      if (target.kind === 'wooden-fish') {
        if (!sessionId) {
          return;
        }
        try {
          const { session } = await woodenFishClient.getSession(sessionId);
          let work: WoodenFishWorkProfileResponse | null = null;
          if (profileId) {
            work = (await woodenFishClient.getWorkDetail(profileId)).item;
          }
          setWoodenFishSession(session);
          setWoodenFishWork(work);
          writeCreationUrlState(
            buildWoodenFishCreationUrlState({ session, work }),
          );
          enterCreateTab();
          setSelectionStage(
            resolveWoodenFishCreationUrlRestoreStage({
              isGeneratingPath: target.isGeneratingPath,
              hasRestoredDraft: Boolean(session.draft),
            }),
          );
        } catch (error) {
          setWoodenFishError(
            resolveRpgCreationErrorMessage(error, '读取敲木鱼创作草稿失败。'),
          );
        }
      }
    };

    void restoreCreationUrlState();
  }, [
    babyObjectMatchDrafts,
    barkBattleWorks,
    bigFishFlow,
    bigFishWorks,
    enterCreateTab,
    initialCreationUrlState,
    jumpHopClient,
    match3dFlow,
    match3dWorks,
    openBabyObjectMatchDraft,
    openBarkBattleDraft,
    openBigFishDraft,
    openMatch3DDraft,
    openPuzzleDraft,
    openSquareHoleDraft,
    openVisualNovelDraft,
    platformBootstrap.canReadProtectedData,
    platformBootstrap.isLoadingPlatform,
    puzzleFlow,
    puzzleWorks,
    setSelectionStage,
    squareHoleFlow,
    squareHoleWorks,
    visualNovelFlow,
    visualNovelWorks,
    woodenFishClient,
  ]);

  const startBigFishRunFromWork = useCallback(
    async (
      item: BigFishWorkSummary,
      returnStage: BigFishRuntimeReturnStage = 'work-detail',
      options: { embedded?: boolean } = {},
    ) => {
      const sessionId = item.sourceSessionId?.trim();
      if (!sessionId) {
        setBigFishError('当前作品缺少会话信息，暂时无法进入玩法。');
        return false;
      }

      const publicWorkCode = buildBigFishPublicWorkCode(item.sourceSessionId);
      setBigFishError(null);
      bigFishFlow.setSession(null);
      setBigFishRuntimeWork(item);
      setBigFishRuntimeShare({
        title: item.title,
        publicWorkCode,
      });
      setBigFishRuntimeStartedAt(null);
      setBigFishRuntimeSessionSource('work');
      setBigFishRuntimeReturnStage(returnStage);
      setBigFishRun(null);
      try {
        const runtimeGuestOptions = await buildRecommendRuntimeAuthOptions(
          authUi,
          options.embedded,
        );
        const { run } = options.embedded
          ? await startBigFishRuntimeRun(sessionId, runtimeGuestOptions)
          : await startBigFishRuntimeRun(sessionId);
        setBigFishRuntimeStartedAt(Date.now());
        setBigFishRun(run);
        if (!options.embedded) {
          setSelectionStage('big-fish-runtime');
          pushAppHistoryPath(
            buildPublicWorkStagePath('big-fish-runtime', publicWorkCode),
          );
        }
        const recordPlayPromise = options.embedded
          ? recordBigFishPlay(sessionId, { elapsedMs: 0 }, runtimeGuestOptions)
          : recordBigFishPlay(sessionId, { elapsedMs: 0 });
        void recordPlayPromise.catch((error) => {
          setBigFishError(
            resolveBigFishErrorMessage(error, '记录大鱼吃小鱼游玩失败。'),
          );
        });
        return true;
      } catch (error) {
        setBigFishError(
          resolveBigFishErrorMessage(error, '启动大鱼吃小鱼玩法失败。'),
        );
        return false;
      }
    },
    [
      authUi,
      bigFishFlow,
      resolveBigFishErrorMessage,
      setBigFishError,
      setSelectionStage,
    ],
  );

  const startBarkBattleRunFromWork = useCallback(
    async (
      item: BarkBattleWorkSummary,
      returnStage: BarkBattleRuntimeReturnStage = 'work-detail',
      options: { embedded?: boolean } = {},
    ) => {
      if (item.status !== 'published') {
        setBarkBattleError('汪汪声浪作品发布后才能进入正式玩法。');
        return false;
      }

      setBarkBattleError(null);
      setBarkBattleGenerationPartialFailed(false);
      setBarkBattleRuntimeMode('published');
      setBarkBattlePublishedConfig(
        buildBarkBattlePublishedConfigFromWork(item),
      );
      setBarkBattleRuntimeReturnStage(returnStage);
      try {
        const runtimeGuestOptions = await buildRecommendRuntimeAuthOptions(
          authUi,
          options.embedded,
        );
        const runResponse = options.embedded
          ? await startBarkBattleRun(item.workId, {}, runtimeGuestOptions)
          : await startBarkBattleRun(item.workId);
        void runResponse;
        selectionStageRef.current = 'bark-battle-runtime';
        if (!options.embedded) {
          setSelectionStage('bark-battle-runtime');
          pushAppHistoryPath(
            buildPublicWorkStagePath(
              'bark-battle-runtime',
              buildBarkBattlePublicWorkCode(item.workId),
            ),
          );
        }
        return true;
      } catch (error) {
        setBarkBattleError(
          resolveBarkBattleErrorMessage(error, '启动汪汪声浪玩法失败。'),
        );
        return false;
      }
    },
    [authUi, resolveBarkBattleErrorMessage, setSelectionStage],
  );

  const startSelectedPublicWork = useCallback(() => {
    if (!selectedPublicWorkDetail || isPublicWorkDetailBusy) {
      return;
    }

    runProtectedAction(() => {
      const intent = resolvePlatformPublicWorkStartIntent(
        selectedPublicWorkDetail,
        {
          selectedPuzzleDetail,
          selectedRpgDetailEntry: selectedDetailEntry,
          barkBattleGalleryEntries,
          barkBattleWorks,
          mapMatch3DWork: mapPublicWorkDetailToMatch3DWork,
        },
      );

      switch (intent.type) {
        case 'blocked':
          setPublicWorkDetailError(intent.errorMessage);
          return;
        case 'start-big-fish':
          startBigFishRunFromWork(intent.work, intent.returnStage);
          return;
        case 'start-puzzle':
          setPublicWorkDetailError(null);
          void startPuzzleRunFromProfile(
            intent.work.profileId,
            intent.returnStage,
            intent.work,
            true,
            null,
            { authMode: intent.authMode },
          );
          return;
        case 'start-jump-hop':
          setPublicWorkDetailError(null);
          void startJumpHopRunFromProfile(intent.profileId, {
            returnStage: intent.returnStage,
          });
          return;
        case 'start-wooden-fish':
          setPublicWorkDetailError(null);
          void startWoodenFishRunFromProfile(intent.profileId, {
            returnStage: intent.returnStage,
          });
          return;
        case 'start-match3d':
          setPublicWorkDetailError(null);
          void startMatch3DRunFromProfile(
            intent.work,
            intent.returnStage,
            true,
          );
          return;
        case 'start-square-hole':
          setPublicWorkDetailError(null);
          void startSquareHoleRunFromProfile(
            intent.work,
            intent.returnStage,
            true,
          );
          return;
        case 'start-visual-novel':
          setPublicWorkDetailError(null);
          void startVisualNovelRunFromProfile(
            intent.profileId,
            intent.returnStage,
          );
          return;
        case 'start-bark-battle':
          setPublicWorkDetailError(null);
          startBarkBattleRunFromWork(intent.work, intent.returnStage);
          return;
        case 'start-edutainment':
          setPublicWorkDetailError(null);
          void startBabyObjectMatchRuntimeFromEntry(
            intent.entry,
            intent.returnStage,
          );
          return;
        case 'record-rpg-gallery-play':
          break;
        default: {
          const exhaustive: never = intent;
          return exhaustive;
        }
      }

      setIsPublicWorkDetailBusy(true);
      void recordRpgEntryWorldGalleryPlay(
        intent.entry.ownerUserId,
        intent.entry.profileId,
      )
        .then((updatedEntry) => {
          setSelectedDetailEntry(updatedEntry);
          setSelectedPublicWorkDetail(
            mapRpgGalleryCardToPublicWorkDetail(updatedEntry),
          );
          handleCustomWorldSelect(updatedEntry.profile);
        })
        .catch((error) => {
          setPublicWorkDetailError(
            resolveRpgCreationErrorMessage(error, '记录作品游玩失败。'),
          );
        })
        .finally(() => {
          setIsPublicWorkDetailBusy(false);
        });
    });
  }, [
    barkBattleGalleryEntries,
    barkBattleWorks,
    handleCustomWorldSelect,
    isPublicWorkDetailBusy,
    runProtectedAction,
    selectedDetailEntry,
    selectedPuzzleDetail,
    selectedPublicWorkDetail,
    startBarkBattleRunFromWork,
    startBigFishRunFromWork,
    startJumpHopRunFromProfile,
    startWoodenFishRunFromProfile,
    startPuzzleRunFromProfile,
    startMatch3DRunFromProfile,
    startSquareHoleRunFromProfile,
    startBabyObjectMatchRuntimeFromEntry,
    startVisualNovelRunFromProfile,
  ]);

  const selectRecommendRuntimeEntry = useCallback(
    async (entry: PlatformPublicGalleryCard) => {
      const entryKey = getPlatformPublicGalleryEntryKey(entry);
      const runtimeKind = getPlatformRecommendRuntimeKind(entry);
      const startRequestId = recommendRuntimeStartRequestRef.current + 1;
      recommendRuntimeStartRequestRef.current = startRequestId;
      const isCurrentStartRequest = () =>
        recommendRuntimeStartRequestRef.current === startRequestId;
      setActiveRecommendEntryKey(entryKey);
      setActiveRecommendRuntimeKind(runtimeKind);
      setActiveRecommendRuntimeError(null);
      setIsStartingRecommendEntry(true);
      if (entryKey !== activeRecommendEntryKey) {
        await saveAndExitRecommendPuzzleRuntime();
        if (!isCurrentStartRequest()) {
          return;
        }
      }
      setActiveRecommendEntryKey(entryKey);
      setActiveRecommendRuntimeKind(runtimeKind);
      setActiveRecommendRuntimeError(null);
      setIsStartingRecommendEntry(true);

      try {
        let started = false;
        const intent = resolvePlatformRecommendRuntimeStartIntent(entry, {
          selectedPuzzleDetail,
          barkBattleGalleryEntries,
          mapMatch3DWork: mapPublicWorkDetailToMatch3DWork,
        });

        switch (intent.type) {
          case 'blocked':
            if (intent.errorTarget === 'big-fish') {
              setBigFishError(intent.errorMessage);
            } else if (intent.errorTarget === 'puzzle') {
              setPuzzleError(intent.errorMessage);
            } else if (intent.errorTarget === 'match3d') {
              setMatch3DError(intent.errorMessage);
            } else if (intent.errorTarget === 'square-hole') {
              setSquareHoleError(intent.errorMessage);
            } else {
              setBarkBattleError(intent.errorMessage);
            }
            break;
          case 'start-big-fish':
            started = await startBigFishRunFromWork(intent.work, 'platform', {
              embedded: intent.embedded,
            });
            break;
          case 'start-puzzle':
            started = await startPuzzleRunFromProfile(
              intent.work.profileId,
              intent.returnStage,
              intent.work,
              false,
              null,
              { embedded: intent.embedded },
            );
            break;
          case 'start-jump-hop':
            started = await startJumpHopRunFromProfile(intent.profileId, {
              embedded: intent.embedded,
              returnStage: intent.returnStage,
            });
            break;
          case 'start-wooden-fish':
            started = await startWoodenFishRunFromProfile(intent.profileId, {
              embedded: intent.embedded,
              returnStage: intent.returnStage,
            });
            break;
          case 'start-match3d':
            started = await startMatch3DRunFromProfile(
              intent.work,
              intent.returnStage,
              false,
              { embedded: intent.embedded },
            );
            break;
          case 'start-square-hole':
            started = await startSquareHoleRunFromProfile(
              intent.work,
              intent.returnStage,
              false,
              { embedded: intent.embedded },
            );
            break;
          case 'start-visual-novel':
            started = await startVisualNovelRunFromProfile(
              intent.profileId,
              intent.returnStage,
              { embedded: intent.embedded },
            );
            break;
          case 'start-bark-battle':
            started = await startBarkBattleRunFromWork(
              intent.work,
              intent.returnStage,
              { embedded: intent.embedded },
            );
            break;
          case 'start-edutainment':
            started = await startBabyObjectMatchRuntimeFromEntry(
              intent.entry,
              intent.returnStage,
              {
                embedded: intent.embedded,
              },
            );
            break;
          case 'mark-ready':
            started = true;
            break;
          default: {
            const exhaustive: never = intent;
            return exhaustive;
          }
        }

        if (!isCurrentStartRequest()) {
          return;
        }

        if (started) {
          setActiveRecommendRuntimeKind(runtimeKind);
          setActiveRecommendRuntimeError(null);
        } else {
          setActiveRecommendRuntimeKind(null);
          setActiveRecommendRuntimeError('作品暂时无法进入，请稍后再试。');
        }
      } catch (error) {
        if (!isCurrentStartRequest()) {
          return;
        }

        setActiveRecommendRuntimeKind(null);
        setActiveRecommendRuntimeError('作品暂时无法进入，请稍后再试。');
      } finally {
        if (isCurrentStartRequest()) {
          setIsStartingRecommendEntry(false);
        }
      }
    },
    [
      activeRecommendEntryKey,
      barkBattleGalleryEntries,
      saveAndExitRecommendPuzzleRuntime,
      selectedPuzzleDetail,
      setBarkBattleError,
      setBigFishError,
      setMatch3DError,
      setPuzzleError,
      setSquareHoleError,
      startBarkBattleRunFromWork,
      startBigFishRunFromWork,
      startJumpHopRunFromProfile,
      startWoodenFishRunFromProfile,
      startMatch3DRunFromProfile,
      startPuzzleRunFromProfile,
      startSquareHoleRunFromProfile,
      startBabyObjectMatchRuntimeFromEntry,
      startVisualNovelRunFromProfile,
    ],
  );
  const selectAdjacentRecommendRuntimeEntry = useCallback(
    (direction: 1 | -1, baseEntryKey?: string | null) => {
      const normalizedBaseEntryKey =
        baseEntryKey?.trim() || activeRecommendEntryKey;
      const nextEntry = selectAdjacentPlatformRecommendEntry(
        recommendRuntimeEntries,
        direction,
        normalizedBaseEntryKey,
      );
      if (!nextEntry) {
        return;
      }

      void selectRecommendRuntimeEntry(nextEntry);
    },
    [
      activeRecommendEntryKey,
      recommendRuntimeEntries,
      selectRecommendRuntimeEntry,
    ],
  );

  const recommendRuntimeContent = useMemo(() => {
    if (
      isDesktopLayout ||
      selectionStage !== 'platform' ||
      platformBootstrap.platformTab !== 'home' ||
      !activeRecommendRuntimeKind
    ) {
      return null;
    }

    const activeEntry =
      recommendRuntimeEntries.find(
        (entry) =>
          getPlatformPublicGalleryEntryKey(entry) === activeRecommendEntryKey,
      ) ?? null;
    if (!activeEntry) {
      return null;
    }

    if (activeRecommendRuntimeKind === 'big-fish') {
      return (
        <BigFishRuntimeShell
          run={bigFishRun}
          assetSlots={bigFishSession?.assetSlots ?? []}
          shareTitle={bigFishRuntimeShare?.title ?? null}
          sharePublicWorkCode={bigFishRuntimeShare?.publicWorkCode ?? null}
          isBusy={isBigFishBusy}
          error={bigFishError}
          embedded
          onBack={() => {
            reportBigFishObservedPlayTime();
            setActiveRecommendRuntimeKind(null);
          }}
          onRestart={() => {
            reportBigFishObservedPlayTime();
            void restartBigFishRun();
          }}
          onSubmitInput={submitBigFishInput}
        />
      );
    }

    if (activeRecommendRuntimeKind === 'match3d') {
      const activeMatch3DRuntimeProfile = resolveActiveMatch3DRuntimeProfile(
        match3dRun,
        match3dRuntimeProfile,
        match3dProfile,
      );
      return (
        <Match3DRuntimeShell
          run={match3dRun}
          isBusy={isMatch3DBusy}
          error={match3dError}
          embedded
          hideBackButton
          levelName={
            activeMatch3DRuntimeProfile?.gameName?.trim() ||
            activeEntry.worldName
          }
          generatedItemAssets={resolveMatch3DRuntimeGeneratedItemAssets(
            match3dRun,
            activeMatch3DRuntimeProfile,
            activeEntry,
          )}
          generatedBackgroundAsset={resolveMatch3DRuntimeGeneratedBackgroundAsset(
            match3dRun,
            activeMatch3DRuntimeProfile,
            activeEntry,
          )}
          backgroundImageSrc={resolveMatch3DRuntimeBackgroundImageSrc(
            match3dRun,
            activeMatch3DRuntimeProfile,
            activeEntry,
          )}
          onBack={() => {
            setActiveRecommendRuntimeKind(null);
          }}
          onRestart={() => {
            if (!match3dRun?.runId || isMatch3DBusy) {
              return;
            }

            match3dFlow.setIsBusy(true);
            setMatch3DError(null);
            void resolveMatch3DRuntimeAdapter(
              activeMatch3DRuntimeProfile?.profileId,
            )
              .restartRun(match3dRun.runId)
              .then(({ run }) => {
                setMatch3DRun(run);
              })
              .catch((error) => {
                setMatch3DError(
                  resolveMatch3DErrorMessage(error, '重新开始抓大鹅玩法失败。'),
                );
              })
              .finally(() => {
                match3dFlow.setIsBusy(false);
              });
          }}
          onOptimisticRunChange={setMatch3DRun}
          onClickItem={(payload) => {
            const runId = payload.runId ?? match3dRun?.runId;
            if (!runId) {
              return Promise.reject(new Error('抓大鹅运行态缺少 runId。'));
            }
            return resolveMatch3DRuntimeAdapter(
              activeMatch3DRuntimeProfile?.profileId,
            ).clickItem(runId, payload);
          }}
          onTimeExpired={() => {
            if (!match3dRun?.runId) {
              return;
            }

            void resolveMatch3DRuntimeAdapter(
              activeMatch3DRuntimeProfile?.profileId,
            )
              .finishTimeUp(match3dRun.runId)
              .then(({ run }) => {
                setMatch3DRun(run);
              })
              .catch((error) => {
                setMatch3DError(
                  resolveMatch3DErrorMessage(error, '同步抓大鹅倒计时失败。'),
                );
              });
          }}
        />
      );
    }

    if (activeRecommendRuntimeKind === 'puzzle') {
      return (
        <PuzzleRuntimeShell
          run={puzzleRun}
          isBusy={
            isPuzzleBusy ||
            isPuzzleNextLevelGenerating ||
            isPuzzleLeaderboardBusy
          }
          error={puzzleError}
          embedded
          hideBackButton
          hideExitControls
          onBack={() => {
            setActiveRecommendRuntimeKind(null);
          }}
          onRemodelWork={
            selectedPuzzleDetail?.publicationStatus === 'published'
              ? remodelCurrentPuzzleRuntimeWork
              : undefined
          }
          onSwapPieces={(payload) => {
            void swapPuzzlePiecesInRun(payload);
          }}
          onDragPiece={(payload) => {
            void dragPuzzlePiece(payload);
          }}
          onAdvanceNextLevel={(target) => {
            void advancePuzzleLevel(target);
          }}
          onRestartLevel={() => {
            void restartPuzzleCurrentLevel();
          }}
          onPauseChange={setPuzzleRuntimePaused}
          onUseProp={usePuzzleProp}
          onTimeExpired={syncPuzzleRuntimeTimeout}
        />
      );
    }

    if (activeRecommendRuntimeKind === 'jump-hop') {
      return (
        <JumpHopRuntimeShell
          profile={jumpHopWork}
          run={jumpHopRun}
          isBusy={isJumpHopBusy}
          error={jumpHopError}
          onBack={() => {
            setActiveRecommendRuntimeKind(null);
          }}
          onRestart={() => {
            if (!jumpHopRun?.runId || isJumpHopBusy) {
              return;
            }

            setIsJumpHopBusy(true);
            setJumpHopError(null);
            void jumpHopClient
              .restartRun(jumpHopRun.runId)
              .then((response) => {
                setJumpHopRun(response.run);
              })
              .catch((error) => {
                setJumpHopError(
                  resolveRpgCreationErrorMessage(error, '重新开始跳一跳失败。'),
                );
              })
              .finally(() => {
                setIsJumpHopBusy(false);
              });
          }}
          onJump={async (payload) => {
            const runId = jumpHopRun?.runId;
            if (!runId) {
              throw new Error('跳一跳运行态缺少 runId。');
            }
            const response = await jumpHopClient.submitJump(runId, payload);
            setJumpHopRun(response.run);
          }}
        />
      );
    }

    if (activeRecommendRuntimeKind === 'wooden-fish') {
      return (
        <WoodenFishRuntimeShell
          profile={woodenFishWork}
          run={woodenFishRun}
          isBusy={isWoodenFishBusy}
          error={woodenFishError}
          onBack={() => {
            setActiveRecommendRuntimeKind(null);
          }}
          onCheckpoint={checkpointWoodenFishRuntimeRun}
        />
      );
    }

    if (activeRecommendRuntimeKind === 'square-hole') {
      return (
        <SquareHoleRuntimeShell
          run={squareHoleRun}
          isBusy={isSquareHoleBusy}
          error={squareHoleError}
          embedded
          onBack={() => {
            if (
              squareHoleRun?.runId &&
              squareHoleRun.status.toLowerCase() === 'running'
            ) {
              void stopSquareHoleRun(squareHoleRun.runId).catch(
                () => undefined,
              );
            }
            setActiveRecommendRuntimeKind(null);
          }}
          onRestart={() => {
            if (!squareHoleRun?.runId || isSquareHoleBusy) {
              return;
            }

            squareHoleFlow.setIsBusy(true);
            setSquareHoleError(null);
            void restartSquareHoleRun(squareHoleRun.runId)
              .then(({ run }) => {
                setSquareHoleRun(run);
              })
              .catch((error) => {
                setSquareHoleError(
                  resolveSquareHoleErrorMessage(
                    error,
                    '重新开始方洞挑战失败。',
                  ),
                );
              })
              .finally(() => {
                squareHoleFlow.setIsBusy(false);
              });
          }}
          onOptimisticRunChange={setSquareHoleRun}
          onDropShape={(payload) => {
            const runId = payload.runId ?? squareHoleRun?.runId;
            if (!runId) {
              return Promise.reject(new Error('方洞挑战运行态缺少 runId。'));
            }
            return dropSquareHoleShape(runId, payload);
          }}
          onTimeExpired={() => {
            if (!squareHoleRun?.runId) {
              return;
            }

            void finishSquareHoleTimeUp(squareHoleRun.runId)
              .then(({ run }) => {
                setSquareHoleRun(run);
              })
              .catch((error) => {
                setSquareHoleError(
                  resolveSquareHoleErrorMessage(
                    error,
                    '同步方洞挑战倒计时失败。',
                  ),
                );
              });
          }}
        />
      );
    }

    if (activeRecommendRuntimeKind === 'visual-novel') {
      return (
        <VisualNovelRuntimeShell
          draft={visualNovelWork?.draft ?? visualNovelSession?.draft}
          run={visualNovelRun}
          isBusy={isVisualNovelBusy}
          error={visualNovelError}
          embedded
          onBack={() => {
            setActiveRecommendRuntimeKind(null);
          }}
          onSubmitAction={(payload) => {
            void submitVisualNovelRuntimeAction(payload);
          }}
        />
      );
    }

    if (
      activeRecommendRuntimeKind === 'bark-battle' &&
      barkBattlePublishedConfig
    ) {
      return (
        <BarkBattleRuntimeShell
          title={barkBattlePublishedConfig.title}
          workId={barkBattlePublishedConfig.workId}
          publishedConfig={barkBattlePublishedConfig}
          runtimeMode="published"
          onExit={() => {
            setActiveRecommendRuntimeKind(null);
          }}
        />
      );
    }

    if (activeRecommendRuntimeKind === 'edutainment' && babyObjectMatchDraft) {
      return (
        <BabyObjectMatchRuntimeShell
          draft={babyObjectMatchDraft}
          embedded
          onBack={() => {
            setActiveRecommendRuntimeKind(null);
          }}
        />
      );
    }

    return (
      <div
        className={`platform-theme ${platformThemeClass} flex h-full min-h-0 items-center justify-center bg-[var(--platform-recommend-runtime-state-fill)] px-5 text-center text-sm font-semibold leading-6 text-[var(--platform-recommend-runtime-state-text)]`}
      >
        正在读取世界
      </div>
    );
  }, [
    activeRecommendEntryKey,
    activeRecommendRuntimeKind,
    barkBattlePublishedConfig,
    babyObjectMatchDraft,
    bigFishError,
    bigFishRun,
    bigFishRuntimeShare,
    bigFishSession?.assetSlots,
    isBigFishBusy,
    isJumpHopBusy,
    isMatch3DBusy,
    isPuzzleBusy,
    isPuzzleLeaderboardBusy,
    isPuzzleNextLevelGenerating,
    isSquareHoleBusy,
    isVisualNovelBusy,
    match3dError,
    match3dFlow,
    match3dProfile,
    match3dRun,
    match3dRuntimeProfile,
    match3dRuntimeAdapter,
    platformBootstrap.platformTab,
    jumpHopError,
    jumpHopRun,
    jumpHopWork,
    isWoodenFishBusy,
    woodenFishError,
    woodenFishRun,
    woodenFishWork,
    platformThemeClass,
    puzzleError,
    puzzleRun,
    recommendRuntimeEntries,
    remodelCurrentPuzzleRuntimeWork,
    resolveMatch3DErrorMessage,
    resolveSquareHoleErrorMessage,
    reportBigFishObservedPlayTime,
    restartBigFishRun,
    selectedPuzzleDetail,
    selectionStage,
    setMatch3DError,
    setMatch3DRun,
    setPuzzleRuntimePaused,
    setSquareHoleRun,
    squareHoleError,
    squareHoleFlow,
    squareHoleRun,
    submitBigFishInput,
    submitVisualNovelRuntimeAction,
    advancePuzzleLevel,
    dragPuzzlePiece,
    restartPuzzleCurrentLevel,
    setSquareHoleError,
    swapPuzzlePiecesInRun,
    syncPuzzleRuntimeTimeout,
    usePuzzleProp,
    visualNovelError,
    visualNovelRun,
    visualNovelSession,
    visualNovelWork,
    checkpointWoodenFishRuntimeRun,
    isDesktopLayout,
  ]);

  useEffect(() => {
    const decision = resolvePlatformRecommendRuntimeAutoStartDecision({
      isDesktopLayout,
      selectionStage,
      platformTab: platformBootstrap.platformTab,
      isLoadingPlatform: platformBootstrap.isLoadingPlatform,
      entries: recommendRuntimeEntries,
      activeEntryKey: activeRecommendEntryKey,
      isStarting: isStartingRecommendEntry,
      readyState: {
        activeKind: activeRecommendRuntimeKind,
        hasBabyObjectMatchDraft: Boolean(babyObjectMatchDraft),
        hasBigFishRun: Boolean(bigFishRun),
        hasJumpHopRun: Boolean(jumpHopRun),
        hasMatch3DRun: Boolean(match3dRun),
        hasSquareHoleRun: Boolean(squareHoleRun),
        hasVisualNovelRun: Boolean(visualNovelRun),
        hasWoodenFishRun: Boolean(woodenFishRun),
        puzzleRunEntryProfileId: puzzleRun?.entryProfileId ?? null,
        puzzleRunCurrentLevelProfileId:
          puzzleRun?.currentLevel?.profileId ?? null,
      },
    });

    if (decision.type === 'noop') {
      return;
    }

    if (decision.type === 'clear') {
      setActiveRecommendEntryKey(null);
      setActiveRecommendRuntimeKind(null);
      setActiveRecommendRuntimeError(null);
      return;
    }

    void selectRecommendRuntimeEntry(decision.entry);
  }, [
    activeRecommendEntryKey,
    activeRecommendRuntimeKind,
    babyObjectMatchDraft,
    bigFishRun,
    jumpHopRun,
    isStartingRecommendEntry,
    match3dRun,
    platformBootstrap.isLoadingPlatform,
    platformBootstrap.platformTab,
    isDesktopLayout,
    puzzleRun,
    recommendRuntimeEntries,
    selectRecommendRuntimeEntry,
    selectionStage,
    squareHoleRun,
    visualNovelRun,
    woodenFishRun,
  ]);

  const remixPublicWork = useCallback(
    (entry: PlatformPublicGalleryCard) => {
      if (isPublicWorkDetailBusy) {
        return;
      }

      runProtectedAction(() => {
        setIsPublicWorkDetailBusy(true);
        setPublicWorkDetailError(null);

        const intent = resolvePlatformPublicWorkRemixIntent(entry);

        if (intent.type === 'remix-big-fish') {
          void remixBigFishGalleryWork(intent.profileId)
            .then((response) => {
              bigFishFlow.setSession(response.session);
              enterCreateTab();
              setSelectionStage(intent.selectionStage);
            })
            .catch((error) => {
              setPublicWorkDetailError(
                resolveBigFishErrorMessage(error, 'Remix 大鱼吃小鱼作品失败。'),
              );
            })
            .finally(() => {
              setIsPublicWorkDetailBusy(false);
            });
          return;
        }

        if (intent.type === 'remix-puzzle') {
          void remixPuzzleGalleryWork(intent.profileId)
            .then((response) => {
              resetRecommendRuntimeSelection();
              puzzleFlow.setSession(response.session);
              setPuzzleOperation(null);
              enterCreateTab();
              setSelectionStage(intent.selectionStage);
            })
            .catch((error) => {
              setPublicWorkDetailError(
                resolvePuzzleErrorMessage(error, 'Remix 拼图作品失败。'),
              );
            })
            .finally(() => {
              setIsPublicWorkDetailBusy(false);
            });
          return;
        }

        if (intent.type === 'unsupported') {
          setPublicWorkDetailError(intent.errorMessage);
          setIsPublicWorkDetailBusy(false);
          return;
        }

        void remixRpgEntryWorldGallery(intent.ownerUserId, intent.profileId)
          .then((response) => {
            const nextEntry = response.entry;
            setSelectedDetailEntry(nextEntry);
            platformBootstrap.setSavedCustomWorldEntries([
              nextEntry,
              ...platformBootstrap.savedCustomWorldEntries.filter(
                (entry) => entry.profileId !== nextEntry.profileId,
              ),
            ]);
            void detailNavigation.openSavedCustomWorldEditor(nextEntry);
          })
          .catch((error) => {
            setPublicWorkDetailError(
              resolveRpgCreationErrorMessage(error, 'Remix RPG 作品失败。'),
            );
          })
          .finally(() => {
            setIsPublicWorkDetailBusy(false);
          });
      });
    },
    [
      bigFishFlow,
      detailNavigation,
      enterCreateTab,
      isPublicWorkDetailBusy,
      platformBootstrap,
      puzzleFlow,
      resetRecommendRuntimeSelection,
      resolveBigFishErrorMessage,
      resolvePuzzleErrorMessage,
      runProtectedAction,
      setSelectionStage,
    ],
  );

  const editOwnedPublicWork = useCallback(
    (entry: PlatformPublicGalleryCard) => {
      if (isPublicWorkDetailBusy) {
        return;
      }

      runProtectedAction(async () => {
        setPublicWorkDetailError(null);

        const intent = resolvePlatformPublicWorkEditIntent(entry, {
          selectedPuzzleDetail,
          selectedRpgDetailEntry: selectedDetailEntry,
          visualNovelWorks,
          barkBattleGalleryEntries,
          barkBattleWorks,
          mapMatch3DWork: mapPublicWorkDetailToMatch3DWork,
        });

        switch (intent.type) {
          case 'blocked':
            setPublicWorkDetailError(intent.errorMessage);
            return;
          case 'edit-big-fish':
            void openBigFishDraft(intent.work);
            return;
          case 'edit-puzzle':
            void openPuzzleDraft(intent.work);
            return;
          case 'edit-match3d':
            void openMatch3DDraft(intent.work, {
              forceDraft: intent.forceDraft,
            });
            return;
          case 'edit-square-hole':
            void openSquareHoleDraft(intent.work, {
              forceDraft: intent.forceDraft,
            });
            return;
          case 'edit-visual-novel':
            void openVisualNovelDraft(intent.work, {
              forceDraft: intent.forceDraft,
            });
            return;
          case 'resolve-edutainment-draft': {
            const matchedDraft = await resolveBabyObjectMatchRuntimeDraft(
              intent.entry,
            );
            if (!matchedDraft) {
              setPublicWorkDetailError('这份宝贝识物缺少可编辑草稿。');
              return;
            }

            openBabyObjectMatchDraft(matchedDraft);
            return;
          }
          case 'edit-bark-battle':
            openBarkBattleDraft(intent.work, {
              forceDraft: intent.forceDraft,
            });
            return;
          case 'edit-rpg-gallery':
            void detailNavigation.openSavedCustomWorldEditor(intent.entry);
            return;
          default: {
            const exhaustive: never = intent;
            return exhaustive;
          }
        }
      });
    },
    [
      detailNavigation,
      isPublicWorkDetailBusy,
      openBigFishDraft,
      openMatch3DDraft,
      openPuzzleDraft,
      openSquareHoleDraft,
      openVisualNovelDraft,
      barkBattleGalleryEntries,
      barkBattleWorks,
      openBabyObjectMatchDraft,
      openBarkBattleDraft,
      resolveBabyObjectMatchRuntimeDraft,
      runProtectedAction,
      selectedDetailEntry,
      selectedPuzzleDetail,
      visualNovelWorks,
    ],
  );

  const remixSelectedPublicWork = useCallback(() => {
    if (!selectedPublicWorkDetail) {
      return;
    }
    if (isSelectedPublicWorkOwned) {
      editOwnedPublicWork(selectedPublicWorkDetail);
      return;
    }
    remixPublicWork(selectedPublicWorkDetail);
  }, [
    editOwnedPublicWork,
    isSelectedPublicWorkOwned,
    remixPublicWork,
    selectedPublicWorkDetail,
  ]);

  const handlePublicCodeSearch = useCallback(
    async (keyword: string) => {
      const searchPlan = resolvePlatformPublicCodeSearchPlan(keyword);
      if (!searchPlan) {
        return;
      }

      const { normalizedKeyword } = searchPlan;

      setIsSearchingPublicCode(true);
      setPublicSearchError(null);
      setSearchedPublicUser(null);

      const tryOpenGalleryEntry = async () => {
        const entry =
          await getRpgEntryWorldGalleryDetailByCode(normalizedKeyword);
        const card = {
          ownerUserId: entry.ownerUserId,
          profileId: entry.profileId,
          publicWorkCode: entry.publicWorkCode,
          authorPublicUserCode: entry.authorPublicUserCode,
          visibility: 'published',
          publishedAt: entry.publishedAt,
          updatedAt: entry.updatedAt,
          authorDisplayName: entry.authorDisplayName,
          worldName: entry.worldName,
          subtitle: entry.subtitle,
          summaryText: entry.summaryText,
          coverImageSrc: entry.coverImageSrc,
          themeMode: entry.themeMode,
          playableNpcCount: entry.playableNpcCount,
          landmarkCount: entry.landmarkCount,
          playCount: entry.playCount ?? 0,
          remixCount: entry.remixCount ?? 0,
          likeCount: entry.likeCount ?? 0,
        } satisfies CustomWorldGalleryCard;
        if (!canExposePublicWork(card)) {
          throw new Error(EDUTAINMENT_HIDDEN_MESSAGE);
        }

        setSelectedDetailEntry(entry);
        openPublicWorkDetail(card);
      };
      const tryOpenPuzzleGalleryEntry = async () => {
        const entries =
          puzzleGalleryEntries.length > 0
            ? puzzleGalleryEntries
            : await refreshPuzzleGallery();
        const matchedEntry = entries
          .map(mapPuzzleWorkToPublicWorkDetail)
          .filter(canExposePublicWork)
          .find((entry) =>
            isSamePuzzlePublicWorkCode(normalizedKeyword, entry.profileId),
          );

        if (!matchedEntry) {
          throw new Error('未找到拼图作品。');
        }

        await openPuzzlePublicWorkDetail(matchedEntry.profileId, {
          tab: platformBootstrap.platformTab,
        });
      };
      const tryOpenBigFishGalleryEntry = async () => {
        const entries =
          bigFishGalleryEntries.length > 0
            ? bigFishGalleryEntries
            : await refreshBigFishGallery();
        const matchedEntry = entries.find((entry) => {
          const detailEntry = mapBigFishWorkToPublicWorkDetail(entry);
          return (
            canExposePublicWork(detailEntry) &&
            isSameBigFishPublicWorkCode(
              normalizedKeyword,
              entry.sourceSessionId,
            )
          );
        });

        if (!matchedEntry) {
          throw new Error('未找到大鱼吃小鱼作品。');
        }

        openPublicWorkDetail(mapBigFishWorkToPublicWorkDetail(matchedEntry));
      };
      const tryOpenJumpHopGalleryEntry = async () => {
        const entries =
          jumpHopGalleryEntries.length > 0
            ? jumpHopGalleryEntries
            : await refreshJumpHopGallery();
        const matchedEntry = entries.find((entry) => {
          const detailEntry = mapJumpHopWorkToPublicWorkDetail(entry);
          return (
            canExposePublicWork(detailEntry) &&
            isSameJumpHopPublicWorkCode(normalizedKeyword, entry.profileId)
          );
        });

        if (!matchedEntry) {
          throw new Error('未找到跳一跳作品。');
        }

        openPublicWorkDetail(mapJumpHopWorkToPublicWorkDetail(matchedEntry));
      };
      const tryOpenWoodenFishGalleryEntry = async () => {
        const entries =
          woodenFishGalleryEntries.length > 0
            ? woodenFishGalleryEntries
            : await refreshWoodenFishGallery();
        const matchedEntry = entries.find((entry) => {
          const detailEntry = mapWoodenFishWorkToPublicWorkDetail(entry);
          return (
            canExposePublicWork(detailEntry) &&
            isSameWoodenFishPublicWorkCode(normalizedKeyword, entry.profileId)
          );
        });

        if (!matchedEntry) {
          throw new Error('未找到敲木鱼作品。');
        }

        openPublicWorkDetail(mapWoodenFishWorkToPublicWorkDetail(matchedEntry));
      };
      const tryOpenMatch3DGalleryEntry = async () => {
        const entries =
          match3dGalleryEntries.length > 0
            ? match3dGalleryEntries
            : await refreshMatch3DGallery();
        const matchedEntry = entries.find((entry) => {
          const detailEntry = mapMatch3DWorkToPublicWorkDetail(entry);
          return (
            canExposePublicWork(detailEntry) &&
            isSameMatch3DPublicWorkCode(normalizedKeyword, entry.profileId)
          );
        });

        if (!matchedEntry) {
          throw new Error('未找到抓大鹅作品。');
        }

        openPublicWorkDetail(mapMatch3DWorkToPublicWorkDetail(matchedEntry));
      };
      const tryOpenSquareHoleGalleryEntry = async () => {
        const entries =
          squareHoleGalleryEntries.length > 0
            ? squareHoleGalleryEntries
            : await refreshSquareHoleGallery();
        const matchedEntry = entries.find((entry) => {
          const detailEntry = mapSquareHoleWorkToPublicWorkDetail(entry);
          return (
            canExposePublicWork(detailEntry) &&
            isSameSquareHolePublicWorkCode(normalizedKeyword, entry.profileId)
          );
        });

        if (!matchedEntry) {
          throw new Error('未找到方洞挑战作品。');
        }

        openPublicWorkDetail(mapSquareHoleWorkToPublicWorkDetail(matchedEntry));
      };
      const tryOpenVisualNovelGalleryEntry = async () => {
        const entries =
          visualNovelGalleryEntries.length > 0
            ? visualNovelGalleryEntries
            : await refreshVisualNovelGallery();
        const matchedEntry = entries.find((entry) => {
          const detailEntry = mapVisualNovelWorkToPublicWorkDetail(entry);
          return (
            canExposePublicWork(detailEntry) &&
            isSameVisualNovelPublicWorkCode(normalizedKeyword, entry.profileId)
          );
        });

        if (!matchedEntry) {
          throw new Error('未找到视觉小说作品。');
        }

        openPublicWorkDetail(
          mapVisualNovelWorkToPublicWorkDetail(matchedEntry),
        );
      };
      const tryOpenBabyObjectMatchGalleryEntry = async () => {
        const entries = (await listLocalBabyObjectMatchDrafts()).filter(
          (draft) => draft.publicationStatus === 'published',
        );
        const matchedDraft = entries.find((draft) => {
          const detailEntry =
            mapBabyObjectMatchDraftToPlatformGalleryCard(draft);
          return (
            canExposePublicWork(detailEntry) &&
            isSameBabyObjectMatchPublicWorkCode(
              normalizedKeyword,
              draft.profileId,
            )
          );
        });

        if (!matchedDraft) {
          throw new Error('未找到宝贝识物作品。');
        }

        const detailEntry =
          mapBabyObjectMatchDraftToPlatformGalleryCard(matchedDraft);
        setBabyObjectMatchDraft(matchedDraft);
        openPublicWorkDetail(detailEntry);
      };
      const tryOpenBarkBattleGalleryEntry = async () => {
        const entries =
          barkBattleGalleryEntries.length > 0
            ? barkBattleGalleryEntries
            : await refreshBarkBattleGallery();
        const matchedEntry = entries.find((entry) => {
          const detailEntry = mapBarkBattleWorkToPlatformGalleryCard(entry);
          return (
            canExposePublicWork(detailEntry) &&
            isSameBarkBattlePublicWorkCode(normalizedKeyword, entry.workId)
          );
        });

        if (!matchedEntry) {
          throw new Error('未找到汪汪声浪作品。');
        }

        if (selectionStage === 'bark-battle-runtime') {
          startBarkBattleRunFromWork(matchedEntry, 'platform');
          return;
        }

        openPublicWorkDetail(
          mapBarkBattleWorkToPlatformGalleryCard(matchedEntry),
        );
      };

      const runSearchStep = async (step: PlatformPublicCodeSearchStep) => {
        switch (step) {
          case 'user-id': {
            const user = await getPublicAuthUserById(normalizedKeyword);
            setSearchedPublicUser(user);
            return;
          }
          case 'public-user-code': {
            const user = await getPublicAuthUserByCode(normalizedKeyword);
            setSearchedPublicUser(user);
            return;
          }
          case 'rpg-work':
            await tryOpenGalleryEntry();
            return;
          case 'puzzle-work':
            await tryOpenPuzzleGalleryEntry();
            return;
          case 'big-fish-work':
            await tryOpenBigFishGalleryEntry();
            return;
          case 'jump-hop-work':
            await tryOpenJumpHopGalleryEntry();
            return;
          case 'wooden-fish-work':
            await tryOpenWoodenFishGalleryEntry();
            return;
          case 'baby-object-match-work':
            await tryOpenBabyObjectMatchGalleryEntry();
            return;
          case 'match3d-work':
            await tryOpenMatch3DGalleryEntry();
            return;
          case 'square-hole-work':
            await tryOpenSquareHoleGalleryEntry();
            return;
          case 'visual-novel-work':
            await tryOpenVisualNovelGalleryEntry();
            return;
          case 'bark-battle-work':
            await tryOpenBarkBattleGalleryEntry();
            return;
          default: {
            const exhaustive: never = step;
            return exhaustive;
          }
        }
      };

      try {
        for (const [index, step] of searchPlan.steps.entries()) {
          try {
            await runSearchStep(step);
            return;
          } catch (error) {
            if (index === searchPlan.steps.length - 1) {
              throw error;
            }
          }
        }
      } catch (error) {
        if (selectionStage === 'work-detail') {
          setSelectedPublicWorkDetail(null);
          setSelectedDetailEntry(null);
          setSelectedPuzzleDetail(null);
          setPuzzleDetailReturnTarget(null);
          setPuzzleRun(null);
          setPuzzleRuntimeAuthMode('default');
          setPuzzleError(null);
          setPublicWorkDetailError(null);
          returnPlatformHomeAfterMissingWork();
          return;
        }

        setPublicSearchError(
          resolveRpgCreationErrorMessage(error, '未找到对应的陶泥号或作品号。'),
        );
      } finally {
        setIsSearchingPublicCode(false);
      }
    },
    [
      barkBattleGalleryEntries,
      bigFishGalleryEntries,
      jumpHopGalleryEntries,
      match3dGalleryEntries,
      refreshMatch3DGallery,
      openPuzzlePublicWorkDetail,
      openPublicWorkDetail,
      platformBootstrap.platformTab,
      puzzleGalleryEntries,
      refreshBarkBattleGallery,
      refreshBigFishGallery,
      refreshJumpHopGallery,
      refreshWoodenFishGallery,
      refreshPuzzleGallery,
      refreshSquareHoleGallery,
      refreshVisualNovelGallery,
      squareHoleGalleryEntries,
      returnPlatformHomeAfterMissingWork,
      selectionStage,
      setPlatformTab,
      setPuzzleError,
      setSelectionStage,
      startBarkBattleRunFromWork,
      visualNovelGalleryEntries,
      woodenFishGalleryEntries,
    ],
  );

  const openProfilePlayedWorks = useCallback(() => {
    setIsProfilePlayStatsOpen(true);
    setIsProfilePlayStatsLoading(true);
    setProfilePlayStatsError(null);

    void getRpgProfilePlayStats()
      .then(setProfilePlayStats)
      .catch((error) => {
        setProfilePlayStats(null);
        setProfilePlayStatsError(
          resolveRpgCreationErrorMessage(error, '读取玩过作品失败。'),
        );
      })
      .finally(() => {
        setIsProfilePlayStatsLoading(false);
      });
  }, []);

  const openPlayedWork = useCallback(
    (work: ProfilePlayedWorkSummary) => {
      const intent = resolvePlatformPlayedWorkOpenIntent(work);
      setIsProfilePlayStatsOpen(false);

      switch (intent.type) {
        case 'noop':
          return;
        case 'open-puzzle':
          void openPuzzlePublicWorkDetail(intent.profileId, {
            tab: intent.tab,
          });
          return;
        case 'open-match3d':
          void openMatch3DPublicWorkDetail(intent.profileId);
          return;
        case 'open-square-hole':
          void openSquareHolePublicWorkDetail(intent.profileId);
          return;
        case 'open-jump-hop':
          void openJumpHopPublicWorkDetail(intent.profileId);
          return;
        case 'open-wooden-fish':
          void openWoodenFishPublicWorkDetail(intent.profileId);
          return;
        case 'open-big-fish':
          void refreshBigFishGallery()
            .then((entries) => {
              const matchedEntry = entries.find(
                (entry) => entry.sourceSessionId === intent.sessionId,
              );
              if (matchedEntry) {
                openPublicWorkDetail(
                  mapBigFishWorkToPublicWorkDetail(matchedEntry),
                );
                return;
              }
              openPublicWorkDetail(
                mapBigFishWorkToPublicWorkDetail(intent.fallbackWork),
              );
            })
            .catch((error) => {
              setBigFishError(
                resolveBigFishErrorMessage(error, '进入大鱼吃小鱼作品失败。'),
              );
            });
          return;
        case 'open-rpg':
          void openRpgPublicWorkDetail(intent.detail);
          return;
        default: {
          const exhaustive: never = intent;
          return exhaustive;
        }
      }
    },
    [
      openMatch3DPublicWorkDetail,
      openPuzzlePublicWorkDetail,
      openPublicWorkDetail,
      openJumpHopPublicWorkDetail,
      openWoodenFishPublicWorkDetail,
      openRpgPublicWorkDetail,
      openSquareHolePublicWorkDetail,
      refreshBigFishGallery,
      resolveBigFishErrorMessage,
      setBigFishError,
    ],
  );

  useEffect(() => {
    const publicWorkCode = initialPublicWorkCode?.trim();
    if (
      !publicWorkCode ||
      handledInitialPublicWorkCodeRef.current === publicWorkCode
    ) {
      return;
    }

    handledInitialPublicWorkCodeRef.current = publicWorkCode;
    void handlePublicCodeSearch(publicWorkCode);
  }, [handlePublicCodeSearch, initialPublicWorkCode]);

  useEffect(() => {
    if (selectionStage === 'platform') {
      if (isBigFishCreationVisible) {
        void refreshBigFishGallery();
      }
      void refreshJumpHopGallery();
      void refreshWoodenFishGallery();
      void refreshMatch3DGallery();
      void refreshPuzzleGallery();
      void refreshBarkBattleGallery();
      if (isSquareHoleCreationVisible) {
        void refreshSquareHoleGallery();
      }
      if (isVisualNovelCreationOpen) {
        void refreshVisualNovelGallery();
      }
    }
  }, [
    isBigFishCreationVisible,
    isSquareHoleCreationVisible,
    isVisualNovelCreationOpen,
    refreshBigFishGallery,
    refreshJumpHopGallery,
    refreshWoodenFishGallery,
    refreshMatch3DGallery,
    refreshPuzzleGallery,
    refreshBarkBattleGallery,
    refreshSquareHoleGallery,
    refreshVisualNovelGallery,
    selectionStage,
  ]);

  useEffect(() => {
    if (
      platformBootstrap.platformTab === 'create' &&
      platformBootstrap.canReadProtectedData
    ) {
      // 中文注释：底部加号创作入口的“最近创作”依赖 RPG works 摘要；
      // 失败草稿也必须随进入创作页刷新，不能只等草稿页刷新后才可见。
      void platformBootstrap.refreshCustomWorldWorks().catch((error) => {
        platformBootstrap.setPlatformError(
          resolveRpgCreationErrorMessage(error, '读取创作作品列表失败。'),
        );
      });
    }

    if (
      (platformBootstrap.platformTab === 'create' ||
        selectionStage === 'platform') &&
      platformBootstrap.canReadProtectedData
    ) {
      void refreshPuzzleShelf();
      void refreshMatch3DShelf();
      if (isSquareHoleCreationVisible) {
        void refreshSquareHoleShelf();
      }
      if (isVisualNovelCreationOpen) {
        void refreshVisualNovelShelf();
      }
      void refreshWoodenFishShelf();
      void refreshBabyObjectMatchShelf();
      void refreshBarkBattleShelf();
    }
  }, [
    isSquareHoleCreationVisible,
    isVisualNovelCreationOpen,
    platformBootstrap.canReadProtectedData,
    platformBootstrap.platformTab,
    platformBootstrap.refreshCustomWorldWorks,
    platformBootstrap.setPlatformError,
    refreshBabyObjectMatchShelf,
    refreshBarkBattleShelf,
    refreshMatch3DShelf,
    refreshPuzzleShelf,
    refreshWoodenFishShelf,
    refreshSquareHoleShelf,
    refreshVisualNovelShelf,
    selectionStage,
  ]);

  useEffect(() => {
    if (
      isBigFishCreationVisible &&
      (platformBootstrap.platformTab === 'create' ||
        selectionStage === 'platform') &&
      platformBootstrap.canReadProtectedData
    ) {
      void refreshBigFishShelf();
    }
  }, [
    isBigFishCreationVisible,
    platformBootstrap.canReadProtectedData,
    platformBootstrap.platformTab,
    refreshBigFishShelf,
    selectionStage,
  ]);

  const creationHubShelfItems = useMemo(
    () =>
      buildCreationWorkShelfItems({
        rpgItems: creationHubItems,
        rpgLibraryEntries: platformBootstrap.savedCustomWorldEntries,
        bigFishItems: isBigFishCreationVisible ? bigFishShelfItems : [],
        jumpHopItems: isJumpHopCreationVisible ? jumpHopShelfItems : [],
        woodenFishItems: woodenFishShelfItems,
        match3dItems: match3dShelfItems,
        squareHoleItems: isSquareHoleCreationVisible ? squareHoleShelfItems : [],
        puzzleItems: puzzleShelfItems,
        babyObjectMatchItems: isBabyObjectMatchVisible
          ? babyObjectMatchDrafts
          : [],
        barkBattleItems: barkBattleShelfItems,
        visualNovelItems: visualNovelShelfItems,
        canDeleteRpg: true,
        canDeleteBigFish: isBigFishCreationVisible,
        canDeleteMatch3D: true,
        canDeleteSquareHole: isSquareHoleCreationVisible,
        canDeletePuzzle: true,
        canDeleteBabyObjectMatch: isBabyObjectMatchVisible,
        canDeleteVisualNovel: true,
        onOpenRpgDraft: (item) => {
          runProtectedAction(() => {
            markCreationFlowReturnToDraftShelf();
            void detailNavigation.handleOpenCreationWork(item);
          });
        },
        onEnterRpgPublished: (profileId) => {
          runProtectedAction(() => {
            const matchedWork = creationHubItems.find(
              (entry) => entry.profileId === profileId,
            );
            if (!matchedWork) {
              return;
            }
            markCreationFlowReturnToDraftShelf();
            void detailNavigation.handleOpenCreationWork(matchedWork);
          });
        },
        onDeleteRpg: handleDeletePublishedWork,
        onOpenBigFishDetail: isBigFishCreationVisible
          ? (item) => {
              runProtectedAction(() => {
                markCreationFlowReturnToDraftShelf();
                void openBigFishDraft(item);
              });
            }
          : undefined,
        onDeleteBigFish: isBigFishCreationVisible
          ? handleDeleteBigFishWork
          : undefined,
        onOpenJumpHopDetail: isJumpHopCreationVisible
          ? (item) => {
              runProtectedAction(() => {
                markCreationFlowReturnToDraftShelf();
                void openJumpHopDraft(item);
              });
            }
          : undefined,
        onOpenWoodenFishDetail: (item) => {
          runProtectedAction(() => {
            markCreationFlowReturnToDraftShelf();
            void openWoodenFishDraft(item);
          });
        },
        onOpenMatch3DDetail: (item) => {
          runProtectedAction(() => {
            markCreationFlowReturnToDraftShelf();
            void openMatch3DDraft(item);
          });
        },
        onDeleteMatch3D: handleDeleteMatch3DWork,
        onOpenSquareHoleDetail: isSquareHoleCreationVisible
          ? (item) => {
              runProtectedAction(() => {
                markCreationFlowReturnToDraftShelf();
                void openSquareHoleDraft(item);
              });
            }
          : undefined,
        onDeleteSquareHole: isSquareHoleCreationVisible
          ? handleDeleteSquareHoleWork
          : undefined,
        onOpenPuzzleDetail: (item) => {
          runProtectedAction(() => {
            markCreationFlowReturnToDraftShelf();
            void openPuzzleDraft(item);
          });
        },
        onDeletePuzzle: handleDeletePuzzleWork,
        onClaimPuzzlePointIncentive: handleClaimPuzzlePointIncentive,
        onOpenBabyObjectMatchDetail: (item) => {
          runProtectedAction(() => {
            markCreationFlowReturnToDraftShelf();
            openBabyObjectMatchDraft(item);
          });
        },
        onDeleteBabyObjectMatch: handleDeleteBabyObjectMatchWork,
        onOpenBarkBattleDetail: (item) => {
          runProtectedAction(() => {
            markCreationFlowReturnToDraftShelf();
            openBarkBattleDraft(item);
          });
        },
        onOpenVisualNovelDetail: (item) => {
          runProtectedAction(() => {
            markCreationFlowReturnToDraftShelf();
            void openVisualNovelDraft(item);
          });
        },
        onDeleteVisualNovel: handleDeleteVisualNovelWork,
        getItemState: getCreationWorkShelfState,
      }),
    [
      barkBattleShelfItems,
      babyObjectMatchDrafts,
      bigFishShelfItems,
      creationHubItems,
      detailNavigation,
      getCreationWorkShelfState,
      handleClaimPuzzlePointIncentive,
      handleDeleteBabyObjectMatchWork,
      handleDeleteBigFishWork,
      handleDeleteMatch3DWork,
      handleDeletePublishedWork,
      handleDeletePuzzleWork,
      handleDeleteSquareHoleWork,
      handleDeleteVisualNovelWork,
      isBabyObjectMatchVisible,
      isBigFishCreationVisible,
      isJumpHopCreationVisible,
      isSquareHoleCreationVisible,
      jumpHopShelfItems,
      markCreationFlowReturnToDraftShelf,
      match3dShelfItems,
      openBabyObjectMatchDraft,
      openBarkBattleDraft,
      openBigFishDraft,
      openJumpHopDraft,
      openMatch3DDraft,
      openPuzzleDraft,
      openSquareHoleDraft,
      openVisualNovelDraft,
      openWoodenFishDraft,
      platformBootstrap.savedCustomWorldEntries,
      puzzleShelfItems,
      runProtectedAction,
      squareHoleShelfItems,
      visualNovelShelfItems,
      woodenFishShelfItems,
    ],
  );

  // 中文注释：最近创作必须由真实作品架/后端草稿摘要决定，不能混入本地生成中占位。
  const backendRecentCreationShelfItems = useMemo(
    () =>
      buildCreationWorkShelfItems({
        rpgItems: creationHubItems,
        rpgLibraryEntries: platformBootstrap.savedCustomWorldEntries,
        bigFishItems: isBigFishCreationVisible ? bigFishWorks : [],
        match3dItems: match3dWorks,
        squareHoleItems: isSquareHoleCreationVisible ? squareHoleWorks : [],
        jumpHopItems: isJumpHopCreationVisible ? jumpHopWorks : [],
        woodenFishItems: woodenFishWorks,
        puzzleItems: puzzleWorks,
        babyObjectMatchItems: isBabyObjectMatchVisible
          ? babyObjectMatchDrafts
          : [],
        barkBattleItems: barkBattleWorks,
        visualNovelItems: isVisualNovelCreationOpen ? visualNovelWorks : [],
        getItemState: getCreationWorkShelfState,
      }),
    [
      barkBattleWorks,
      babyObjectMatchDrafts,
      bigFishWorks,
      creationHubItems,
      getCreationWorkShelfState,
      isBabyObjectMatchVisible,
      isBigFishCreationVisible,
      isJumpHopCreationVisible,
      isSquareHoleCreationVisible,
      isVisualNovelCreationOpen,
      jumpHopWorks,
      match3dWorks,
      platformBootstrap.savedCustomWorldEntries,
      puzzleWorks,
      squareHoleWorks,
      visualNovelWorks,
      woodenFishWorks,
    ],
  );

  const renderCreationHubContent = (
    mode: 'start-only' | 'works-only',
    fallbackLabel: string,
  ) => (
    <Suspense fallback={<LazyPanelFallback label={fallbackLabel} />}>
      {creationEntryConfig ? (
        <CustomWorldCreationHub
          mode={mode}
          shelfItems={creationHubShelfItems}
          loading={
            platformBootstrap.isLoadingPlatform ||
            isBigFishLoadingLibrary ||
            isMatch3DLoadingLibrary ||
            (isSquareHoleCreationVisible && isSquareHoleLoadingLibrary) ||
            isPuzzleLoadingLibrary ||
            (isVisualNovelCreationOpen && isVisualNovelLoadingLibrary) ||
            isBabyObjectMatchBusy
          }
          error={
            platformBootstrap.isLoadingPlatform ||
            isBigFishLoadingLibrary ||
            isMatch3DLoadingLibrary ||
            (isSquareHoleCreationVisible && isSquareHoleLoadingLibrary) ||
            isPuzzleLoadingLibrary ||
            (isVisualNovelCreationOpen && isVisualNovelLoadingLibrary) ||
            isBabyObjectMatchBusy
              ? null
              : (platformBootstrap.platformError ??
                sessionController.agentWorkspaceRestoreError ??
                bigFishError ??
                match3dError ??
                (isSquareHoleCreationVisible ? squareHoleError : null) ??
                puzzleShelfError ??
                puzzleError ??
                (isVisualNovelCreationOpen ? visualNovelError : null) ??
                babyObjectMatchError ??
                barkBattleError)
          }
          onRetry={() => {
            platformBootstrap.setPlatformError(null);
            setCreationEntryConfigError(null);
            void fetchCreationEntryConfig()
              .then(setCreationEntryConfig)
              .catch((error: unknown) => {
                setCreationEntryConfigError(
                  error instanceof Error
                    ? error.message
                    : '读取创作入口配置失败。',
                );
              });
            setBigFishError(null);
            setMatch3DError(null);
            setSquareHoleError(null);
            setPuzzleShelfError(null);
            setPuzzleCreationError(null);
            setPuzzleError(null);
            setVisualNovelError(null);
            setBabyObjectMatchError(null);
            setWoodenFishError(null);
            void platformBootstrap.refreshCustomWorldWorks().catch((error) => {
              platformBootstrap.setPlatformError(
                resolveRpgCreationErrorMessage(error, '读取创作作品列表失败。'),
              );
            });
            if (isBigFishCreationVisible) {
              void refreshBigFishShelf();
            }
            void refreshMatch3DShelf();
            if (isSquareHoleCreationVisible) {
              void refreshSquareHoleShelf();
            }
            void refreshPuzzleShelf();
            void refreshWoodenFishShelf();
            if (isVisualNovelCreationOpen) {
              void refreshVisualNovelShelf();
            }
            void refreshBabyObjectMatchShelf();
            void refreshBarkBattleShelf();
          }}
          createBusy={
            !creationEntryConfig ||
            sessionController.isCreatingAgentSession ||
            isCreativeAgentBusy ||
            isCreativeAgentStreaming ||
            isBigFishBusy ||
            isMatch3DBusy ||
            (isSquareHoleCreationVisible && isSquareHoleBusy) ||
            isWoodenFishBusy ||
            isPuzzleBusy ||
            (isVisualNovelCreationOpen && isVisualNovelBusy) ||
            (isVisualNovelCreationOpen && isVisualNovelStreamingReply) ||
            isBabyObjectMatchBusy ||
            isBarkBattleBusy
          }
          entryConfig={creationEntryConfig}
          creationTypes={creationEntryTypes}
          recentWorkItems={backendRecentCreationShelfItems}
          onCreateType={handleCreationHubCreateType}
          onOpenShelfItem={(item) => {
            markDraftNoticeSeen(getGenerationNoticeShelfKeys(item));
          }}
          deletingWorkId={deletingCreationWorkId}
          claimingPuzzleProfileId={claimingPuzzlePointIncentiveProfileId}
        />
      ) : null}
    </Suspense>
  );
  const creationStartContent = renderCreationHubContent(
    'start-only',
    '正在加载创作大厅...',
  );
  const draftHubContent = renderCreationHubContent(
    'works-only',
    '正在加载草稿列表...',
  );

  return (
    <>
      <AnimatePresence mode="wait">
        {selectionStage === 'platform' && (
          <motion.div
            key="platform-home"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 min-w-0 flex-col overflow-hidden"
          >
            <PlatformEntryHomeView
              activeTab={platformBootstrap.platformTab}
              onTabChange={platformBootstrap.setPlatformTab}
              hasSavedGame={hasSavedGame}
              savedSnapshot={savedSnapshot}
              saveEntries={platformBootstrap.saveEntries}
              saveError={platformBootstrap.saveError}
              featuredEntries={featuredGalleryEntries}
              latestEntries={latestGalleryEntries}
              myEntries={platformBootstrap.savedCustomWorldEntries}
              historyEntries={platformBootstrap.historyEntries}
              profileDashboard={platformBootstrap.profileDashboard}
              isLoadingPlatform={platformBootstrap.isLoadingPlatform}
              isLoadingDashboard={platformBootstrap.isLoadingDashboard}
              hasUnreadDraftUpdate={hasUnreadDraftUpdates}
              profileTaskRefreshKey={profileTaskRefreshKey}
              isDesktopLayout={isDesktopLayout}
              isResumingSaveWorldKey={platformBootstrap.isResumingSaveWorldKey}
              platformError={
                platformBootstrap.isLoadingPlatform
                  ? null
                  : (platformBootstrap.platformError ??
                    sessionController.agentWorkspaceRestoreError)
              }
              dashboardError={
                platformBootstrap.isLoadingDashboard
                  ? null
                  : platformBootstrap.dashboardError
              }
              createTabContent={creationStartContent}
              draftTabContent={draftHubContent}
              onContinueGame={handleContinueGame}
              onResumeSave={(entry) => {
                if (
                  (entry.worldType ?? '').toLowerCase() === 'puzzle' ||
                  entry.worldKey.startsWith('puzzle:')
                ) {
                  void resumePuzzleSaveArchive(entry);
                  return;
                }
                void platformBootstrap.handleResumeSaveEntry(entry);
              }}
              onOpenCreateWorld={openCreationTypePicker}
              onOpenCreateTypePicker={openCreationTypePicker}
              onOpenGalleryDetail={openPublicGalleryDetail}
              onOpenChildMotionDemo={startChildMotionDemo}
              onOpenBabyLoveDrawing={startBabyLoveDrawingRuntime}
              onOpenRecommendGalleryDetail={openRecommendGalleryDetail}
              recommendRuntimeContent={recommendRuntimeContent}
              activeRecommendEntryKey={activeRecommendEntryKey}
              isStartingRecommendEntry={
                isStartingRecommendEntry ||
                isBigFishBusy ||
                (isPuzzleBusy &&
                  !(activeRecommendRuntimeKind === 'puzzle' && puzzleRun)) ||
                isMatch3DBusy ||
                isSquareHoleBusy ||
                isVisualNovelBusy ||
                isWoodenFishBusy
              }
              recommendRuntimeError={activeRecommendRuntimeError}
              onSelectNextRecommendEntry={(activeEntryKey) =>
                selectAdjacentRecommendRuntimeEntry(1, activeEntryKey)
              }
              onSelectPreviousRecommendEntry={(activeEntryKey) =>
                selectAdjacentRecommendRuntimeEntry(-1, activeEntryKey)
              }
              onLikeRecommendEntry={(entry) => {
                likePublicWork(entry);
              }}
              onRemixRecommendEntry={(entry) => {
                remixPublicWork(entry);
              }}
              onOpenLibraryDetail={(entry) => {
                runProtectedAction(() => {
                  void detailNavigation.openLibraryDetail(entry);
                });
              }}
              onDeleteLibraryEntry={(entry) => {
                handleDeleteLibraryEntry(entry);
              }}
              deletingLibraryEntryId={deletingCreationWorkId}
              onSearchPublicCode={(keyword) => {
                void handlePublicCodeSearch(keyword);
              }}
              isSearchingPublicCode={isSearchingPublicCode}
              profilePlayStats={profilePlayStats}
              isProfilePlayStatsOpen={isProfilePlayStatsOpen}
              isProfilePlayStatsLoading={isProfilePlayStatsLoading}
              profilePlayStatsError={profilePlayStatsError}
              onCloseProfilePlayStats={() => {
                setIsProfilePlayStatsOpen(false);
              }}
              onOpenPlayedWork={openPlayedWork}
              onOpenFeedback={openProfileFeedback}
              onOpenProfileDashboardCard={(cardKey) => {
                if (cardKey === 'playedWorks') {
                  openProfilePlayedWorks();
                  return;
                }
                if (platformBootstrap.dashboardError) {
                  void platformBootstrap.refreshProfileDashboard();
                }
              }}
              onRechargeSuccess={platformBootstrap.refreshProfileDashboard}
            />
          </motion.div>
        )}

        {selectionStage === 'profile-feedback' && (
          <motion.div
            key="platform-profile-feedback"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <PlatformFeedbackView
              onBack={() => {
                setPlatformTab('profile');
                setSelectionStage('platform');
              }}
              onSubmit={submitRpgProfileFeedback}
            />
          </motion.div>
        )}

        {selectionStage === 'work-detail' && !selectedPublicWorkDetail && (
          <motion.div
            key="platform-work-detail-empty"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 items-center justify-center"
          >
            <div className="platform-subpanel rounded-2xl px-5 py-4 text-sm text-[var(--platform-text-base)]">
              {publicWorkDetailError || '正在读取作品详情...'}
            </div>
          </motion.div>
        )}

        {selectionStage === 'work-detail' && selectedPublicWorkDetail && (
          <motion.div
            key="platform-work-detail"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <PlatformWorkDetailView
              entry={selectedPublicWorkDetail}
              authorSummary={selectedPublicWorkAuthor}
              isBusy={
                isPublicWorkDetailBusy ||
                isPuzzleBusy ||
                isBigFishBusy ||
                isMatch3DBusy ||
                isSquareHoleBusy ||
                isVisualNovelBusy
              }
              error={publicWorkDetailError}
              actionMode={selectedPublicWorkActionMode}
              visibleCoverCount={resolveVisiblePuzzleDetailCoverCount(
                selectedPublicWorkDetail,
                puzzleRun,
              )}
              onBack={() => {
                setPublicWorkDetailError(null);
                clearSelectedPublicWorkAuthor();
                setSelectionStage('platform');
              }}
              onLike={() => {
                likePublicWork(selectedPublicWorkDetail);
              }}
              onStart={startSelectedPublicWork}
              onRemix={remixSelectedPublicWork}
            />
          </motion.div>
        )}

        {selectionStage === 'detail' && (
          <motion.div
            key="platform-detail"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            {detailNavigation.isDetailLoading || !selectedDetailEntry ? (
              <div className="flex h-full items-center justify-center">
                <div className="platform-subpanel rounded-2xl px-5 py-4 text-sm text-[var(--platform-text-base)]">
                  {detailNavigation.detailError || '正在读取作品详情...'}
                </div>
              </div>
            ) : selectedDetailEntry.visibility !== 'draft' ? (
              <PlatformWorkDetailView
                entry={mapRpgGalleryCardToPublicWorkDetail(selectedDetailEntry)}
                authorSummary={selectedPublicWorkAuthor}
                isBusy={detailNavigation.isMutatingDetail}
                error={detailNavigation.detailError}
                actionMode={
                  detailNavigation.isSelectedWorldOwned ? 'edit' : 'remix'
                }
                onBack={() => {
                  detailNavigation.setDetailError(null);
                  clearSelectedPublicWorkAuthor();
                  entryNavigation.backToPlatformHome();
                }}
                onLike={() => {
                  likePublicWork(
                    mapRpgGalleryCardToPublicWorkDetail(selectedDetailEntry),
                  );
                }}
                onStart={handleStartSelectedWorld}
                onRemix={() => {
                  const publicWorkEntry =
                    mapRpgGalleryCardToPublicWorkDetail(selectedDetailEntry);
                  if (detailNavigation.isSelectedWorldOwned) {
                    editOwnedPublicWork(publicWorkEntry);
                    return;
                  }
                  remixPublicWork(publicWorkEntry);
                }}
              />
            ) : (
              <PlatformEntryWorldDetailView
                entry={selectedDetailEntry}
                isMutating={detailNavigation.isMutatingDetail}
                error={detailNavigation.detailError}
                onBack={() => {
                  detailNavigation.setDetailError(null);
                  entryNavigation.backToPlatformHome();
                }}
                onStartGame={handleStartSelectedWorld}
                onContinueEdit={
                  detailNavigation.isSelectedWorldOwned
                    ? () => {
                        runProtectedAction(() => {
                          void detailNavigation.openSavedCustomWorldEditor(
                            selectedDetailEntry,
                          );
                        });
                      }
                    : null
                }
                onPublish={
                  selectedDetailEntry.visibility === 'draft' &&
                  detailNavigation.isSelectedWorldOwned
                    ? () => {
                        runProtectedAction(() => {
                          void detailNavigation.handlePublishSelectedWorld();
                        });
                      }
                    : null
                }
                onUnpublish={
                  selectedDetailEntry.visibility !== 'draft' &&
                  detailNavigation.isSelectedWorldOwned
                    ? () => {
                        runProtectedAction(() => {
                          void detailNavigation.handleUnpublishSelectedWorld();
                        });
                      }
                    : null
                }
                onDelete={
                  detailNavigation.isSelectedWorldOwned
                    ? () => {
                        runProtectedAction(() => {
                          void detailNavigation.handleDeleteSelectedWorld();
                        });
                      }
                    : null
                }
              />
            )}
          </motion.div>
        )}

        {selectionStage === 'agent-workspace' && (
          <motion.div
            key="agent-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={
                <LazyPanelFallback label="正在加载 Agent 共创工作区..." />
              }
            >
              <UnifiedCreationPage
                spec={getUnifiedSpec('rpg')}
                onBack={leaveAgentWorkspace}
                isBackDisabled={
                  sessionController.isStreamingAgentReply ||
                  Boolean(sessionController.agentOperation)
                }
              >
                {sessionController.agentSession ? (
                  <CustomWorldAgentWorkspace
                    session={sessionController.agentSession}
                    activeOperation={sessionController.agentOperation}
                    streamingReplyText={
                      sessionController.streamingAgentReplyText
                    }
                    isStreamingReply={sessionController.isStreamingAgentReply}
                    onBack={leaveAgentWorkspace}
                    showBackButton={false}
                    onSubmitMessage={(payload) => {
                      void sessionController.submitAgentMessage(payload);
                    }}
                    onExecuteAction={(payload) => {
                      void sessionController.executeAgentAction(payload);
                    }}
                  />
                ) : (
                  <div className="flex h-full items-center justify-center">
                    <div className="platform-subpanel rounded-2xl px-5 py-4 text-sm text-[var(--platform-text-base)]">
                      {sessionController.isLoadingAgentSession
                        ? '正在准备 Agent 共创工作区...'
                        : sessionController.agentWorkspaceRestoreError ||
                          '正在恢复创作工作区...'}
                    </div>
                  </div>
                )}
              </UnifiedCreationPage>
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'big-fish-agent-workspace' && (
          <motion.div
            key="big-fish-agent-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={
                <LazyPanelFallback label="正在加载大鱼吃小鱼共创工作区..." />
              }
            >
              <UnifiedCreationPage
                spec={getUnifiedSpec('big-fish')}
                onBack={leaveBigFishFlow}
                isBackDisabled={isBigFishBusy || isStreamingBigFishReply}
              >
                <BigFishAgentWorkspace
                  session={bigFishSession}
                  streamingReplyText={streamingBigFishReplyText}
                  isStreamingReply={isStreamingBigFishReply}
                  isBusy={isBigFishBusy || isStreamingBigFishReply}
                  error={bigFishError}
                  onBack={leaveBigFishFlow}
                  showBackButton={false}
                  onSubmitMessage={(payload) => {
                    void submitBigFishMessage(payload);
                  }}
                  onExecuteAction={(payload) => {
                    void executeBigFishAction(payload);
                  }}
                />
              </UnifiedCreationPage>
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'big-fish-generating' && (
          <motion.div
            key="big-fish-generating"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={
                <LazyPanelFallback label="正在加载大鱼吃小鱼生成面板..." />
              }
            >
              <CustomWorldGenerationView
                settingText={
                  bigFishSession?.lastAssistantReply ?? '正在整理当前玩法草稿。'
                }
                anchorEntries={buildBigFishGenerationAnchorEntries(
                  bigFishSession,
                )}
                progress={buildMiniGameDraftGenerationProgress(
                  bigFishGenerationState,
                )}
                isGenerating={isBigFishBusy}
                error={bigFishError}
                onBack={returnToCreationCenterFromGeneration}
                onEditSetting={() => {
                  setSelectionStage('big-fish-agent-workspace');
                }}
                onRetry={() => {
                  void executeBigFishAction({
                    action: 'big_fish_compile_draft',
                  });
                }}
                onInterrupt={undefined}
                backLabel="返回创作中心"
                settingActionLabel={null}
                retryLabel="重新生成草稿"
                settingTitle="当前玩法信息"
                settingDescription={null}
                progressTitle="大鱼吃小鱼草稿生成进度"
                activeBadgeLabel="草稿生成中"
                pausedBadgeLabel="草稿生成已暂停"
                idleBadgeLabel="等待返回工作区"
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'big-fish-result' && bigFishSession?.draft && (
          <motion.div
            key="big-fish-result"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载玩法结果页..." />}
            >
              <BigFishResultView
                session={bigFishSession}
                isBusy={isBigFishBusy}
                error={bigFishError}
                onBack={() => {
                  if (shouldReturnToDraftShelf()) {
                    leaveBigFishFlow();
                    return;
                  }
                  setSelectionStage('big-fish-agent-workspace');
                }}
                onDismissError={() => {
                  setBigFishError(null);
                }}
                onExecuteAction={(payload) => {
                  void executeBigFishAction(payload);
                }}
                onStartTestRun={() => {
                  void startBigFishRun();
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'big-fish-runtime' && (
          <motion.div
            key="big-fish-runtime"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[100]"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载大鱼吃小鱼玩法..." />}
            >
              <BigFishRuntimeShell
                run={bigFishRun}
                assetSlots={bigFishSession?.assetSlots ?? []}
                shareTitle={bigFishRuntimeShare?.title ?? null}
                sharePublicWorkCode={
                  bigFishRuntimeShare?.publicWorkCode ?? null
                }
                isBusy={isBigFishBusy}
                error={bigFishError}
                onBack={() => {
                  reportBigFishObservedPlayTime();
                  setSelectionStage(bigFishRuntimeReturnStage);
                }}
                onRestart={() => {
                  reportBigFishObservedPlayTime();
                  void restartBigFishRun();
                }}
                onSubmitInput={submitBigFishInput}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'match3d-agent-workspace' && (
          <motion.div
            key="match3d-agent-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={
                <LazyPanelFallback label="正在加载抓大鹅共创工作区..." />
              }
            >
              <UnifiedCreationWorkspace
                playId="match3d"
                spec={getUnifiedSpec('match3d')}
                session={match3dSession}
                isBusy={isStreamingMatch3DReply}
                error={match3dError}
                onBack={leaveMatch3DFlow}
                onExecuteAction={(payload) => {
                  void executeMatch3DAction(payload);
                }}
                initialFormPayload={match3dFormDraftPayload}
                onCreateFromForm={(payload) => {
                  runProtectedAction(() => {
                    void createMatch3DDraftFromForm(payload);
                  });
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'match3d-generating' && (
          <motion.div
            key="match3d-generating"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载抓大鹅生成面板..." />}
            >
              <UnifiedGenerationPage
                playId="match3d"
                settingText={
                  match3dGenerationViewSession?.lastAssistantReply ??
                  '正在生成本局抓大鹅物品素材。'
                }
                anchorEntries={buildMatch3DGenerationAnchorEntries(
                  match3dGenerationViewSession,
                  match3dGenerationViewPayload,
                )}
                progress={buildMiniGameDraftGenerationProgress(
                  match3dGenerationViewState,
                  miniGameGenerationProgressNowMs,
                )}
                isGenerating={isMatch3DGenerationViewBusy}
                error={match3dGenerationViewError}
                onBack={returnToCreationCenterFromGeneration}
                onEditSetting={() => {
                  setSelectionStage('match3d-agent-workspace');
                }}
                onRetry={retryMatch3DDraftGeneration}
                hideBatchModule
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'match3d-result' && match3dSession?.draft && (
          <motion.div
            key="match3d-result"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载抓大鹅结果..." />}
            >
              <Match3DResultView
                profile={
                  match3dProfile ??
                  buildMatch3DProfileFromSession(match3dSession)!
                }
                draft={match3dSession.draft}
                isBusy={isMatch3DBusy}
                error={match3dError}
                onBack={() => {
                  if (shouldReturnToDraftShelf()) {
                    leaveMatch3DFlow();
                    return;
                  }
                  returnToCreationCenterFromGeneration();
                }}
                onSaved={(profile) => {
                  setMatch3DProfile(normalizeMatch3DWorkForRuntimeUi(profile));
                }}
                onPublished={(profile) => {
                  const normalizedProfile =
                    normalizeMatch3DWorkForRuntimeUi(profile);
                  setMatch3DProfile(normalizedProfile);
                  void Promise.allSettled([
                    refreshMatch3DShelf(),
                    refreshMatch3DGallery(),
                  ]);
                  openPublicWorkDetail(
                    mapMatch3DWorkToPublicWorkDetail(normalizedProfile),
                  );
                  openPublishShareModal({
                    title: normalizedProfile.gameName,
                    publicWorkCode: buildMatch3DPublicWorkCode(
                      normalizedProfile.profileId,
                    ),
                    stage: 'work-detail',
                  });
                }}
                onStartTestRun={(profile, options) => {
                  const normalizedProfile =
                    normalizeMatch3DWorkForRuntimeUi(profile);
                  setMatch3DProfile(normalizedProfile);
                  void startMatch3DRunFromProfile(
                    normalizedProfile,
                    'match3d-result',
                    false,
                    options,
                  );
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'match3d-runtime' &&
          (() => {
            const activeMatch3DRuntimeProfile =
              resolveActiveMatch3DRuntimeProfile(
                match3dRun,
                match3dRuntimeProfile,
                match3dProfile,
              );
            return (
              <motion.div
                key="match3d-runtime"
                initial={{ opacity: 0 }}
                animate={{ opacity: 1 }}
                exit={{ opacity: 0 }}
                className="fixed inset-0 z-[100]"
              >
                <Suspense
                  fallback={<LazyPanelFallback label="正在加载抓大鹅玩法..." />}
                >
                  <Match3DRuntimeShell
                    run={match3dRun}
                    isBusy={isMatch3DBusy}
                    error={match3dError}
                    generatedItemAssets={resolveMatch3DRuntimeGeneratedItemAssets(
                      match3dRun,
                      activeMatch3DRuntimeProfile,
                      selectedPublicWorkDetail,
                    )}
                    generatedBackgroundAsset={resolveMatch3DRuntimeGeneratedBackgroundAsset(
                      match3dRun,
                      activeMatch3DRuntimeProfile,
                      selectedPublicWorkDetail,
                    )}
                    backgroundImageSrc={resolveMatch3DRuntimeBackgroundImageSrc(
                      match3dRun,
                      activeMatch3DRuntimeProfile,
                      selectedPublicWorkDetail,
                    )}
                    onBack={() => {
                      if (
                        match3dRun?.runId &&
                        match3dRun.status === 'running'
                      ) {
                        void resolveMatch3DRuntimeAdapter(
                          activeMatch3DRuntimeProfile?.profileId,
                        )
                          .stopRun(match3dRun.runId)
                          .catch(() => undefined);
                      }
                      setSelectionStage(match3dRuntimeReturnStage);
                    }}
                    onRestart={() => {
                      if (!match3dRun?.runId || isMatch3DBusy) {
                        return;
                      }

                      match3dFlow.setIsBusy(true);
                      setMatch3DError(null);
                      void resolveMatch3DRuntimeAdapter(
                        activeMatch3DRuntimeProfile?.profileId,
                      )
                        .restartRun(match3dRun.runId)
                        .then(({ run }) => {
                          setMatch3DRun(run);
                        })
                        .catch((error) => {
                          setMatch3DError(
                            resolveMatch3DErrorMessage(
                              error,
                              '重新开始抓大鹅玩法失败。',
                            ),
                          );
                        })
                        .finally(() => {
                          match3dFlow.setIsBusy(false);
                        });
                    }}
                    onOptimisticRunChange={setMatch3DRun}
                    onClickItem={(payload) => {
                      const runId = payload.runId ?? match3dRun?.runId;
                      if (!runId) {
                        return Promise.reject(
                          new Error('抓大鹅运行态缺少 runId。'),
                        );
                      }
                      return resolveMatch3DRuntimeAdapter(
                        activeMatch3DRuntimeProfile?.profileId,
                      ).clickItem(runId, payload);
                    }}
                    onTimeExpired={() => {
                      if (!match3dRun?.runId) {
                        return;
                      }

                      void resolveMatch3DRuntimeAdapter(
                        activeMatch3DRuntimeProfile?.profileId,
                      )
                        .finishTimeUp(match3dRun.runId)
                        .then(({ run }) => {
                          setMatch3DRun(run);
                        })
                        .catch((error) => {
                          setMatch3DError(
                            resolveMatch3DErrorMessage(
                              error,
                              '同步抓大鹅倒计时失败。',
                            ),
                          );
                        });
                    }}
                  />
                </Suspense>
              </motion.div>
            );
          })()}

        {selectionStage === 'baby-object-match-workspace' && (
          <motion.div
            key="baby-object-match-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载宝贝识物创作..." />}
            >
              <UnifiedCreationPage
                spec={getUnifiedSpec('baby-object-match')}
                onBack={leaveBabyObjectMatchFlow}
                isBackDisabled={isBabyObjectMatchBusy}
              >
                <BabyObjectMatchWorkspace
                  isBusy={isBabyObjectMatchBusy}
                  error={babyObjectMatchError}
                  onBack={leaveBabyObjectMatchFlow}
                  showBackButton={false}
                  title={null}
                  initialPayload={babyObjectMatchFormPayload}
                  onCreateDraft={(payload) => {
                    void createBabyObjectMatchDraftFromForm(payload);
                  }}
                />
              </UnifiedCreationPage>
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'baby-object-match-generating' && (
          <motion.div
            key="baby-object-match-generating"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={
                <LazyPanelFallback label="正在加载宝贝识物生成面板..." />
              }
            >
              <CustomWorldGenerationView
                settingText={
                  babyObjectMatchFormPayload
                    ? `${babyObjectMatchFormPayload.itemAName} / ${babyObjectMatchFormPayload.itemBName}`
                    : '正在整理当前宝贝识物草稿。'
                }
                anchorEntries={buildBabyObjectMatchGenerationAnchorEntries(
                  babyObjectMatchFormPayload,
                  babyObjectMatchDraft,
                )}
                progress={buildMiniGameDraftGenerationProgress(
                  babyObjectMatchGenerationState,
                  miniGameGenerationProgressNowMs,
                )}
                isGenerating={
                  isBabyObjectMatchBusy &&
                  babyObjectMatchGenerationPhase === 'generating'
                }
                error={babyObjectMatchError}
                onBack={leaveBabyObjectMatchFlow}
                onEditSetting={() => {
                  setSelectionStage('baby-object-match-workspace');
                }}
                onRetry={retryBabyObjectMatchDraftGeneration}
                onInterrupt={undefined}
                backLabel="返回创作中心"
                settingActionLabel={null}
                retryLabel="重新生成草稿"
                settingTitle="当前宝贝识物信息"
                settingDescription={null}
                progressTitle="宝贝识物草稿生成进度"
                activeBadgeLabel="草稿生成中"
                pausedBadgeLabel="草稿生成已暂停"
                idleBadgeLabel="等待返回工作区"
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'baby-object-match-result' &&
          babyObjectMatchDraft && (
            <motion.div
              key="baby-object-match-result"
              initial={{ opacity: 0, y: 12 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -12 }}
              className="flex h-full min-h-0 flex-col"
            >
              <Suspense
                fallback={<LazyPanelFallback label="正在加载宝贝识物结果..." />}
              >
                <BabyObjectMatchResultView
                  draft={babyObjectMatchDraft}
                  isBusy={isBabyObjectMatchBusy}
                  error={babyObjectMatchError}
                  onBack={() => {
                    if (shouldReturnToDraftShelf()) {
                      leaveBabyObjectMatchFlow();
                      return;
                    }
                    setSelectionStage('baby-object-match-workspace');
                  }}
                  onSaveDraft={(draft) => {
                    void saveBabyObjectMatchResultDraft(draft);
                  }}
                  onPublish={(draft) => {
                    void publishBabyObjectMatchResultDraft(draft);
                  }}
                  onRegenerateAssets={(draft) => {
                    void regenerateBabyObjectMatchResultAssets(draft);
                  }}
                  onStartTestRun={(draft) => {
                    void startBabyObjectMatchRuntimeFromDraft(
                      draft,
                      'baby-object-match-result',
                    );
                  }}
                />
              </Suspense>
            </motion.div>
          )}

        {selectionStage === 'baby-object-match-runtime' &&
          babyObjectMatchDraft && (
            <motion.div
              key="baby-object-match-runtime"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0 }}
              className="fixed inset-0 z-[100]"
            >
              <Suspense
                fallback={<LazyPanelFallback label="正在加载宝贝识物玩法..." />}
              >
                <BabyObjectMatchRuntimeShell
                  draft={babyObjectMatchDraft}
                  onBack={() => {
                    setSelectionStage(babyObjectMatchRuntimeReturnStage);
                  }}
                />
              </Suspense>
            </motion.div>
          )}

        {selectionStage === 'baby-love-drawing-runtime' && (
          <motion.div
            key="baby-love-drawing-runtime"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[100]"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载宝贝爱画..." />}
            >
              <BabyLoveDrawingRuntimeShell
                onBack={() => {
                  setSelectionStage('platform');
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'bark-battle-workspace' && (
          <motion.div
            key="bark-battle-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载汪汪声浪创作..." />}
            >
              <UnifiedCreationPage
                spec={getUnifiedSpec('bark-battle')}
                onBack={leaveBarkBattleFlow}
                isBackDisabled={isBarkBattleBusy}
              >
                <BarkBattleConfigEditor
                  isBusy={isBarkBattleBusy}
                  error={barkBattleError}
                  onBack={leaveBarkBattleFlow}
                  showBackButton={false}
                  title={null}
                  onPreview={(payload) => {
                    void createBarkBattleGeneratingDraft(payload);
                  }}
                />
              </UnifiedCreationPage>
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'square-hole-agent-workspace' && (
          <motion.div
            key="square-hole-agent-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={
                <LazyPanelFallback label="正在加载方洞挑战共创工作区..." />
              }
            >
              <UnifiedCreationPage
                spec={getUnifiedSpec('square-hole')}
                onBack={leaveSquareHoleFlow}
                isBackDisabled={isSquareHoleBusy || isStreamingSquareHoleReply}
              >
                <SquareHoleAgentWorkspace
                  session={squareHoleSession}
                  streamingReplyText={streamingSquareHoleReplyText}
                  isStreamingReply={isStreamingSquareHoleReply}
                  isBusy={isSquareHoleBusy || isStreamingSquareHoleReply}
                  error={squareHoleError}
                  onBack={leaveSquareHoleFlow}
                  showBackButton={false}
                  onSubmitMessage={(payload) => {
                    void submitSquareHoleMessage(payload);
                  }}
                  onExecuteAction={(payload) => {
                    void executeSquareHoleAction(payload);
                  }}
                />
              </UnifiedCreationPage>
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'square-hole-generating' && (
          <motion.div
            key="square-hole-generating"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={
                <LazyPanelFallback label="正在加载方洞挑战生成面板..." />
              }
            >
              <CustomWorldGenerationView
                settingText={
                  squareHoleSession?.lastAssistantReply ??
                  '正在整理当前方洞挑战草稿。'
                }
                anchorEntries={buildSquareHoleGenerationAnchorEntries(
                  squareHoleSession,
                )}
                progress={buildMiniGameDraftGenerationProgress(
                  squareHoleGenerationState,
                )}
                isGenerating={isSquareHoleBusy}
                error={squareHoleError}
                onBack={returnToCreationCenterFromGeneration}
                onEditSetting={() => {
                  setSelectionStage('square-hole-agent-workspace');
                }}
                onRetry={retrySquareHoleAssetGeneration}
                onInterrupt={undefined}
                backLabel="返回创作中心"
                settingActionLabel={null}
                retryLabel="重新生成图片"
                settingTitle="当前方洞挑战"
                settingDescription={null}
                progressTitle="方洞挑战图片生成进度"
                activeBadgeLabel="图片生成中"
                pausedBadgeLabel="图片生成已暂停"
                idleBadgeLabel="等待返回结果页"
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'square-hole-result' &&
          squareHoleSession?.draft && (
            <motion.div
              key="square-hole-result"
              initial={{ opacity: 0, y: 12 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -12 }}
              className="flex h-full min-h-0 flex-col"
            >
              <Suspense
                fallback={<LazyPanelFallback label="正在加载方洞挑战结果..." />}
              >
                <SquareHoleResultView
                  profile={
                    squareHoleProfile ??
                    buildSquareHoleProfileFromSession(squareHoleSession)!
                  }
                  draft={squareHoleSession.draft}
                  isBusy={isSquareHoleBusy}
                  error={squareHoleError}
                  onBack={() => {
                    if (shouldReturnToDraftShelf()) {
                      leaveSquareHoleFlow();
                      return;
                    }
                    setSelectionStage('square-hole-agent-workspace');
                  }}
                  onSaved={(profile) => {
                    setSquareHoleProfile(profile);
                  }}
                  onPublished={(profile) => {
                    setSquareHoleProfile(profile);
                    void Promise.allSettled([
                      refreshSquareHoleShelf(),
                      refreshSquareHoleGallery(),
                    ]);
                    openPublicWorkDetail(
                      mapSquareHoleWorkToPublicWorkDetail(profile),
                    );
                    openPublishShareModal({
                      title: profile.gameName,
                      publicWorkCode: buildSquareHolePublicWorkCode(
                        profile.profileId,
                      ),
                      stage: 'work-detail',
                    });
                  }}
                  onStartTestRun={(profile) => {
                    setSquareHoleProfile(profile);
                    void startSquareHoleRunFromProfile(
                      profile,
                      'square-hole-result',
                    );
                  }}
                />
              </Suspense>
            </motion.div>
          )}

        {selectionStage === 'square-hole-runtime' && (
          <motion.div
            key="square-hole-runtime"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[100]"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载方洞挑战玩法..." />}
            >
              <SquareHoleRuntimeShell
                run={squareHoleRun}
                isBusy={isSquareHoleBusy}
                error={squareHoleError}
                onBack={() => {
                  if (
                    squareHoleRun?.runId &&
                    squareHoleRun.status.toLowerCase() === 'running'
                  ) {
                    void stopSquareHoleRun(squareHoleRun.runId).catch(
                      () => undefined,
                    );
                  }
                  setSelectionStage(squareHoleRuntimeReturnStage);
                }}
                onRestart={() => {
                  if (!squareHoleRun?.runId || isSquareHoleBusy) {
                    return;
                  }

                  squareHoleFlow.setIsBusy(true);
                  setSquareHoleError(null);
                  void restartSquareHoleRun(squareHoleRun.runId)
                    .then(({ run }) => {
                      setSquareHoleRun(run);
                    })
                    .catch((error) => {
                      setSquareHoleError(
                        resolveSquareHoleErrorMessage(
                          error,
                          '重新开始方洞挑战失败。',
                        ),
                      );
                    })
                    .finally(() => {
                      squareHoleFlow.setIsBusy(false);
                    });
                }}
                onOptimisticRunChange={setSquareHoleRun}
                onDropShape={(payload) => {
                  const runId = payload.runId ?? squareHoleRun?.runId;
                  if (!runId) {
                    return Promise.reject(
                      new Error('方洞挑战运行态缺少 runId。'),
                    );
                  }
                  return dropSquareHoleShape(runId, payload);
                }}
                onTimeExpired={() => {
                  if (!squareHoleRun?.runId) {
                    return;
                  }

                  void finishSquareHoleTimeUp(squareHoleRun.runId)
                    .then(({ run }) => {
                      setSquareHoleRun(run);
                    })
                    .catch((error) => {
                      setSquareHoleError(
                        resolveSquareHoleErrorMessage(
                          error,
                          '同步方洞挑战倒计时失败。',
                        ),
                      );
                    });
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'jump-hop-workspace' && (
          <motion.div
            key="jump-hop-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载跳一跳创作..." />}
            >
              <UnifiedCreationWorkspace
                playId="jump-hop"
                spec={getUnifiedSpec('jump-hop')}
                isBusy={isJumpHopBusy}
                error={jumpHopError}
                onBack={leaveJumpHopFlow}
                onSubmitted={(result, payload) => {
                  void compileJumpHopSession(result, payload);
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'jump-hop-generating' && (
          <motion.div
            key="jump-hop-generating"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载跳一跳生成面板..." />}
            >
              <UnifiedGenerationPage
                playId="jump-hop"
                settingText={
                  jumpHopSession?.draft?.workTitle?.trim() ||
                  jumpHopSession?.draft?.workDescription?.trim() ||
                  '正在整理跳一跳草稿。'
                }
                anchorEntries={buildJumpHopGenerationAnchorEntries(
                  jumpHopSession,
                  null,
                )}
                progress={buildMiniGameDraftGenerationProgress(
                  jumpHopGenerationState,
                )}
                isGenerating={isJumpHopBusy}
                error={jumpHopError}
                onBack={leaveJumpHopFlow}
                onEditSetting={() => {
                  setSelectionStage('jump-hop-workspace');
                }}
                onRetry={retryJumpHopDraftGeneration}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'jump-hop-result' &&
          (() => {
            const activeJumpHopResultProfile =
              jumpHopWork ?? jumpHopSession?.draft ?? null;

            return (
              <motion.div
                key="jump-hop-result"
                initial={{ opacity: 0, y: 12 }}
                animate={{ opacity: 1, y: 0 }}
                exit={{ opacity: 0, y: -12 }}
                className="flex h-full min-h-0 flex-col"
              >
                {activeJumpHopResultProfile ? (
                  <Suspense
                    fallback={
                      <LazyPanelFallback label="正在加载跳一跳结果..." />
                    }
                  >
                    <JumpHopResultView
                      profile={activeJumpHopResultProfile}
                      error={jumpHopError}
                      onBack={leaveJumpHopFlow}
                      onEdit={() => {
                        setSelectionStage('jump-hop-workspace');
                      }}
                      onStartTestRun={startJumpHopTestRunFromProfile}
                      onPublish={publishJumpHopDraft}
                      onRegenerateCharacter={() => {
                        void regenerateJumpHopAsset('regenerate-character');
                      }}
                      onRegenerateTiles={() => {
                        void regenerateJumpHopAsset('regenerate-tiles');
                      }}
                    />
                  </Suspense>
                ) : (
                  <CreationResultRecoveryPanel
                    title="跳一跳草稿未恢复"
                    message="当前链接缺少可恢复的跳一跳草稿信息。"
                    actionLabel="返回创作"
                    onAction={() => {
                      setSelectionStage('jump-hop-workspace');
                    }}
                  />
                )}
              </motion.div>
            );
          })()}

        {selectionStage === 'jump-hop-runtime' && (
          <motion.div
            key="jump-hop-runtime"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[100]"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载跳一跳玩法..." />}
            >
              <JumpHopRuntimeShell
                snapshot={jumpHopRun}
                profile={jumpHopWork}
                isBusy={isJumpHopBusy}
                error={jumpHopError}
                onBack={() => {
                  setSelectionStage(jumpHopRuntimeReturnStage);
                }}
                onRestart={() => {
                  void restartJumpHopRuntimeRun();
                }}
                onJump={submitJumpHopJumpAction}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'wooden-fish-workspace' && (
          <motion.div
            key="wooden-fish-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载敲木鱼创作..." />}
            >
              <UnifiedCreationWorkspace
                playId="wooden-fish"
                spec={getUnifiedSpec('wooden-fish')}
                isBusy={isWoodenFishBusy}
                error={woodenFishError}
                onBack={leaveWoodenFishFlow}
                onSubmitted={(result, payload) => {
                  void compileWoodenFishSession(result, payload);
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'wooden-fish-generating' && (
          <motion.div
            key="wooden-fish-generating"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载敲木鱼生成面板..." />}
            >
              <UnifiedGenerationPage
                playId="wooden-fish"
                settingText={
                  woodenFishSession?.draft?.workTitle?.trim() ||
                  woodenFishSession?.draft?.workDescription?.trim() ||
                  '正在整理敲木鱼草稿。'
                }
                anchorEntries={buildWoodenFishGenerationAnchorEntries(
                  woodenFishSession,
                  null,
                )}
                progress={buildMiniGameDraftGenerationProgress(
                  woodenFishGenerationState,
                )}
                isGenerating={isWoodenFishBusy}
                error={woodenFishError}
                onBack={leaveWoodenFishFlow}
                onEditSetting={() => {
                  setSelectionStage('wooden-fish-workspace');
                }}
                onRetry={retryWoodenFishDraftGeneration}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'wooden-fish-result' &&
          woodenFishSession?.draft && (
            <motion.div
              key="wooden-fish-result"
              initial={{ opacity: 0, y: 12 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -12 }}
              className="flex h-full min-h-0 flex-col"
            >
              <Suspense
                fallback={<LazyPanelFallback label="正在加载敲木鱼结果..." />}
              >
                <WoodenFishResultView
                  profile={woodenFishWork ?? woodenFishSession.draft}
                  isBusy={isWoodenFishBusy}
                  error={woodenFishError}
                  onBack={leaveWoodenFishFlow}
                  onEdit={() => {
                    setSelectionStage('wooden-fish-workspace');
                  }}
                  onStartTestRun={startWoodenFishTestRunFromProfile}
                  onPublish={publishWoodenFishDraft}
                  onRegenerateHitObject={() => {
                    void regenerateWoodenFishAsset('regenerate-hit-object');
                  }}
                  onUpdateWorkMeta={updateWoodenFishWorkMeta}
                />
              </Suspense>
            </motion.div>
          )}

        {selectionStage === 'wooden-fish-runtime' && (
          <motion.div
            key="wooden-fish-runtime"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[100]"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载敲木鱼玩法..." />}
            >
              <WoodenFishRuntimeShell
                snapshot={woodenFishRun}
                profile={woodenFishWork}
                isBusy={isWoodenFishBusy}
                error={woodenFishError}
                onBack={() => {
                  setSelectionStage(woodenFishRuntimeReturnStage);
                }}
                onCheckpoint={checkpointWoodenFishRuntimeRun}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'creative-agent-workspace' && (
          <motion.div
            key="creative-agent-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载智能创作..." />}
            >
              <UnifiedCreationPage
                spec={getUnifiedSpec('creative-agent')}
                onBack={leaveCreativeAgentWorkspace}
                isBackDisabled={isCreativeAgentBusy || isPuzzleBusy}
              >
                <CreativeAgentWorkspace
                  session={creativeAgentSession}
                  isBusy={isCreativeAgentBusy || isPuzzleBusy}
                  isStreaming={isCreativeAgentStreaming}
                  error={creativeAgentError}
                  eventLog={creativeAgentEvents}
                  onBack={leaveCreativeAgentWorkspace}
                  showBackButton={false}
                  onSubmitMessage={(payload) => {
                    void submitCreativeAgentMessage(payload);
                  }}
                  onConfirmTemplate={(selection) => {
                    void confirmCreativeTemplateSelection(selection);
                  }}
                  onOpenTarget={() => {
                    void openCreativeAgentTarget();
                  }}
                />
              </UnifiedCreationPage>
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'puzzle-agent-workspace' && (
          <motion.div
            key="puzzle-agent-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载拼图创作..." />}
            >
              <UnifiedCreationWorkspace
                playId="puzzle"
                spec={getUnifiedSpec('puzzle')}
                session={puzzleSession}
                isBusy={isStreamingPuzzleReply}
                error={puzzleError}
                onBack={leavePuzzleFlow}
                onSubmitMessage={(payload) => {
                  void submitPuzzleMessage(payload);
                }}
                onExecuteAction={(payload) => {
                  executePuzzleWorkspaceAction(payload);
                }}
                initialFormPayload={puzzleFormDraftPayload}
                onCreateFromForm={(payload) => {
                  void createPuzzleDraftFromForm(payload);
                }}
                onAutoSaveForm={(payload) => {
                  void savePuzzleFormDraft(payload);
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'puzzle-onboarding' && (
          <motion.div
            key="puzzle-onboarding"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[100]"
          >
            <PuzzleOnboardingView
              prompt={puzzleOnboardingPrompt}
              phase={puzzleOnboardingPhase}
              error={puzzleOnboardingError}
              copy={PUZZLE_ONBOARDING_COPY}
              onPromptChange={setPuzzleOnboardingPrompt}
              onSubmit={() => {
                void submitPuzzleOnboardingPrompt();
              }}
              onSkip={skipPuzzleOnboarding}
            />
          </motion.div>
        )}

        {selectionStage === 'puzzle-generating' && (
          <motion.div
            key="puzzle-generating"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载拼图生成面板..." />}
            >
              <UnifiedGenerationPage
                playId="puzzle"
                settingText={
                  puzzleGenerationViewSession?.lastAssistantReply ??
                  '正在整理当前拼图草稿。'
                }
                anchorEntries={buildPuzzleGenerationAnchorEntries(
                  puzzleGenerationViewSession,
                  puzzleGenerationViewPayload,
                )}
                progress={buildMiniGameDraftGenerationProgress(
                  puzzleGenerationViewState,
                  miniGameGenerationProgressNowMs,
                )}
                isGenerating={isPuzzleGenerationViewBusy}
                error={puzzleGenerationViewError}
                onBack={returnToCreationCenterFromGeneration}
                onEditSetting={() => {
                  setSelectionStage('puzzle-agent-workspace');
                }}
                onRetry={retryPuzzleDraftGeneration}
                hideBatchModule
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'puzzle-result' &&
          puzzleSession?.draft &&
          !isPuzzleFormOnlyDraft(puzzleSession) && (
            <motion.div
              key="puzzle-result"
              initial={{ opacity: 0, y: 12 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -12 }}
              className="flex h-full min-h-0 flex-col"
            >
              <Suspense
                fallback={<LazyPanelFallback label="正在加载拼图结果..." />}
              >
                <PuzzleResultView
                  session={puzzleSession}
                  profileId={
                    puzzleSession.publishedProfileId ??
                    buildPuzzleResultProfileId(puzzleSession.sessionId)
                  }
                  isBusy={isPuzzleBusy}
                  error={puzzleError}
                  onBack={leavePuzzleFlow}
                  onExecuteAction={(payload) => {
                    executePuzzleWorkspaceAction(payload);
                  }}
                  onStartTestRun={startPuzzleTestRunFromDraft}
                  creativeDraftEdit={
                    activeCreativeAgentSessionId
                      ? {
                          isBusy: isCreativeDraftEditBusy,
                          error: creativeDraftEditError,
                          onSubmit: submitCreativeDraftEdit,
                        }
                      : null
                  }
                />
              </Suspense>
            </motion.div>
          )}

        {selectionStage === 'visual-novel-agent-workspace' && (
          <motion.div
            key="visual-novel-agent-workspace"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载视觉小说创作..." />}
            >
              <UnifiedCreationPage
                spec={getUnifiedSpec('visual-novel')}
                onBack={leaveVisualNovelFlow}
                isBackDisabled={isVisualNovelBusy || isVisualNovelStreamingReply}
              >
                <VisualNovelAgentWorkspace
                  session={visualNovelSession}
                  isBusy={isVisualNovelBusy || isVisualNovelStreamingReply}
                  error={visualNovelError}
                  onBack={leaveVisualNovelFlow}
                  showBackButton={false}
                  title={null}
                  initialFormPayload={visualNovelFormDraftPayload}
                  onCreateFromForm={(payload) => {
                    void createVisualNovelDraftFromForm(payload);
                  }}
                />
              </UnifiedCreationPage>
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'visual-novel-generating' && (
          <motion.div
            key="visual-novel-generating"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={
                <LazyPanelFallback label="正在加载视觉小说生成面板..." />
              }
            >
              <CustomWorldGenerationView
                settingText={
                  visualNovelFormDraftPayload?.seedText ??
                  visualNovelSession?.messages.find(
                    (message) => message.role === 'user',
                  )?.text ??
                  '正在整理当前视觉小说草稿。'
                }
                anchorEntries={buildVisualNovelEntryGenerationAnchorEntries(
                  visualNovelFormDraftPayload,
                )}
                progress={buildVisualNovelEntryGenerationProgress(
                  visualNovelGenerationStartedAtMs,
                  visualNovelGenerationPhase,
                  miniGameGenerationProgressNowMs,
                )}
                isGenerating={isVisualNovelBusy || isVisualNovelStreamingReply}
                error={visualNovelError}
                onBack={returnToCreationCenterFromGeneration}
                onEditSetting={() => {
                  setSelectionStage('visual-novel-agent-workspace');
                }}
                onRetry={retryVisualNovelDraftGeneration}
                onInterrupt={undefined}
                backLabel="返回创作中心"
                settingActionLabel={null}
                retryLabel="重新生成草稿"
                settingTitle="当前视觉小说信息"
                settingDescription={null}
                progressTitle="视觉小说草稿生成进度"
                activeBadgeLabel="草稿生成中"
                pausedBadgeLabel="草稿生成已暂停"
                idleBadgeLabel="等待返回工作区"
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'visual-novel-result' &&
          (visualNovelSession?.draft || visualNovelWork?.draft) && (
            <motion.div
              key="visual-novel-result"
              initial={{ opacity: 0, y: 12 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -12 }}
              className="flex h-full min-h-0 flex-col"
            >
              <Suspense
                fallback={<LazyPanelFallback label="正在加载视觉小说结果..." />}
              >
                <VisualNovelResultView
                  draft={visualNovelWork?.draft ?? visualNovelSession?.draft}
                  isBusy={isVisualNovelBusy}
                  error={visualNovelError}
                  onBack={() => {
                    if (shouldReturnToDraftShelf()) {
                      leaveVisualNovelFlow();
                      return;
                    }
                    setSelectionStage('visual-novel-agent-workspace');
                  }}
                  onSaveDraft={(draft) => {
                    void saveVisualNovelDraft(draft);
                  }}
                  onCompileWorkProfile={(draft) => {
                    void compileVisualNovelDraft(draft);
                  }}
                  onStartTestRun={(draft) => {
                    void startVisualNovelTestRunFromDraft(draft);
                  }}
                  onPublish={(draft) => {
                    void publishVisualNovelDraft(draft);
                  }}
                />
              </Suspense>
            </motion.div>
          )}

        {selectionStage === 'visual-novel-runtime' && (
          <motion.div
            key="visual-novel-runtime"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[100]"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载视觉小说试玩..." />}
            >
              <VisualNovelRuntimeShell
                draft={visualNovelWork?.draft ?? visualNovelSession?.draft}
                run={visualNovelRun}
                isBusy={isVisualNovelBusy}
                error={visualNovelError}
                onBack={() => {
                  setSelectionStage(visualNovelRuntimeReturnStage);
                }}
                onSubmitAction={(payload) => {
                  void submitVisualNovelRuntimeAction(payload);
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'visual-novel-gallery-detail' &&
          visualNovelWork && (
            <motion.div
              key="visual-novel-gallery-detail"
              initial={{ opacity: 0, y: 12 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -12 }}
              className="flex h-full min-h-0 flex-col"
            >
              <Suspense
                fallback={<LazyPanelFallback label="正在加载视觉小说详情..." />}
              >
                <VisualNovelResultView
                  draft={visualNovelWork.draft}
                  isBusy={isVisualNovelBusy}
                  error={visualNovelError}
                  onBack={() => {
                    setSelectionStage('platform');
                  }}
                  onStartTestRun={(draft) => {
                    setVisualNovelRuntimeReturnStage(
                      'visual-novel-gallery-detail',
                    );
                    void startVisualNovelTestRunFromDraft(draft);
                  }}
                />
              </Suspense>
            </motion.div>
          )}

        {selectionStage === 'puzzle-gallery-detail' && selectedPuzzleDetail && (
          <motion.div
            key="puzzle-gallery-detail"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载拼图详情..." />}
            >
              <PuzzleGalleryDetailView
                item={selectedPuzzleDetail}
                isBusy={isPuzzleBusy}
                error={puzzleError}
                onBack={() => {
                  platformBootstrap.setPlatformTab(
                    puzzleDetailReturnTarget?.tab ?? 'home',
                  );
                  setPuzzleDetailReturnTarget(null);
                  setSelectionStage('platform');
                }}
                onEdit={
                  selectedPuzzleDetail.ownerUserId === authUi?.user?.id &&
                  Boolean(selectedPuzzleDetail.sourceSessionId?.trim())
                    ? () => {
                        runProtectedAction(() => {
                          void openPuzzleDraft(selectedPuzzleDetail);
                        });
                      }
                    : null
                }
                onStartGame={() => {
                  void startPuzzleRunFromProfile(
                    selectedPuzzleDetail.profileId,
                    'puzzle-gallery-detail',
                    selectedPuzzleDetail,
                    false,
                    null,
                    { authMode: 'isolated' },
                  );
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'puzzle-runtime' && (
          <motion.div
            key="puzzle-runtime"
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-[100]"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载拼图玩法..." />}
            >
              <PuzzleRuntimeShell
                run={puzzleRun}
                isBusy={
                  isPuzzleBusy ||
                  isPuzzleNextLevelGenerating ||
                  isPuzzleLeaderboardBusy
                }
                error={puzzleError}
                hideBackButton={Boolean(puzzleOnboardingDraft)}
                onBack={() => {
                  setSelectionStage(puzzleRuntimeReturnStage);
                }}
                onRemodelWork={
                  selectedPuzzleDetail?.publicationStatus === 'published'
                    ? remodelCurrentPuzzleRuntimeWork
                    : undefined
                }
                onSwapPieces={(payload) => {
                  void swapPuzzlePiecesInRun(payload);
                }}
                onDragPiece={(payload) => {
                  void dragPuzzlePiece(payload);
                }}
                onAdvanceNextLevel={(target) => {
                  void advancePuzzleLevel(target);
                }}
                onRestartLevel={() => {
                  void restartPuzzleCurrentLevel();
                }}
                onPauseChange={setPuzzleRuntimePaused}
                onUseProp={usePuzzleProp}
                onTimeExpired={syncPuzzleRuntimeTimeout}
              />
            </Suspense>
            {isPuzzleNextLevelGenerating ? (
              <div className="fixed inset-0 z-[120] flex items-center justify-center bg-slate-950/62 px-5 backdrop-blur-sm">
                <div className="flex max-w-[18rem] flex-col items-center gap-3 rounded-[1.5rem] border border-white/12 bg-slate-950/92 px-6 py-5 text-center text-white shadow-[0_28px_80px_rgba(0,0,0,0.35)]">
                  <Loader2 className="h-6 w-6 animate-spin text-amber-200" />
                  <div className="text-sm font-bold">正在准备下一关</div>
                  <div className="text-xs leading-5 text-white/68">
                    广场暂无可接续作品，正在生成新的候选图。
                  </div>
                </div>
              </div>
            ) : null}
            {puzzleOnboardingDraft &&
            puzzleRun?.currentLevel?.status === 'cleared' ? (
              <PuzzleOnboardingLoginOverlay
                isSaving={isPuzzleOnboardingSaving}
                error={puzzleOnboardingError}
                copy={PUZZLE_ONBOARDING_CLEAR_COPY}
                onLogin={requestPuzzleOnboardingLogin}
              />
            ) : null}
          </motion.div>
        )}

        {selectionStage === 'custom-world-generating' && (
          <motion.div
            key="custom-world-generating"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载世界生成面板..." />}
            >
              <CustomWorldGenerationView
                settingText={sessionController.agentDraftSettingPreview}
                anchorEntries={sessionController.agentDraftAnchorPreviewEntries}
                progress={sessionController.agentDraftGenerationProgress}
                isGenerating={sessionController.isActiveGenerationRunning}
                error={sessionController.activeGenerationError}
                onBack={returnToCreationCenterFromGeneration}
                onEditSetting={leaveAgentDraftGeneration}
                onRetry={() => {
                  void sessionController.executeAgentAction({
                    action: 'draft_foundation',
                  });
                }}
                onInterrupt={undefined}
                backLabel="返回创作中心"
                settingActionLabel={null}
                retryLabel="继续生成草稿"
                settingTitle="当前世界信息"
                settingDescription={null}
                progressTitle="世界草稿生成进度"
                activeBadgeLabel="草稿编译中"
                pausedBadgeLabel="草稿生成已暂停"
                idleBadgeLabel="等待返回工作区"
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'bark-battle-generating' &&
          barkBattleDraftConfig && (
            <motion.div
              key="bark-battle-generating"
              initial={{ opacity: 0, y: 12 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -12 }}
              className="flex h-full min-h-0 flex-col"
            >
              <Suspense
                fallback={<LazyPanelFallback label="正在生成汪汪声浪素材..." />}
              >
                <BarkBattleGeneratingView
                  draft={barkBattleDraftConfig}
                  isBusy={isBarkBattleBusy}
                  error={barkBattleError}
                  onBack={() => {
                    enterCreateTab();
                    selectionStageRef.current = 'platform';
                    setSelectionStage('platform');
                  }}
                  onComplete={handleBarkBattleGenerationComplete}
                  onError={setBarkBattleError}
                />
              </Suspense>
            </motion.div>
          )}

        {selectionStage === 'bark-battle-result' && barkBattleDraftConfig && (
          <motion.div
            key="bark-battle-result"
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -12 }}
            className="flex h-full min-h-0 flex-col"
          >
            <Suspense
              fallback={<LazyPanelFallback label="正在加载汪汪声浪草稿..." />}
            >
              <BarkBattleResultView
                draft={barkBattleDraftConfig}
                isBusy={isBarkBattleBusy}
                error={
                  barkBattleGenerationPartialFailed
                    ? (barkBattleError ??
                      '部分素材未生成成功，可以在对应槽位重新生成或上传。')
                    : barkBattleError
                }
                onBack={() => {
                  if (shouldReturnToDraftShelf()) {
                    leaveBarkBattleFlow();
                    return;
                  }
                  enterCreateTab();
                  selectionStageRef.current = 'platform';
                  setSelectionStage('platform');
                }}
                onDraftChange={(draft) => {
                  void handleBarkBattleDraftChange(draft);
                }}
                onStartTestRun={testBarkBattleDraft}
                onPublish={(draft) => {
                  void publishBarkBattleDraft(draft);
                }}
              />
            </Suspense>
          </motion.div>
        )}

        {selectionStage === 'bark-battle-runtime' &&
          barkBattlePublishedConfig && (
            <motion.div
              key="bark-battle-runtime"
              initial={{ opacity: 0, y: 12 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -12 }}
              className="flex h-full min-h-0 flex-col"
            >
              <Suspense
                fallback={<LazyPanelFallback label="正在加载汪汪声浪试玩..." />}
              >
                <BarkBattleRuntimeShell
                  title={barkBattlePublishedConfig.title}
                  workId={barkBattlePublishedConfig.workId}
                  publishedConfig={barkBattlePublishedConfig}
                  runtimeMode={barkBattleRuntimeMode}
                  onExit={() => {
                    if (
                      barkBattleRuntimeReturnStage === 'bark-battle-result' &&
                      barkBattleDraftConfig
                    ) {
                      setSelectionStage('bark-battle-result');
                    } else {
                      enterCreateTab();
                      setSelectionStage('platform');
                    }
                  }}
                />
              </Suspense>
            </motion.div>
          )}

        {selectionStage === 'custom-world-result' &&
          sessionController.generatedCustomWorldProfile && (
            <motion.div
              key="custom-world-result"
              initial={{ opacity: 0, y: 12 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -12 }}
              className="flex h-full min-h-0 flex-col"
            >
              <Suspense
                fallback={<LazyPanelFallback label="正在加载世界编辑器..." />}
              >
                <RpgCreationResultView
                  profile={sessionController.generatedCustomWorldProfile}
                  previewCharacters={previewCustomWorldCharacters}
                  isGenerating={false}
                  progress={0}
                  progressLabel=""
                  error={resultViewError}
                  onProfileChange={(profile) => {
                    sessionController.setGeneratedCustomWorldProfile(profile);
                  }}
                  onBack={
                    sessionController.isAgentDraftResultView
                      ? () => {
                          leaveAgentDraftResult();
                        }
                      : leaveCustomWorldResult
                  }
                  onEditSetting={undefined}
                  onRegenerate={undefined}
                  onContinueExpand={undefined}
                  onEnterWorld={() => {
                    runProtectedAction(() => {
                      void enterWorldCoordinator
                        .enterWorldFromCurrentResult()
                        .catch((error) => {
                          sessionController.setCustomWorldError(
                            resolveRpgCreationErrorMessage(
                              error,
                              '发布并进入世界失败。',
                            ),
                          );
                        });
                    });
                  }}
                  onTestWorld={
                    sessionController.isAgentDraftResultView &&
                    sessionController.agentSession?.stage !== 'published'
                      ? () => {
                          runProtectedAction(() => {
                            void enterWorldCoordinator
                              .enterWorldForTestFromCurrentResult()
                              .catch((error) => {
                                sessionController.setCustomWorldError(
                                  resolveRpgCreationErrorMessage(
                                    error,
                                    '进入作品测试失败。',
                                  ),
                                );
                              });
                          });
                        }
                      : undefined
                  }
                  onPublishWorld={
                    sessionController.isAgentDraftResultView &&
                    sessionController.agentSession?.stage !== 'published'
                      ? async () => {
                          try {
                            const publishedProfile =
                              await enterWorldCoordinator.publishCurrentResult();
                            void openRpgPublishShareModal(publishedProfile);
                          } catch (error) {
                            sessionController.setCustomWorldError(
                              resolveRpgCreationErrorMessage(
                                error,
                                '发布到广场失败。',
                              ),
                            );
                            throw error;
                          }
                        }
                      : undefined
                  }
                  onGenerateEntity={
                    sessionController.isAgentDraftResultView
                      ? async (kind) => {
                          const action =
                            kind === 'landmark'
                              ? 'generate_landmarks'
                              : 'generate_characters';
                          await autosaveCoordinator.executeAgentActionAndWait({
                            action,
                            count: 1,
                            ...(kind === 'playable'
                              ? { roleType: 'playable' as const }
                              : kind === 'story'
                                ? { roleType: 'story' as const }
                                : {}),
                          });
                          const latestView =
                            sessionController.activeAgentSessionId
                              ? await sessionController.syncAgentCreationResultView(
                                  sessionController.activeAgentSessionId,
                                )
                              : null;
                          const latestProfile =
                            rpgCreationPreviewAdapter.buildPreviewFromResultView(
                              latestView,
                            );
                          if (latestProfile) {
                            sessionController.setGeneratedCustomWorldProfile(
                              latestProfile,
                            );
                          }
                          return { profile: latestProfile };
                        }
                      : undefined
                  }
                  onDeleteEntities={
                    sessionController.isAgentDraftResultView
                      ? async (kind, ids) => {
                          if (ids.length === 0) return;
                          await autosaveCoordinator.executeAgentActionAndWait(
                            kind === 'story'
                              ? { action: 'delete_characters', roleIds: ids }
                              : { action: 'delete_landmarks', sceneIds: ids },
                          );
                          const latestView =
                            sessionController.activeAgentSessionId
                              ? await sessionController.syncAgentCreationResultView(
                                  sessionController.activeAgentSessionId,
                                )
                              : null;
                          const latestProfile =
                            rpgCreationPreviewAdapter.buildPreviewFromResultView(
                              latestView,
                            );
                          if (latestProfile) {
                            sessionController.setGeneratedCustomWorldProfile(
                              latestProfile,
                            );
                          }
                        }
                      : undefined
                  }
                  readOnly={false}
                  compactAgentResultMode={
                    sessionController.isAgentDraftResultView
                  }
                  backLabel={
                    sessionController.isAgentDraftResultView
                      ? '返回创作'
                      : undefined
                  }
                  editActionLabel="继续调整设定"
                  enterWorldActionLabel={
                    sessionController.isAgentDraftResultView &&
                    sessionController.agentSession?.stage !== 'published'
                      ? '发布并进入世界'
                      : '进入世界'
                  }
                  publishReady={
                    sessionController.isAgentDraftResultView
                      ? agentResultPublishGateView.publishReady
                      : true
                  }
                  publishBlockers={
                    sessionController.isAgentDraftResultView
                      ? agentResultPublishGateView.blockers
                      : []
                  }
                  qualityFindings={
                    sessionController.isAgentDraftResultView
                      ? agentResultPreviewQualityFindings
                      : []
                  }
                  previewSourceLabel={
                    sessionController.isAgentDraftResultView
                      ? agentResultPreviewSourceLabel
                      : null
                  }
                  autoSaveState={autosaveCoordinator.customWorldAutoSaveState}
                />
              </Suspense>
            </motion.div>
          )}
      </AnimatePresence>

      {creationEntryConfig ? (
        <PlatformEntryCreationTypeModal
          isOpen={showCreationTypeModal}
          isBusy={
            sessionController.isCreatingAgentSession ||
            isCreativeAgentBusy ||
            isCreativeAgentStreaming ||
            isBigFishBusy ||
            isMatch3DBusy ||
            isSquareHoleBusy ||
            isPuzzleBusy ||
            isJumpHopBusy ||
            isWoodenFishBusy ||
            (isVisualNovelCreationOpen && isVisualNovelBusy) ||
            (isVisualNovelCreationOpen && isVisualNovelStreamingReply) ||
            isBabyObjectMatchBusy
          }
          entryConfig={creationEntryConfig}
          creationTypes={creationEntryTypes}
          onClose={() => {
            if (
              sessionController.isCreatingAgentSession ||
              isCreativeAgentBusy ||
              isCreativeAgentStreaming ||
              isBigFishBusy ||
              isMatch3DBusy ||
              isSquareHoleBusy ||
              isPuzzleBusy ||
              isJumpHopBusy ||
              isWoodenFishBusy ||
              (isVisualNovelCreationOpen && isVisualNovelBusy) ||
              (isVisualNovelCreationOpen && isVisualNovelStreamingReply) ||
              isBabyObjectMatchBusy
            ) {
              return;
            }
            setShowCreationTypeModal(false);
          }}
          onSelectRpg={() => {
            runProtectedAction(() => {
              void sessionController.openRpgAgentWorkspace();
            });
          }}
          onSelectBigFish={() => {
            runProtectedAction(() => {
              void openBigFishAgentWorkspace();
            });
          }}
          onSelectMatch3D={() => {
            handleCreationHubCreateType('match3d');
          }}
          onSelectSquareHole={() => {
            runProtectedAction(() => {
              void openSquareHoleAgentWorkspace();
            });
          }}
          onSelectPuzzle={() => {
            handleCreationHubCreateType('puzzle');
          }}
          onSelectJumpHop={() => {
            handleCreationHubCreateType('jump-hop');
          }}
          onSelectWoodenFish={() => {
            handleCreationHubCreateType('wooden-fish');
          }}
          onSelectCreativeAgent={() => {
            runProtectedAction(() => {
              void openCreativeAgentWorkspace();
            });
          }}
          onSelectBarkBattle={() => {
            handleCreationHubCreateType('bark-battle');
          }}
          onSelectVisualNovel={() => {
            handleCreationHubCreateType('visual-novel');
          }}
          onSelectBabyObjectMatch={() => {
            handleCreationHubCreateType('baby-object-match');
          }}
        />
      ) : null}
      <UnifiedModal
        open={Boolean(draftGenerationPointNotice)}
        title={draftGenerationPointNotice?.title ?? '泥点提示'}
        description={draftGenerationPointNoticeDescription}
        onClose={() => setDraftGenerationPointNotice(null)}
        closeOnBackdrop
        size="sm"
        overlayClassName={`platform-theme ${platformThemeClass} !items-center`}
        panelClassName="platform-remap-surface rounded-[1.75rem]"
        footer={
          <button
            type="button"
            onClick={() => setDraftGenerationPointNotice(null)}
            className="platform-button platform-button--primary min-h-0 rounded-full px-4 py-2 text-sm"
          >
            知道了
          </button>
        }
      >
        <div className="text-sm leading-6 text-[var(--platform-text-base)]">
          {draftGenerationPointNotice?.message}
        </div>
      </UnifiedModal>
      <PublishShareModal
        open={Boolean(publishSharePayload)}
        payload={publishSharePayload}
        onClose={() => setPublishSharePayload(null)}
      />
      <PlatformErrorDialog
        error={activePlatformErrorDialog}
        onClose={closePlatformErrorDialog}
        overlayClassName={`platform-theme ${platformThemeClass} !items-center`}
        panelClassName="platform-remap-surface rounded-[1.5rem]"
      />
      <PlatformTaskCompletionDialog
        completion={activePlatformTaskCompletionDialog}
        onClose={closePlatformTaskCompletionDialog}
        overlayClassName={`platform-theme ${platformThemeClass} !items-center`}
        panelClassName="platform-remap-surface rounded-[1.5rem]"
      />
      <UnifiedModal
        open={Boolean(pendingDeleteCreationWork)}
        title="删除作品"
        description={
          pendingDeleteCreationWork
            ? `确认删除《${pendingDeleteCreationWork.title}》吗？`
            : undefined
        }
        onClose={closeDeleteCreationWorkConfirmation}
        closeDisabled={Boolean(deletingCreationWorkId)}
        closeOnBackdrop={!deletingCreationWorkId}
        size="sm"
        overlayClassName={`platform-theme ${platformThemeClass} !items-center`}
        panelClassName="platform-remap-surface rounded-[1.75rem]"
        footer={
          <>
            <button
              type="button"
              onClick={closeDeleteCreationWorkConfirmation}
              disabled={Boolean(deletingCreationWorkId)}
              className="platform-button platform-button--ghost min-h-0 rounded-full px-4 py-2 text-sm"
            >
              取消
            </button>
            <button
              type="button"
              onClick={confirmDeleteCreationWork}
              disabled={Boolean(deletingCreationWorkId)}
              className="platform-button platform-button--danger min-h-0 rounded-full px-4 py-2 text-sm disabled:cursor-not-allowed disabled:opacity-55"
            >
              {deletingCreationWorkId ? '删除中' : '确认删除'}
            </button>
          </>
        }
      >
        <div className="text-sm leading-6 text-[var(--platform-text-base)]">
          {pendingDeleteCreationWork?.detail}
        </div>
      </UnifiedModal>
      <AnimatePresence>
        {(searchedPublicUser || publicSearchError) && (
          <motion.div
            initial={{ opacity: 0 }}
            animate={{ opacity: 1 }}
            exit={{ opacity: 0 }}
            className="fixed inset-0 z-50 flex items-center justify-center bg-black/45 p-4"
          >
            <div className="platform-surface w-full max-w-md rounded-[1.6rem] p-5">
              <div className="flex items-start justify-between gap-4">
                <div>
                  <div className="text-sm font-semibold text-[var(--platform-text-soft)]">
                    公开编号搜索
                  </div>
                  <div className="mt-1 text-xl font-black text-[var(--platform-text-strong)]">
                    {publicSearchError ? '未找到结果' : '命中用户'}
                  </div>
                </div>
                <button
                  type="button"
                  onClick={() => {
                    setSearchedPublicUser(null);
                    setPublicSearchError(null);
                  }}
                  className="platform-icon-button"
                  aria-label="关闭搜索结果"
                >
                  ×
                </button>
              </div>
              {publicSearchError ? (
                <div className="mt-4 text-sm leading-6 text-[var(--platform-text-soft)]">
                  {publicSearchError}
                </div>
              ) : searchedPublicUser ? (
                <div className="mt-4 rounded-[1.2rem] border border-[var(--platform-line-soft)] p-4">
                  <div className="text-lg font-bold text-[var(--platform-text-strong)]">
                    {searchedPublicUser.displayName}
                  </div>
                  <div className="mt-2 text-sm text-[var(--platform-text-soft)]">
                    陶泥号 {searchedPublicUser.publicUserCode}
                  </div>
                </div>
              ) : null}
            </div>
          </motion.div>
        )}
      </AnimatePresence>
    </>
  );
}

export default PlatformEntryFlowShellImpl;
