import {
  ArrowLeft,
  CheckCircle2,
  ImagePlus,
  Images,
  Loader2,
  Play,
  Plus,
  RefreshCw,
  Send,
  Trash2,
} from 'lucide-react';
import { type ChangeEvent, useEffect, useMemo, useState } from 'react';
import { createPortal } from 'react-dom';

import type { SquareHoleResultDraft } from '../../../packages/shared/src/contracts/squareHoleAgent';
import type {
  PutSquareHoleWorkRequest,
  SquareHoleHoleOption,
  SquareHoleShapeOption,
  SquareHoleWorkProfile,
} from '../../../packages/shared/src/contracts/squareHoleWorks';
import {
  publishSquareHoleWork,
  regenerateSquareHoleWorkImage,
  squareHoleAssetClient,
  type SquareHoleHistoryAsset,
  type SquareHoleImageAssetKind,
  updateSquareHoleWork,
} from '../../services/square-hole-works';
import { useAuthUi } from '../auth/AuthUiContext';
import { PlatformActionButton } from '../common/PlatformActionButton';
import { PlatformAssetPickerGrid } from '../common/PlatformAssetPickerCard';
import { PlatformFieldLabel } from '../common/PlatformFieldLabel';
import { PlatformIconButton } from '../common/PlatformIconButton';
import { PlatformMediaFrame } from '../common/PlatformMediaFrame';
import { PlatformModalCloseButton } from '../common/PlatformModalCloseButton';
import { PlatformPillBadge } from '../common/PlatformPillBadge';
import { PlatformStatGrid } from '../common/PlatformStatGrid';
import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
import { PlatformSubpanel } from '../common/PlatformSubpanel';
import {
  PlatformSelectField,
  PlatformTextField,
} from '../common/PlatformTextField';

type SquareHoleResultViewProps = {
  profile: SquareHoleWorkProfile;
  draft?: SquareHoleResultDraft | null;
  isBusy?: boolean;
  error?: string | null;
  onBack: () => void;
  onSaved?: (profile: SquareHoleWorkProfile) => void;
  onPublished?: (profile: SquareHoleWorkProfile) => void;
  onStartTestRun: (profile: SquareHoleWorkProfile) => void;
};

type SquareHoleAutoSaveState = 'idle' | 'saving' | 'saved' | 'error';

type SquareHoleResultEditState = {
  gameName: string;
  summary: string;
  tagsText: string;
  coverImageSrc: string;
  backgroundPrompt: string;
  backgroundImageSrc: string;
  themeText: string;
  twistRule: string;
  shapeOptions: SquareHoleShapeOption[];
  holeOptions: SquareHoleHoleOption[];
  shapeCountText: string;
  difficulty: number;
};

type SquareHoleImageSlot = {
  kind: 'cover' | 'background' | 'shape' | 'hole';
  title: string;
  assetKind: SquareHoleImageAssetKind;
  shapeOptionId?: string;
  holeOptionId?: string;
};

const SQUARE_HOLE_AUTOSAVE_DEBOUNCE_MS = 600;
const SQUARE_HOLE_SHAPE_KIND_OPTIONS = [
  'square',
  'circle',
  'triangle',
  'star',
  'arch',
  'diamond',
];

function fallbackHoleOptionId(index: number) {
  return `hole-${index + 1}`;
}

function resolveFirstHoleId(holeOptions: SquareHoleHoleOption[]) {
  return (
    holeOptions.find((option) => option.holeId.trim())?.holeId.trim() ?? ''
  );
}

function resolveShapeTargetHoleId(
  option: SquareHoleShapeOption,
  index: number,
  holeOptions: SquareHoleHoleOption[],
) {
  const holeIds = holeOptions
    .map((holeOption) => holeOption.holeId.trim())
    .filter(Boolean);
  const currentTarget = option.targetHoleId?.trim() ?? '';
  if (holeIds.includes(currentTarget)) {
    return currentTarget;
  }
  return holeIds[index % Math.max(1, holeIds.length)] ?? '';
}

function remapShapeTargetsToHoles(
  shapeOptions: SquareHoleShapeOption[],
  holeOptions: SquareHoleHoleOption[],
) {
  return shapeOptions.map((option, index) => ({
    ...option,
    targetHoleId: resolveShapeTargetHoleId(option, index, holeOptions),
  }));
}

function normalizeTags(value: string) {
  return [
    ...new Set(
      value
        .split(/[\n,，、]/u)
        .map((entry) => entry.trim())
        .filter(Boolean),
    ),
  ];
}

function normalizeShapeCount(value: string) {
  const parsed = Number.parseInt(value.trim(), 10);
  return Number.isFinite(parsed) && parsed >= 6 && parsed <= 24 ? parsed : null;
}

function createEditState(
  profile: SquareHoleWorkProfile,
): SquareHoleResultEditState {
  const holeOptions = profile.holeOptions.map((option, index) => {
    const holeId = option.holeId.trim() || fallbackHoleOptionId(index);
    return {
      ...option,
      holeId,
      holeKind: option.holeKind.trim() || holeId,
      imagePrompt: option.imagePrompt ?? '',
      imageSrc: option.imageSrc ?? null,
    };
  });
  const shapeOptions = remapShapeTargetsToHoles(
    profile.shapeOptions.map((option) => ({
      ...option,
      targetHoleId: option.targetHoleId ?? '',
    })),
    holeOptions,
  );

  return {
    gameName: profile.gameName,
    summary: profile.summary,
    tagsText: profile.tags.join('，'),
    coverImageSrc: profile.coverImageSrc?.trim() || '',
    backgroundPrompt: profile.backgroundPrompt || '',
    backgroundImageSrc: profile.backgroundImageSrc?.trim() || '',
    themeText: profile.themeText,
    twistRule: profile.twistRule,
    shapeOptions,
    holeOptions,
    shapeCountText: String(profile.shapeCount),
    difficulty: profile.difficulty,
  };
}

function buildSavePayload(
  editState: SquareHoleResultEditState,
): PutSquareHoleWorkRequest | null {
  const shapeCount = normalizeShapeCount(editState.shapeCountText);
  const gameName = editState.gameName.trim();
  const themeText = editState.themeText.trim();
  const twistRule = editState.twistRule.trim();
  const summary = editState.summary.trim();
  const tags = normalizeTags(editState.tagsText);
  const shapeOptions = editState.shapeOptions
    .map((option) => ({
      optionId: option.optionId.trim(),
      shapeKind: option.shapeKind.trim(),
      label: option.label.trim(),
      targetHoleId: option.targetHoleId.trim(),
      imagePrompt: option.imagePrompt.trim(),
      imageSrc: option.imageSrc?.trim() || null,
    }))
    .filter(
      (option) =>
        option.optionId &&
        option.shapeKind &&
        option.label &&
        option.targetHoleId &&
        option.imagePrompt,
    );
  const holeOptions = editState.holeOptions
    .map((option, index) => {
      const holeId = option.holeId.trim() || fallbackHoleOptionId(index);
      return {
        holeId,
        holeKind: holeId,
        label: option.label.trim(),
        imagePrompt: option.imagePrompt.trim(),
        imageSrc: option.imageSrc?.trim() || null,
      };
    })
    .filter((option) => option.holeId && option.label && option.imagePrompt);
  const holeIdSet = new Set(holeOptions.map((option) => option.holeId));
  const hasInvalidShapeTarget = shapeOptions.some(
    (option) => !holeIdSet.has(option.targetHoleId),
  );

  if (
    !gameName ||
    !themeText ||
    !twistRule ||
    !summary ||
    tags.length === 0 ||
    shapeOptions.length === 0 ||
    holeOptions.length === 0 ||
    hasInvalidShapeTarget ||
    !shapeCount
  ) {
    return null;
  }

  return {
    gameName,
    themeText,
    twistRule,
    summary,
    tags,
    coverImageSrc: editState.coverImageSrc.trim() || null,
    backgroundPrompt: editState.backgroundPrompt.trim(),
    backgroundImageSrc: editState.backgroundImageSrc.trim() || null,
    shapeOptions,
    holeOptions,
    shapeCount,
    difficulty: editState.difficulty,
  };
}

function buildPublishBlockers(editState: SquareHoleResultEditState) {
  const blockers = [
    ...(editState.gameName.trim() ? [] : ['游戏名称不能为空。']),
    ...(editState.themeText.trim() ? [] : ['题材主题不能为空。']),
    ...(editState.twistRule.trim() ? [] : ['反差规则不能为空。']),
    ...(editState.summary.trim() ? [] : ['简介不能为空。']),
    ...(normalizeTags(editState.tagsText).length > 0
      ? []
      : ['至少需要 1 个标签。']),
    ...(editState.shapeOptions.some(
      (option) =>
        option.optionId.trim() &&
        option.shapeKind.trim() &&
        option.label.trim() &&
        option.targetHoleId.trim() &&
        option.imagePrompt.trim(),
    )
      ? []
      : ['至少需要 1 个形状选项。']),
    ...(editState.holeOptions.some(
      (option) =>
        option.holeId.trim() &&
        option.label.trim() &&
        option.imagePrompt.trim(),
    )
      ? []
      : ['至少需要 1 个洞口选项。']),
    ...(editState.shapeOptions.every((option) =>
      editState.holeOptions.some(
        (holeOption) => holeOption.holeId.trim() === option.targetHoleId.trim(),
      ),
    )
      ? []
      : ['每个展示选项都需要绑定一个洞口选项。']),
    ...(normalizeShapeCount(editState.shapeCountText)
      ? []
      : ['形状数量需要在 6 到 24 之间。']),
  ];

  return [...new Set(blockers)];
}

function readImageAsDataUrl(file: File) {
  return new Promise<string>((resolve, reject) => {
    if (!file.type.startsWith('image/')) {
      reject(new Error('请选择图片文件。'));
      return;
    }

    const reader = new FileReader();
    reader.onerror = () => reject(new Error('封面图读取失败，请重试。'));
    reader.onload = () => resolve(String(reader.result || ''));
    reader.readAsDataURL(file);
  });
}

function createShapeOption(
  index: number,
  holeOptions: SquareHoleHoleOption[],
): SquareHoleShapeOption {
  return {
    optionId: `shape-${Date.now().toString(36)}-${index}`,
    shapeKind:
      SQUARE_HOLE_SHAPE_KIND_OPTIONS[
        index % SQUARE_HOLE_SHAPE_KIND_OPTIONS.length
      ] ?? 'square',
    label: `形状 ${index + 1}`,
    targetHoleId: resolveFirstHoleId(holeOptions),
    imagePrompt: '主题贴图',
    imageSrc: null,
  };
}

function createHoleOption(index: number): SquareHoleHoleOption {
  const holeId = `hole-${Date.now().toString(36)}-${index}`;
  return {
    holeId,
    holeKind: holeId,
    label: `洞口 ${index + 1}`,
    imagePrompt: `洞口 ${index + 1}贴图，透明背景，游戏资产`,
    imageSrc: null,
  };
}

function formatHistoryAssetDate(value: string) {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) {
    return value || '';
  }
  return date.toLocaleString('zh-CN', {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function resolveImageSlotSrc(
  editState: SquareHoleResultEditState,
  slot: SquareHoleImageSlot,
) {
  if (slot.kind === 'cover') {
    return editState.coverImageSrc;
  }
  if (slot.kind === 'background') {
    return editState.backgroundImageSrc;
  }
  if (slot.kind === 'hole') {
    return (
      editState.holeOptions
        .find((option) => option.holeId === slot.holeOptionId)
        ?.imageSrc?.trim() || ''
    );
  }
  return (
    editState.shapeOptions
      .find((option) => option.optionId === slot.shapeOptionId)
      ?.imageSrc?.trim() || ''
  );
}

function applyImageSlotSrc(
  current: SquareHoleResultEditState,
  slot: SquareHoleImageSlot,
  imageSrc: string,
): SquareHoleResultEditState {
  if (slot.kind === 'cover') {
    return {
      ...current,
      coverImageSrc: imageSrc,
    };
  }
  if (slot.kind === 'background') {
    return {
      ...current,
      backgroundImageSrc: imageSrc,
    };
  }
  if (slot.kind === 'hole') {
    return {
      ...current,
      holeOptions: current.holeOptions.map((option) =>
        option.holeId === slot.holeOptionId
          ? {
              ...option,
              imageSrc,
            }
          : option,
      ),
    };
  }
  return {
    ...current,
    shapeOptions: current.shapeOptions.map((option) =>
      option.optionId === slot.shapeOptionId
        ? {
            ...option,
            imageSrc,
          }
        : option,
    ),
  };
}

function buildPlayableProfile(
  profile: SquareHoleWorkProfile,
  editState: SquareHoleResultEditState,
) {
  const payload = buildSavePayload(editState);
  if (!payload) {
    return profile;
  }

  return {
    ...profile,
    gameName: payload.gameName,
    themeText: payload.themeText ?? profile.themeText,
    twistRule: payload.twistRule,
    summary: payload.summary,
    tags: payload.tags,
    coverImageSrc: payload.coverImageSrc,
    backgroundPrompt: payload.backgroundPrompt ?? profile.backgroundPrompt,
    backgroundImageSrc: payload.backgroundImageSrc,
    shapeOptions: payload.shapeOptions ?? profile.shapeOptions,
    holeOptions: payload.holeOptions ?? profile.holeOptions,
    shapeCount: payload.shapeCount,
    difficulty: payload.difficulty ?? profile.difficulty,
  };
}

function SquareHoleResultHeader({
  autoSaveState,
  isBusy,
  onBack,
}: {
  autoSaveState: SquareHoleAutoSaveState;
  isBusy: boolean;
  onBack: () => void;
}) {
  const badge =
    autoSaveState === 'saving' ? (
      <PlatformPillBadge tone="warning" size="xs" className="px-3 py-1">
        保存中
      </PlatformPillBadge>
    ) : autoSaveState === 'saved' ? (
      <PlatformPillBadge tone="success" size="xs" className="px-3 py-1">
        已自动保存
      </PlatformPillBadge>
    ) : autoSaveState === 'error' ? (
      <PlatformPillBadge tone="danger" size="xs" className="px-3 py-1">
        保存失败
      </PlatformPillBadge>
    ) : null;

  return (
    <div className="mb-4 flex items-center justify-between gap-3">
      <PlatformActionButton
        onClick={onBack}
        disabled={isBusy}
        tone="ghost"
        size="xs"
        className="min-h-0 self-start gap-1.5 px-3 py-1.5 text-[11px]"
      >
        <ArrowLeft className="h-3.5 w-3.5" />
        返回
      </PlatformActionButton>
      {badge}
    </div>
  );
}

function SquareHoleImageSlotDialog({
  currentImageSrc,
  canRegenerateImages,
  isBusy,
  isRegeneratingImages,
  slot,
  onClose,
  onRegenerateImages,
  onSelectHistory,
  onUpload,
}: {
  currentImageSrc: string;
  canRegenerateImages: boolean;
  isBusy: boolean;
  isRegeneratingImages: boolean;
  slot: SquareHoleImageSlot;
  onClose: () => void;
  onRegenerateImages: () => void;
  onSelectHistory: (asset: SquareHoleHistoryAsset) => void;
  onUpload: (
    slot: SquareHoleImageSlot,
    event: ChangeEvent<HTMLInputElement>,
  ) => void;
}) {
  const platformTheme = useAuthUi()?.platformTheme ?? 'light';
  const [assets, setAssets] = useState<SquareHoleHistoryAsset[]>([]);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    setIsLoading(true);
    setError(null);
    squareHoleAssetClient
      .listHistoryAssets({ kind: slot.assetKind, limit: 120 })
      .then((nextAssets) => {
        if (!cancelled) {
          setAssets(nextAssets);
        }
      })
      .catch((loadError) => {
        if (!cancelled) {
          setError(
            loadError instanceof Error
              ? loadError.message
              : '历史图片读取失败。',
          );
        }
      })
      .finally(() => {
        if (!cancelled) {
          setIsLoading(false);
        }
      });

    return () => {
      cancelled = true;
    };
  }, [slot.assetKind]);

  if (typeof document === 'undefined') {
    return null;
  }

  return createPortal(
    <div
      className={`platform-theme platform-theme--${platformTheme} platform-overlay fixed inset-0 z-[145] flex items-end justify-center p-3 backdrop-blur-sm sm:items-center sm:p-4`}
      onClick={(event) => {
        if (event.target === event.currentTarget) {
          onClose();
        }
      }}
    >
      <div
        role="dialog"
        aria-modal="true"
        aria-label={`${slot.title}查看`}
        className="platform-modal-shell platform-remap-surface flex max-h-[min(92vh,46rem)] w-full max-w-5xl flex-col overflow-hidden rounded-t-[1.75rem] shadow-[0_24px_80px_rgba(0,0,0,0.55)] sm:rounded-[1.75rem]"
        onClick={(event) => event.stopPropagation()}
      >
        <div className="flex items-center justify-between gap-3 border-b border-[var(--platform-subpanel-border)] px-5 py-4">
          <div className="text-base font-semibold text-[var(--platform-text-strong)]">
            {slot.title}
          </div>
          <PlatformModalCloseButton
            onClick={onClose}
            label="关闭"
            variant="platformIcon"
          />
        </div>

        <div className="min-h-0 flex-1 overflow-y-auto px-5 py-4">
          <div className="grid gap-4 lg:grid-cols-[minmax(0,1fr)_minmax(16rem,0.78fr)]">
            <div className="space-y-3">
              <PlatformMediaFrame
                src={currentImageSrc}
                alt={slot.title}
                fallbackLabel={`${slot.title}占位图`}
                fallbackContent={<Images className="h-10 w-10" />}
                aspect="standard"
                surface="plain"
                className="rounded-[1.35rem]"
                fallbackClassName="tracking-normal text-[var(--platform-text-soft)]"
              />
              <div className="grid gap-2 sm:grid-cols-2">
                <PlatformActionButton
                  asChild="label"
                  tone="ghost"
                  size="md"
                  aria-disabled={isBusy}
                  className={`min-h-11 cursor-pointer gap-2 px-4 ${isBusy ? 'cursor-not-allowed opacity-55' : ''}`}
                >
                  <ImagePlus className="h-4 w-4" />
                  上传图片
                  <input
                    type="file"
                    accept="image/*"
                    className="sr-only"
                    disabled={isBusy}
                    onChange={(event) => onUpload(slot, event)}
                  />
                </PlatformActionButton>
                <PlatformActionButton
                  onClick={onRegenerateImages}
                  disabled={!canRegenerateImages || isBusy}
                  tone="secondary"
                  size="md"
                  className="min-h-11 gap-2 px-4"
                >
                  {isRegeneratingImages ? (
                    <Loader2 className="h-4 w-4 animate-spin" />
                  ) : (
                    <RefreshCw className="h-4 w-4" />
                  )}
                  AI生成图片
                </PlatformActionButton>
              </div>
            </div>

            <div className="min-h-0 space-y-3">
              <PlatformFieldLabel
                variant="section"
                className="flex items-center gap-2"
              >
                <Images className="h-3.5 w-3.5" />
                历史生成
              </PlatformFieldLabel>

              <PlatformAssetPickerGrid
                items={assets}
                isLoading={isLoading}
                error={error}
                loadingLabel="读取中..."
                emptyLabel="暂无历史图片"
                disabled={isBusy}
                getKey={(asset) => asset.assetObjectId}
                getImageSrc={(asset) => asset.imageSrc}
                getImageAlt={(asset) => asset.ownerLabel || '历史图片'}
                getTitle={(asset) => asset.ownerLabel || '未记录账号'}
                getSubtitle={(asset) => formatHistoryAssetDate(asset.createdAt)}
                onSelect={onSelectHistory}
                gridClassName="grid max-h-[24rem] grid-cols-2 gap-3 overflow-y-auto pr-1 sm:grid-cols-3 lg:grid-cols-2 xl:grid-cols-3"
              />
            </div>
          </div>
        </div>
      </div>
    </div>,
    document.body,
  );
}

export function SquareHoleResultView({
  profile,
  draft = null,
  isBusy = false,
  error = null,
  onBack,
  onSaved,
  onPublished,
  onStartTestRun,
}: SquareHoleResultViewProps) {
  const [editState, setEditState] = useState(() => createEditState(profile));
  const [autoSaveState, setAutoSaveState] =
    useState<SquareHoleAutoSaveState>('idle');
  const [localError, setLocalError] = useState<string | null>(null);
  const [isPublishing, setIsPublishing] = useState(false);
  const [isRegeneratingImages, setIsRegeneratingImages] = useState(false);
  const [isApplyingHistoryImage, setIsApplyingHistoryImage] = useState(false);
  const [isStartingTestRun, setIsStartingTestRun] = useState(false);
  const [activeImageSlot, setActiveImageSlot] =
    useState<SquareHoleImageSlot | null>(null);
  const blockers = useMemo(() => buildPublishBlockers(editState), [editState]);
  const canSubmit = blockers.length === 0;

  useEffect(() => {
    setEditState(createEditState(profile));
    setAutoSaveState('idle');
    setLocalError(null);
  }, [profile]);

  useEffect(() => {
    if (
      isApplyingHistoryImage ||
      isPublishing ||
      isRegeneratingImages ||
      isStartingTestRun
    ) {
      return undefined;
    }

    const payload = buildSavePayload(editState);
    if (!payload) {
      return undefined;
    }

    const currentPayload = buildSavePayload(createEditState(profile));
    const changed =
      !currentPayload ||
      payload.gameName !== currentPayload.gameName ||
      payload.themeText !== currentPayload.themeText ||
      payload.twistRule !== currentPayload.twistRule ||
      payload.summary !== currentPayload.summary ||
      (payload.coverImageSrc ?? '') !== (currentPayload.coverImageSrc ?? '') ||
      (payload.backgroundPrompt ?? '') !==
        (currentPayload.backgroundPrompt ?? '') ||
      (payload.backgroundImageSrc ?? '') !==
        (currentPayload.backgroundImageSrc ?? '') ||
      payload.shapeCount !== currentPayload.shapeCount ||
      JSON.stringify(payload.shapeOptions ?? []) !==
        JSON.stringify(currentPayload.shapeOptions ?? []) ||
      JSON.stringify(payload.holeOptions ?? []) !==
        JSON.stringify(currentPayload.holeOptions ?? []) ||
      payload.tags.length !== currentPayload.tags.length ||
      payload.tags.some((tag, index) => tag !== currentPayload.tags[index]);

    if (!changed) {
      return undefined;
    }

    setAutoSaveState('saving');
    setLocalError(null);
    let cancelled = false;
    const timer = window.setTimeout(() => {
      void updateSquareHoleWork(profile.profileId, payload)
        .then(({ item }) => {
          if (cancelled) {
            return;
          }
          setAutoSaveState('saved');
          onSaved?.(item);
        })
        .catch((saveError) => {
          if (cancelled) {
            return;
          }
          setAutoSaveState('error');
          setLocalError(
            saveError instanceof Error ? saveError.message : '自动保存失败。',
          );
        });
    }, SQUARE_HOLE_AUTOSAVE_DEBOUNCE_MS);

    return () => {
      cancelled = true;
      window.clearTimeout(timer);
    };
  }, [
    editState,
    isApplyingHistoryImage,
    isPublishing,
    isRegeneratingImages,
    isStartingTestRun,
    onSaved,
    profile,
  ]);

  const saveStateNow = async (state: SquareHoleResultEditState) => {
    const payload = buildSavePayload(state);
    if (!payload) {
      setLocalError(blockers[0] ?? '请补全作品信息。');
      return null;
    }

    setAutoSaveState('saving');
    setLocalError(null);
    const { item } = await updateSquareHoleWork(profile.profileId, payload);
    setAutoSaveState('saved');
    onSaved?.(item);
    return item;
  };

  const saveNow = async () => {
    return saveStateNow(editState);
  };

  const handleImageSlotUpload = async (
    slot: SquareHoleImageSlot,
    event: ChangeEvent<HTMLInputElement>,
  ) => {
    const file = event.target.files?.[0] ?? null;
    event.target.value = '';
    if (!file) {
      return;
    }

    try {
      const dataUrl = await readImageAsDataUrl(file);
      setEditState((current) => applyImageSlotSrc(current, slot, dataUrl));
      setLocalError(null);
    } catch (caughtError) {
      setLocalError(
        caughtError instanceof Error ? caughtError.message : '图片读取失败。',
      );
    }
  };

  const handleStartTestRun = async () => {
    if (!canSubmit || isStartingTestRun) {
      setLocalError(blockers[0] ?? null);
      return;
    }

    setIsStartingTestRun(true);
    try {
      const savedProfile = await saveNow();
      onStartTestRun(savedProfile ?? buildPlayableProfile(profile, editState));
    } catch (caughtError) {
      setLocalError(
        caughtError instanceof Error
          ? caughtError.message
          : '启动试玩前保存失败。',
      );
    } finally {
      setIsStartingTestRun(false);
    }
  };

  const handleRegenerateImages = async () => {
    if (!activeImageSlot || !canSubmit || isRegeneratingImages) {
      setLocalError(blockers[0] ?? null);
      return;
    }

    setIsRegeneratingImages(true);
    try {
      const savedProfile = await saveNow();
      const targetProfile =
        savedProfile ?? buildPlayableProfile(profile, editState);
      const { item } = await regenerateSquareHoleWorkImage(
        targetProfile.profileId,
        {
          visualAssetSlot: activeImageSlot.kind,
          visualAssetOptionId:
            activeImageSlot.shapeOptionId ??
            activeImageSlot.holeOptionId ??
            null,
        },
      );
      setEditState(createEditState(item));
      onSaved?.(item);
      setLocalError(null);
    } catch (caughtError) {
      setLocalError(
        caughtError instanceof Error
          ? caughtError.message
          : '重生成图片前保存失败。',
      );
    } finally {
      setIsRegeneratingImages(false);
    }
  };

  const handleSelectHistoryImage = async (
    slot: SquareHoleImageSlot,
    asset: SquareHoleHistoryAsset,
  ) => {
    if (
      isApplyingHistoryImage ||
      isBusy ||
      isPublishing ||
      isRegeneratingImages ||
      isStartingTestRun
    ) {
      return;
    }

    const nextState = applyImageSlotSrc(editState, slot, asset.imageSrc);
    setEditState(nextState);
    setIsApplyingHistoryImage(true);
    try {
      await saveStateNow(nextState);
      setLocalError(null);
    } catch (caughtError) {
      setLocalError(
        caughtError instanceof Error
          ? caughtError.message
          : '套用历史图片失败。',
      );
    } finally {
      setIsApplyingHistoryImage(false);
    }
  };

  const handlePublish = async () => {
    if (!canSubmit || isPublishing) {
      setLocalError(blockers[0] ?? null);
      return;
    }

    setIsPublishing(true);
    try {
      const savedProfile = await saveNow();
      const { item } = await publishSquareHoleWork(
        savedProfile?.profileId ?? profile.profileId,
      );
      onPublished?.(item);
      setLocalError(null);
    } catch (caughtError) {
      setLocalError(
        caughtError instanceof Error
          ? caughtError.message
          : '发布方洞挑战失败。',
      );
    } finally {
      setIsPublishing(false);
    }
  };

  const busy =
    isBusy ||
    isPublishing ||
    isRegeneratingImages ||
    isApplyingHistoryImage ||
    isStartingTestRun;
  const displayError = error ?? localError;
  const activeImageSrc = activeImageSlot
    ? resolveImageSlotSrc(editState, activeImageSlot)
    : '';

  return (
    <div className="platform-remap-surface mx-auto flex h-full min-h-0 w-full flex-col xl:max-w-[min(100%,88rem)]">
      <SquareHoleResultHeader
        autoSaveState={autoSaveState}
        isBusy={busy}
        onBack={onBack}
      />

      <div className="min-h-0 flex-1 overflow-y-auto pr-1">
        <div className="grid gap-3 lg:grid-cols-[minmax(17rem,0.72fr)_minmax(0,1fr)]">
          <PlatformSubpanel radius="xl" padding="lg">
            <button
              type="button"
              disabled={busy}
              onClick={() =>
                setActiveImageSlot({
                  kind: 'cover',
                  title: '封面图',
                  assetKind: 'square_hole_cover_image',
                })
              }
              className={`group block w-full overflow-hidden rounded-[1.25rem] border border-[var(--platform-subpanel-border)] bg-[radial-gradient(circle_at_42%_30%,rgba(125,211,252,0.28),transparent_34%),linear-gradient(135deg,rgba(15,23,42,0.16),rgba(20,184,166,0.18))] text-left ${busy ? 'cursor-not-allowed opacity-70' : ''}`}
              aria-label="查看封面图"
            >
              <PlatformMediaFrame
                src={editState.coverImageSrc}
                alt=""
                fallbackLabel="封面图"
                fallbackContent={<ImagePlus className="h-10 w-10" />}
                aspect="standard"
                surface="none"
                className="rounded-none bg-transparent"
                fallbackClassName="tracking-normal text-slate-700"
              />
            </button>
            <PlatformStatGrid
              items={[
                { value: `${editState.shapeCountText || '-'} 个` },
                {
                  value:
                    (draft?.publishReady ?? profile.publishReady)
                      ? '可发布'
                      : '草稿',
                },
              ]}
              columns="two"
              density="compact"
              surface="plain"
              className="mt-3"
              itemClassName="border-0 bg-white/68"
            />
            <button
              type="button"
              disabled={busy}
              onClick={() =>
                setActiveImageSlot({
                  kind: 'background',
                  title: '背景图',
                  assetKind: 'square_hole_background_image',
                })
              }
              className={`mt-3 block w-full overflow-hidden rounded-[1.1rem] border border-[var(--platform-subpanel-border)] bg-[linear-gradient(135deg,rgba(15,23,42,0.12),rgba(34,197,94,0.16))] text-left ${busy ? 'cursor-not-allowed opacity-70' : ''}`}
              aria-label="查看背景图"
            >
              <PlatformMediaFrame
                src={editState.backgroundImageSrc}
                alt=""
                fallbackLabel="背景图"
                fallbackContent={<ImagePlus className="h-8 w-8" />}
                aspect="landscape"
                surface="none"
                className="rounded-none bg-transparent"
                fallbackClassName="tracking-normal text-slate-700"
              />
            </button>
          </PlatformSubpanel>

          <PlatformSubpanel radius="xl" padding="lg">
            <div className="grid gap-3 sm:grid-cols-2">
              <label className="block sm:col-span-2">
                <PlatformFieldLabel variant="section">
                  游戏名称
                </PlatformFieldLabel>
                <PlatformTextField
                  value={editState.gameName}
                  disabled={busy}
                  onChange={(event) =>
                    setEditState({ ...editState, gameName: event.target.value })
                  }
                  size="lg"
                  className="mt-2"
                />
              </label>

              <label className="block sm:col-span-2">
                <PlatformFieldLabel variant="section">标签</PlatformFieldLabel>
                <PlatformTextField
                  value={editState.tagsText}
                  disabled={busy}
                  onChange={(event) =>
                    setEditState({ ...editState, tagsText: event.target.value })
                  }
                  className="mt-2"
                />
              </label>

              <label className="block sm:col-span-2">
                <PlatformFieldLabel variant="section">简介</PlatformFieldLabel>
                <PlatformTextField
                  variant="textarea"
                  value={editState.summary}
                  disabled={busy}
                  onChange={(event) =>
                    setEditState({ ...editState, summary: event.target.value })
                  }
                  rows={3}
                  size="md"
                  className="mt-2"
                />
              </label>

              <label className="block">
                <PlatformFieldLabel variant="section">
                  题材主题
                </PlatformFieldLabel>
                <PlatformTextField
                  value={editState.themeText}
                  disabled={busy}
                  onChange={(event) =>
                    setEditState({
                      ...editState,
                      themeText: event.target.value,
                    })
                  }
                  className="mt-2"
                />
              </label>

              <label className="block">
                <PlatformFieldLabel variant="section">
                  反差规则
                </PlatformFieldLabel>
                <PlatformTextField
                  value={editState.twistRule}
                  disabled={busy}
                  onChange={(event) =>
                    setEditState({
                      ...editState,
                      twistRule: event.target.value,
                    })
                  }
                  className="mt-2"
                />
              </label>

              <label className="block sm:col-span-2">
                <PlatformFieldLabel variant="section">
                  背景提示
                </PlatformFieldLabel>
                <PlatformTextField
                  value={editState.backgroundPrompt}
                  disabled={busy}
                  onChange={(event) =>
                    setEditState({
                      ...editState,
                      backgroundPrompt: event.target.value,
                    })
                  }
                  className="mt-2"
                />
              </label>

              <label className="block">
                <PlatformFieldLabel variant="section">
                  形状数量
                </PlatformFieldLabel>
                <PlatformTextField
                  value={editState.shapeCountText}
                  inputMode="numeric"
                  disabled={busy}
                  onChange={(event) =>
                    setEditState({
                      ...editState,
                      shapeCountText: event.target.value,
                    })
                  }
                  className="mt-2"
                />
              </label>
            </div>
          </PlatformSubpanel>

          <PlatformSubpanel radius="xl" padding="lg" className="lg:col-span-2">
            <div className="mb-3 flex items-center justify-between gap-3">
              <PlatformFieldLabel variant="section">
                形状选项
              </PlatformFieldLabel>
              <PlatformActionButton
                disabled={busy}
                onClick={() =>
                  setEditState((current) => ({
                    ...current,
                    shapeOptions: [
                      ...current.shapeOptions,
                      createShapeOption(
                        current.shapeOptions.length,
                        current.holeOptions,
                      ),
                    ],
                  }))
                }
                tone="ghost"
                size="xs"
                className="min-h-0 gap-1.5 px-3 py-1.5 text-[11px]"
              >
                <Plus className="h-3.5 w-3.5" />
                新增
              </PlatformActionButton>
            </div>
            <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
              {editState.shapeOptions.map((option) => (
                <PlatformSubpanel
                  as="div"
                  key={option.optionId}
                  surface="flat"
                  radius="sm"
                  padding="sm"
                >
                  <div className="mb-3 flex items-start gap-3">
                    <PlatformSubpanel
                      as="button"
                      disabled={busy}
                      surface="flat"
                      radius="sm"
                      padding="none"
                      interactive
                      onClick={() =>
                        setActiveImageSlot({
                          kind: 'shape',
                          title: `${option.label || '形状'}贴图`,
                          assetKind: 'square_hole_shape_image',
                          shapeOptionId: option.optionId,
                        })
                      }
                      className="relative grid h-20 w-20 shrink-0 place-items-center overflow-hidden bg-white/82 text-slate-600"
                      aria-label={`查看${option.label || '形状'}贴图`}
                    >
                      <PlatformMediaFrame
                        src={option.imageSrc}
                        alt=""
                        fallbackLabel={`${option.label || '形状'}贴图`}
                        fallbackContent={<ImagePlus className="h-6 w-6" />}
                        aspect="square"
                        surface="none"
                        className="h-full w-full rounded-none bg-transparent"
                        fallbackClassName="tracking-normal text-slate-600"
                      />
                    </PlatformSubpanel>
                    <div className="min-w-0 flex-1 space-y-2">
                      <PlatformTextField
                        aria-label={`${option.label || '形状'}名称`}
                        value={option.label}
                        disabled={busy}
                        density="compact"
                        onChange={(event) =>
                          setEditState((current) => ({
                            ...current,
                            shapeOptions: current.shapeOptions.map((entry) =>
                              entry.optionId === option.optionId
                                ? { ...entry, label: event.target.value }
                                : entry,
                            ),
                          }))
                        }
                      />
                      <PlatformSelectField
                        aria-label={`${option.label || '形状'}目标洞口`}
                        value={option.targetHoleId}
                        disabled={busy}
                        density="compact"
                        onChange={(event) =>
                          setEditState((current) => ({
                            ...current,
                            shapeOptions: current.shapeOptions.map((entry) =>
                              entry.optionId === option.optionId
                                ? { ...entry, targetHoleId: event.target.value }
                                : entry,
                            ),
                          }))
                        }
                      >
                        {editState.holeOptions.map((holeOption, holeIndex) => (
                          <option
                            key={holeOption.holeId}
                            value={holeOption.holeId}
                          >
                            {holeOption.label.trim() || `洞口 ${holeIndex + 1}`}
                          </option>
                        ))}
                      </PlatformSelectField>
                    </div>
                    <PlatformIconButton
                      disabled={busy || editState.shapeOptions.length <= 1}
                      onClick={() =>
                        setEditState((current) => ({
                          ...current,
                          shapeOptions: current.shapeOptions.filter(
                            (entry) => entry.optionId !== option.optionId,
                          ),
                        }))
                      }
                      label="删除形状选项"
                      icon={<Trash2 className="h-4 w-4" />}
                      className="p-2 text-slate-500 hover:bg-white/72 disabled:opacity-40"
                    />
                  </div>
                  <PlatformTextField
                    variant="textarea"
                    aria-label={`${option.label || '形状'}图片提示词`}
                    value={option.imagePrompt}
                    disabled={busy}
                    rows={2}
                    size="xs"
                    density="compact"
                    onChange={(event) =>
                      setEditState((current) => ({
                        ...current,
                        shapeOptions: current.shapeOptions.map((entry) =>
                          entry.optionId === option.optionId
                            ? { ...entry, imagePrompt: event.target.value }
                            : entry,
                        ),
                      }))
                    }
                  />
                </PlatformSubpanel>
              ))}
            </div>
          </PlatformSubpanel>

          <PlatformSubpanel radius="xl" padding="lg" className="lg:col-span-2">
            <div className="mb-3 flex items-center justify-between gap-3">
              <PlatformFieldLabel variant="section">
                洞口选项
              </PlatformFieldLabel>
              <PlatformActionButton
                disabled={busy}
                onClick={() =>
                  setEditState((current) => ({
                    ...current,
                    holeOptions: [
                      ...current.holeOptions,
                      createHoleOption(current.holeOptions.length),
                    ],
                  }))
                }
                tone="ghost"
                size="xs"
                className="min-h-0 gap-1.5 px-3 py-1.5 text-[11px]"
              >
                <Plus className="h-3.5 w-3.5" />
                新增
              </PlatformActionButton>
            </div>
            <div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
              {editState.holeOptions.map((option) => (
                <PlatformSubpanel
                  as="div"
                  key={option.holeId}
                  surface="flat"
                  radius="sm"
                  padding="sm"
                >
                  <div className="mb-3 flex items-start gap-3">
                    <PlatformSubpanel
                      as="button"
                      disabled={busy}
                      surface="flat"
                      radius="sm"
                      padding="none"
                      interactive
                      onClick={() =>
                        setActiveImageSlot({
                          kind: 'hole',
                          title: `${option.label || '洞口'}贴图`,
                          assetKind: 'square_hole_hole_image',
                          holeOptionId: option.holeId,
                        })
                      }
                      className="relative grid h-20 w-20 shrink-0 place-items-center overflow-hidden bg-white/82 text-slate-600"
                      aria-label={`查看${option.label || '洞口'}贴图`}
                    >
                      <PlatformMediaFrame
                        src={option.imageSrc}
                        alt=""
                        fallbackLabel={`${option.label || '洞口'}贴图`}
                        fallbackContent={<ImagePlus className="h-6 w-6" />}
                        aspect="square"
                        surface="none"
                        className="h-full w-full rounded-none bg-transparent"
                        fallbackClassName="tracking-normal text-slate-600"
                      />
                    </PlatformSubpanel>
                    <div className="min-w-0 flex-1 space-y-2">
                      <PlatformTextField
                        aria-label={`${option.label || '洞口'}名称`}
                        value={option.label}
                        disabled={busy}
                        density="compact"
                        onChange={(event) =>
                          setEditState((current) => ({
                            ...current,
                            holeOptions: current.holeOptions.map((entry) =>
                              entry.holeId === option.holeId
                                ? { ...entry, label: event.target.value }
                                : entry,
                            ),
                          }))
                        }
                      />
                      <PlatformTextField
                        variant="textarea"
                        aria-label={`${option.label || '洞口'}图片提示词`}
                        value={option.imagePrompt}
                        disabled={busy}
                        rows={2}
                        size="xs"
                        density="compact"
                        onChange={(event) =>
                          setEditState((current) => ({
                            ...current,
                            holeOptions: current.holeOptions.map((entry) =>
                              entry.holeId === option.holeId
                                ? { ...entry, imagePrompt: event.target.value }
                                : entry,
                            ),
                          }))
                        }
                      />
                    </div>
                    <PlatformIconButton
                      disabled={busy || editState.holeOptions.length <= 1}
                      onClick={() =>
                        setEditState((current) => {
                          const nextHoleOptions = current.holeOptions.filter(
                            (entry) => entry.holeId !== option.holeId,
                          );
                          return {
                            ...current,
                            holeOptions: nextHoleOptions,
                            shapeOptions: remapShapeTargetsToHoles(
                              current.shapeOptions.map((shapeOption) => ({
                                ...shapeOption,
                                targetHoleId:
                                  shapeOption.targetHoleId === option.holeId
                                    ? (nextHoleOptions[0]?.holeId ?? '')
                                    : shapeOption.targetHoleId,
                              })),
                              nextHoleOptions,
                            ),
                          };
                        })
                      }
                      label="删除洞口选项"
                      icon={<Trash2 className="h-4 w-4" />}
                      className="p-2 text-slate-500 hover:bg-white/72 disabled:opacity-40"
                    />
                  </div>
                </PlatformSubpanel>
              ))}
            </div>
          </PlatformSubpanel>
        </div>
      </div>

      {displayError ? (
        <PlatformStatusMessage
          tone="error"
          surface="platform"
          size="md"
          className="mt-3 rounded-2xl"
        >
          {displayError}
        </PlatformStatusMessage>
      ) : null}

      <div className="mt-3 flex flex-col gap-2 pb-[max(0.25rem,env(safe-area-inset-bottom))] sm:flex-row sm:justify-end">
        <PlatformActionButton
          onClick={handleStartTestRun}
          disabled={!canSubmit || busy}
          tone="ghost"
          size="md"
          className="min-h-11 gap-2 px-5"
        >
          {isStartingTestRun ? (
            <Loader2 className="h-4 w-4 animate-spin" />
          ) : (
            <Play className="h-4 w-4" />
          )}
          试玩
        </PlatformActionButton>
        <PlatformActionButton
          onClick={handlePublish}
          disabled={!canSubmit || busy}
          size="md"
          className="min-h-11 gap-2 px-5"
        >
          {isPublishing ? (
            <Loader2 className="h-4 w-4 animate-spin" />
          ) : profile.publicationStatus === 'published' ? (
            <CheckCircle2 className="h-4 w-4" />
          ) : (
            <Send className="h-4 w-4" />
          )}
          {profile.publicationStatus === 'published' ? '更新发布' : '发布'}
        </PlatformActionButton>
      </div>

      {activeImageSlot ? (
        <SquareHoleImageSlotDialog
          canRegenerateImages={canSubmit}
          currentImageSrc={activeImageSrc}
          isBusy={busy}
          isRegeneratingImages={isRegeneratingImages}
          slot={activeImageSlot}
          onClose={() => setActiveImageSlot(null)}
          onRegenerateImages={handleRegenerateImages}
          onSelectHistory={(asset) => {
            void handleSelectHistoryImage(activeImageSlot, asset);
          }}
          onUpload={(slot, event) => {
            void handleImageSlotUpload(slot, event);
          }}
        />
      ) : null}
    </div>
  );
}

export default SquareHoleResultView;
