import { Pencil, Plus, RefreshCcw, Save, Trash2, X } from 'lucide-react';
import { FormEvent, useEffect, useState } from 'react';

import {
  getAdminCreationEntryConfig,
  upsertAdminCreationEntryBanners,
  upsertAdminCreationEntryConfig,
} from '../api/adminApiClient';
import type {
  AdminCreationEntryEventBannerPayload,
  AdminCreationEntryTypeConfigPayload,
  UnifiedCreationFieldPayload,
  UnifiedCreationSpecPayload,
} from '../api/adminApiTypes';
import { useAdminWriteConfirm } from '../components/useAdminWriteConfirm';
import { handlePageError } from './pageUtils';

/** 创作入口后台页面参数；公告模式只展示底部加号入口公告表单。 */
interface AdminCreationEntrySwitchPageProps {
  token: string;
  onUnauthorized: (message?: string) => void;
  mode?: 'switches' | 'announcements';
}

/** 后台公告表单的一行编辑态，保存时会统一序列化为后端传输字段。 */
type AnnouncementFormItem = {
  id: string;
  title: string;
  htmlCode: string;
};

/** 公告表单保存前的校验与序列化结果。 */
type AnnouncementFormBuildResult =
  | { ok: true; json: string }
  | { ok: false; message: string };

/** 统一创作契约字段的弹窗表单态。 */
type UnifiedCreationSpecFieldFormItem = {
  id: string;
  fieldId: string;
  kind: UnifiedCreationFieldPayload['kind'];
  label: string;
  required: boolean;
};

/** 统一创作契约弹窗表单态；保存入库前会重新组装为后端契约。 */
type UnifiedCreationSpecFormState = {
  playId: string;
  title: string;
  mudPointCost: string;
  /** 内部阶段由已有契约或玩法默认映射带出，不在后台表单中开放编辑。 */
  workspaceStage: string;
  generationStage: string;
  resultStage: string;
  fields: UnifiedCreationSpecFieldFormItem[];
};

type UnifiedCreationSpecStageState = Pick<
  UnifiedCreationSpecFormState,
  'workspaceStage' | 'generationStage' | 'resultStage'
>;

const DEFAULT_UNIFIED_CREATION_STAGE_MAP: Record<
  string,
  UnifiedCreationSpecStageState
> = {
  rpg: {
    workspaceStage: 'agent-workspace',
    generationStage: 'custom-world-generating',
    resultStage: 'custom-world-result',
  },
  'big-fish': {
    workspaceStage: 'big-fish-agent-workspace',
    generationStage: 'big-fish-generating',
    resultStage: 'big-fish-result',
  },
  puzzle: {
    workspaceStage: 'puzzle-agent-workspace',
    generationStage: 'puzzle-generating',
    resultStage: 'puzzle-result',
  },
  'puzzle-clear': {
    workspaceStage: 'puzzle-clear-workspace',
    generationStage: 'puzzle-clear-generating',
    resultStage: 'puzzle-clear-result',
  },
  match3d: {
    workspaceStage: 'match3d-agent-workspace',
    generationStage: 'match3d-generating',
    resultStage: 'match3d-result',
  },
  'jump-hop': {
    workspaceStage: 'jump-hop-workspace',
    generationStage: 'jump-hop-generating',
    resultStage: 'jump-hop-result',
  },
  'wooden-fish': {
    workspaceStage: 'wooden-fish-workspace',
    generationStage: 'wooden-fish-generating',
    resultStage: 'wooden-fish-result',
  },
  'square-hole': {
    workspaceStage: 'square-hole-agent-workspace',
    generationStage: 'square-hole-generating',
    resultStage: 'square-hole-result',
  },
  'bark-battle': {
    workspaceStage: 'bark-battle-workspace',
    generationStage: 'bark-battle-generating',
    resultStage: 'bark-battle-result',
  },
  'visual-novel': {
    workspaceStage: 'visual-novel-agent-workspace',
    generationStage: 'visual-novel-generating',
    resultStage: 'visual-novel-result',
  },
  'baby-object-match': {
    workspaceStage: 'baby-object-match-workspace',
    generationStage: 'baby-object-match-generating',
    resultStage: 'baby-object-match-result',
  },
  'creative-agent': {
    workspaceStage: 'creative-agent-workspace',
    generationStage: 'puzzle-generating',
    resultStage: 'puzzle-result',
  },
};

let announcementFormItemSequence = 0;
let unifiedCreationSpecFieldSequence = 0;

export function AdminCreationEntrySwitchPage({
  token,
  onUnauthorized,
  mode = 'switches',
}: AdminCreationEntrySwitchPageProps) {
  const [entries, setEntries] = useState<
    AdminCreationEntryTypeConfigPayload[]
  >([]);
  const [selectedId, setSelectedId] = useState('puzzle');
  const [title, setTitle] = useState('');
  const [subtitle, setSubtitle] = useState('');
  const [badge, setBadge] = useState('');
  const [imageSrc, setImageSrc] = useState('');
  const [visible, setVisible] = useState(true);
  const [open, setOpen] = useState(true);
  const [sortOrder, setSortOrder] = useState('30');
  const [categoryId, setCategoryId] = useState('recommended');
  const [categoryLabel, setCategoryLabel] = useState('热门推荐');
  const [categorySortOrder, setCategorySortOrder] = useState('20');
  const [unifiedCreationSpec, setUnifiedCreationSpec] =
    useState<UnifiedCreationSpecPayload | null>(null);
  const [unifiedCreationSpecForm, setUnifiedCreationSpecForm] =
    useState<UnifiedCreationSpecFormState | null>(null);
  const [unifiedCreationSpecFormError, setUnifiedCreationSpecFormError] =
    useState('');
  const [announcementItems, setAnnouncementItems] = useState<
    AnnouncementFormItem[]
  >([]);
  const [isLoading, setIsLoading] = useState(false);
  const [isSaving, setIsSaving] = useState(false);
  const [isSavingBanners, setIsSavingBanners] = useState(false);
  const [listErrorMessage, setListErrorMessage] = useState('');
  const [errorMessage, setErrorMessage] = useState('');
  const [bannerErrorMessage, setBannerErrorMessage] = useState('');
  const { confirmWrite, confirmDialog } = useAdminWriteConfirm();
  const isAnnouncementMode = mode === 'announcements';

  useEffect(() => {
    void refreshEntries();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [token]);

  async function refreshEntries() {
    setIsLoading(true);
    setListErrorMessage('');
    try {
      const response = await getAdminCreationEntryConfig(token);
      const nextEntries = sortEntries(response.entries);
      setEntries(nextEntries);
      setAnnouncementItems(formatEventBannersFormItems(response.eventBanners));
      fillForm(
        nextEntries.find((entry) => entry.id === selectedId) ??
          nextEntries[0] ??
          null,
      );
    } catch (error: unknown) {
      handlePageError(error, onUnauthorized, setListErrorMessage);
    } finally {
      setIsLoading(false);
    }
  }

  async function handleSave(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (isSaving) {
      return;
    }

    const targetId = selectedId.trim();
    setErrorMessage('');
    const unifiedCreationSpecResult = validateUnifiedCreationSpecForEntry(
      targetId,
      unifiedCreationSpec,
    );
    if (!unifiedCreationSpecResult.ok) {
      setErrorMessage(unifiedCreationSpecResult.message);
      return;
    }
    const confirmed = await confirmWrite({
      action: '保存创作入口开关',
      target: targetId,
    });
    if (!confirmed) {
      return;
    }

    setIsSaving(true);
    try {
      const response = await upsertAdminCreationEntryConfig(token, {
        id: targetId,
        title: title.trim(),
        subtitle: subtitle.trim(),
        badge: badge.trim(),
        imageSrc: imageSrc.trim(),
        visible,
        open,
        sortOrder: parseInteger(sortOrder),
        categoryId: categoryId.trim(),
        categoryLabel: categoryLabel.trim(),
        categorySortOrder: parseInteger(categorySortOrder),
        unifiedCreationSpec: unifiedCreationSpecResult.spec,
      });
      const nextEntries = sortEntries(response.entries);
      setEntries(nextEntries);
      setAnnouncementItems(formatEventBannersFormItems(response.eventBanners));
      fillForm(nextEntries.find((entry) => entry.id === targetId) ?? null);
    } catch (error: unknown) {
      handlePageError(error, onUnauthorized, setErrorMessage);
    } finally {
      setIsSaving(false);
    }
  }

  /** 保存底部加号创作入口页的多公告表单配置。 */
  async function handleSaveBanners() {
    if (isSavingBanners) {
      return;
    }

    setBannerErrorMessage('');
    const bannerJsonResult = buildEventBannersJsonFromForm(announcementItems);
    if (!bannerJsonResult.ok) {
      setBannerErrorMessage(bannerJsonResult.message);
      return;
    }
    const confirmed = await confirmWrite({
      action: '保存创作入口公告',
      target: 'creation-entry-announcements',
    });
    if (!confirmed) {
      return;
    }

    setIsSavingBanners(true);
    try {
      const response = await upsertAdminCreationEntryBanners(token, {
        eventBannersJson: bannerJsonResult.json,
      });
      setEntries(sortEntries(response.entries));
      setAnnouncementItems(formatEventBannersFormItems(response.eventBanners));
    } catch (error: unknown) {
      handlePageError(error, onUnauthorized, setBannerErrorMessage);
    } finally {
      setIsSavingBanners(false);
    }
  }

  function fillForm(entry: AdminCreationEntryTypeConfigPayload | null) {
    if (!entry) {
      return;
    }
    setSelectedId(entry.id);
    setTitle(entry.title);
    setSubtitle(entry.subtitle);
    setBadge(entry.badge);
    setImageSrc(entry.imageSrc);
    setVisible(entry.visible);
    setOpen(entry.open);
    setSortOrder(String(entry.sortOrder));
    setCategoryId(entry.categoryId);
    setCategoryLabel(entry.categoryLabel);
    setCategorySortOrder(String(entry.categorySortOrder));
    setUnifiedCreationSpec(entry.unifiedCreationSpec ?? null);
    setUnifiedCreationSpecForm(null);
    setUnifiedCreationSpecFormError('');
  }

  /** 打开统一创作契约弹窗；缺省时用当前入口 ID 和标题预填。 */
  function openUnifiedCreationSpecForm() {
    setUnifiedCreationSpecForm(
      buildUnifiedCreationSpecForm(
        unifiedCreationSpec,
        selectedId.trim(),
        title.trim(),
      ),
    );
    setUnifiedCreationSpecFormError('');
  }

  function closeUnifiedCreationSpecForm() {
    setUnifiedCreationSpecForm(null);
    setUnifiedCreationSpecFormError('');
  }

  function applyUnifiedCreationSpecForm(event: FormEvent<HTMLFormElement>) {
    event.preventDefault();
    if (!unifiedCreationSpecForm) {
      return;
    }

    const result = buildUnifiedCreationSpecFromForm(unifiedCreationSpecForm);
    if (!result.ok) {
      setUnifiedCreationSpecFormError(result.message);
      return;
    }
    if (result.spec.playId !== selectedId.trim()) {
      setUnifiedCreationSpecFormError('统一创作契约 playId 必须与入口 ID 一致');
      return;
    }
    setUnifiedCreationSpec(result.spec);
    closeUnifiedCreationSpecForm();
  }

  function updateUnifiedCreationSpecForm(
    patch: Partial<Omit<UnifiedCreationSpecFormState, 'fields'>>,
  ) {
    setUnifiedCreationSpecForm((currentForm) =>
      currentForm ? { ...currentForm, ...patch } : currentForm,
    );
  }

  function updateUnifiedCreationSpecField(
    index: number,
    patch: Partial<Omit<UnifiedCreationSpecFieldFormItem, 'id'>>,
  ) {
    setUnifiedCreationSpecForm((currentForm) =>
      currentForm
        ? {
            ...currentForm,
            fields: currentForm.fields.map((field, fieldIndex) =>
              fieldIndex === index ? { ...field, ...patch } : field,
            ),
          }
        : currentForm,
    );
  }

  function addUnifiedCreationSpecField() {
    setUnifiedCreationSpecForm((currentForm) =>
      currentForm
        ? {
            ...currentForm,
            fields: [...currentForm.fields, createUnifiedCreationSpecFieldFormItem()],
          }
        : currentForm,
    );
  }

  function removeUnifiedCreationSpecField(index: number) {
    setUnifiedCreationSpecForm((currentForm) => {
      if (!currentForm) {
        return currentForm;
      }
      const fields = currentForm.fields.filter(
        (_, fieldIndex) => fieldIndex !== index,
      );
      return {
        ...currentForm,
        fields: fields.length > 0 ? fields : [createUnifiedCreationSpecFieldFormItem()],
      };
    });
  }

  /** 更新单条公告表单字段，避免后台页面直接暴露 JSON 编辑。 */
  function updateAnnouncementItem(
    index: number,
    patch: Partial<Pick<AnnouncementFormItem, 'title' | 'htmlCode'>>,
  ) {
    setAnnouncementItems((currentItems) =>
      currentItems.map((item, itemIndex) =>
        itemIndex === index ? { ...item, ...patch } : item,
      ),
    );
  }

  /** 新增一条空公告表单行。 */
  function addAnnouncementItem() {
    setAnnouncementItems((currentItems) => [
      ...currentItems,
      createAnnouncementFormItem('', ''),
    ]);
  }

  /** 删除指定公告表单行，至少保留一条空行供继续编辑。 */
  function removeAnnouncementItem(index: number) {
    setAnnouncementItems((currentItems) => {
      const nextItems = currentItems.filter(
        (_, itemIndex) => itemIndex !== index,
      );
      return nextItems.length > 0
        ? nextItems
        : [createAnnouncementFormItem('', '')];
    });
  }

  return (
    <section className="admin-page">
      <div className="admin-page-heading">
        <div>
          <h2>{isAnnouncementMode ? '创作入口公告' : '创作入口开关'}</h2>
          <p>
            {isAnnouncementMode
              ? '配置底部加号创作入口页的公告轮播'
              : '控制创作中心入口展示与运行态路由可用性'}
          </p>
        </div>
        <button
          className="admin-secondary-button"
          disabled={isLoading}
          type="button"
          onClick={refreshEntries}
        >
          <RefreshCcw size={17} aria-hidden="true" />
          <span>{isLoading ? '刷新中' : '刷新'}</span>
        </button>
      </div>

      {listErrorMessage ? (
        <div className="admin-alert" role="status">
          {listErrorMessage}
        </div>
      ) : null}

      {isAnnouncementMode ? (
        <section className="admin-panel admin-form">
          <div className="admin-subsection-heading">
            <h3>创作入口公告</h3>
            <span>{announcementItems.length > 0 ? '已配置' : '未配置'}</span>
          </div>
          <div className="admin-form-actions">
            <button
              className="admin-secondary-button"
              type="button"
              onClick={addAnnouncementItem}
            >
              <Plus size={17} aria-hidden="true" />
              <span>新增公告</span>
            </button>
          </div>
          {announcementItems.map((item, index) => (
            <section className="admin-subsection" key={item.id}>
              <div className="admin-subsection-heading">
                <span>{`公告 ${index + 1}`}</span>
                <button
                  className="admin-link-button"
                  type="button"
                  aria-label={`删除公告 ${index + 1}`}
                  onClick={() => removeAnnouncementItem(index)}
                >
                  <Trash2 size={15} aria-hidden="true" />
                  删除
                </button>
              </div>
              <label className="admin-field">
                <span>{`公告 ${index + 1} 标题`}</span>
                <input
                  value={item.title}
                  onChange={(event) =>
                    updateAnnouncementItem(index, { title: event.target.value })
                  }
                />
              </label>
              <label className="admin-field">
                <span>{`公告 ${index + 1} HTML`}</span>
                <textarea
                  rows={6}
                  value={item.htmlCode}
                  onChange={(event) =>
                    updateAnnouncementItem(index, {
                      htmlCode: event.target.value,
                    })
                  }
                />
              </label>
            </section>
          ))}
          {bannerErrorMessage ? (
            <div className="admin-alert" role="status">
              {bannerErrorMessage}
            </div>
          ) : null}
          <div className="admin-form-actions">
            <button
              className="admin-secondary-button"
              disabled={isSavingBanners}
              type="button"
              onClick={handleSaveBanners}
            >
              <Save size={17} aria-hidden="true" />
              <span>{isSavingBanners ? '保存中' : '保存公告'}</span>
            </button>
          </div>
        </section>
      ) : null}

      {!isAnnouncementMode ? (
        <div className="admin-two-column admin-two-column-wide">
          <form className="admin-panel admin-form" onSubmit={handleSave}>
            <div className="admin-form-row">
              <label className="admin-field admin-field-fill">
                <span>入口 ID</span>
                <input
                  value={selectedId}
                  onChange={(event) => setSelectedId(event.target.value)}
                />
              </label>
              <label className="admin-switch-field">
                <input
                  checked={visible}
                  type="checkbox"
                  onChange={(event) => setVisible(event.target.checked)}
                />
                <span>展示</span>
              </label>
              <label className="admin-switch-field">
                <input
                  checked={open}
                  type="checkbox"
                  onChange={(event) => setOpen(event.target.checked)}
                />
                <span>开放</span>
              </label>
            </div>

            <div className="admin-form-row">
              <label className="admin-field">
                <span>标题</span>
                <input
                  value={title}
                  onChange={(event) => setTitle(event.target.value)}
                />
              </label>
              <label className="admin-field">
                <span>角标</span>
                <input
                  value={badge}
                  onChange={(event) => setBadge(event.target.value)}
                />
              </label>
            </div>

            <label className="admin-field">
              <span>副标题</span>
              <input
                value={subtitle}
                onChange={(event) => setSubtitle(event.target.value)}
              />
            </label>

            <label className="admin-field">
              <span>图片路径</span>
              <input
                value={imageSrc}
                onChange={(event) => setImageSrc(event.target.value)}
              />
            </label>

            <label className="admin-field">
              <span>排序</span>
              <input
                inputMode="numeric"
                value={sortOrder}
                onChange={(event) => setSortOrder(event.target.value)}
              />
            </label>

            <div className="admin-form-row">
              <label className="admin-field">
                <span>分类 ID</span>
                <input
                  value={categoryId}
                  onChange={(event) => setCategoryId(event.target.value)}
                />
              </label>
              <label className="admin-field">
                <span>分类名称</span>
                <input
                  value={categoryLabel}
                  onChange={(event) => setCategoryLabel(event.target.value)}
                />
              </label>
            </div>

            <label className="admin-field">
              <span>分类排序</span>
              <input
                inputMode="numeric"
                value={categorySortOrder}
                onChange={(event) => setCategorySortOrder(event.target.value)}
              />
            </label>

            <section className="admin-subsection">
              <div className="admin-subsection-heading">
                <span>统一创作契约</span>
                <span>
                  {unifiedCreationSpec ? '已配置' : '未配置'}
                </span>
              </div>
              <div className="admin-form-actions">
                <button
                  className="admin-secondary-button"
                  type="button"
                  onClick={openUnifiedCreationSpecForm}
                >
                  <Pencil size={17} aria-hidden="true" />
                  <span>{unifiedCreationSpec ? '修改契约' : '新增契约'}</span>
                </button>
                {unifiedCreationSpec ? (
                  <button
                    className="admin-secondary-button"
                    type="button"
                    onClick={() => setUnifiedCreationSpec(null)}
                  >
                    <Trash2 size={17} aria-hidden="true" />
                    <span>清空契约</span>
                  </button>
                ) : null}
              </div>
              {unifiedCreationSpec ? (
                <UnifiedCreationSpecCard spec={unifiedCreationSpec} />
              ) : (
                <div className="admin-muted-text">未配置统一创作页契约</div>
              )}
            </section>

            {errorMessage ? (
              <div className="admin-alert" role="status">
                {errorMessage}
              </div>
            ) : null}

            <div className="admin-form-actions">
              <button
                className="admin-primary-button"
                disabled={isSaving}
                type="submit"
              >
                <Save size={17} aria-hidden="true" />
                <span>{isSaving ? '保存中' : '保存入库'}</span>
              </button>
            </div>
          </form>

          <section className="admin-panel">
            <div className="admin-table-wrap">
              <table className="admin-table admin-table-compact">
                <thead>
                  <tr>
                    <th>入口</th>
                    <th>展示</th>
                    <th>开放</th>
                    <th>统一契约</th>
                    <th>分类</th>
                    <th>排序</th>
                  </tr>
                </thead>
                <tbody>
                  {entries.map((entry) => (
                    <tr key={entry.id}>
                      <td>
                        <button
                          className="admin-link-button"
                          type="button"
                          onClick={() => fillForm(entry)}
                        >
                          {entry.title || entry.id}
                        </button>
                      </td>
                      <td>{entry.visible ? '是' : '否'}</td>
                      <td>{entry.open ? '是' : '否'}</td>
                      <td>{entry.unifiedCreationSpec ? '是' : '否'}</td>
                      <td>{entry.categoryLabel || entry.categoryId}</td>
                      <td>{entry.sortOrder}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </section>
        </div>
      ) : null}

      {confirmDialog}
      {unifiedCreationSpecForm ? (
        <div
          className="admin-confirm-backdrop"
          role="presentation"
          onMouseDown={(event) => {
            if (event.target === event.currentTarget) {
              closeUnifiedCreationSpecForm();
            }
          }}
        >
          <form
            aria-labelledby="admin-unified-creation-spec-editor-title"
            aria-modal="true"
            className="admin-detail-panel admin-form admin-contract-dialog"
            role="dialog"
            onSubmit={applyUnifiedCreationSpecForm}
          >
            <div className="admin-panel-heading">
              <h3 id="admin-unified-creation-spec-editor-title">
                统一创作契约
              </h3>
              <button
                className="admin-ghost-button"
                title="关闭"
                type="button"
                onClick={closeUnifiedCreationSpecForm}
              >
                <X size={17} aria-hidden="true" />
              </button>
            </div>

            <label className="admin-field">
              <span>表头</span>
              <input
                value={unifiedCreationSpecForm.title}
                onChange={(event) =>
                  updateUnifiedCreationSpecForm({
                    title: event.target.value,
                  })
                }
              />
            </label>

            <label className="admin-field">
              <span>泥点消耗</span>
              <input
                inputMode="numeric"
                min={1}
                step={1}
                type="number"
                value={unifiedCreationSpecForm.mudPointCost}
                onChange={(event) =>
                  updateUnifiedCreationSpecForm({
                    mudPointCost: event.target.value,
                  })
                }
              />
            </label>

            <section className="admin-subsection">
              <div className="admin-subsection-heading">
                <span>字段</span>
                <button
                  className="admin-link-button"
                  type="button"
                  onClick={addUnifiedCreationSpecField}
                >
                  <Plus size={15} aria-hidden="true" />
                  新增字段
                </button>
              </div>
              <div className="admin-contract-field-editor-list">
                {unifiedCreationSpecForm.fields.map((field, index) => (
                  <section className="admin-contract-field-editor" key={field.id}>
                    <div className="admin-subsection-heading">
                      <span>{`字段 ${index + 1}`}</span>
                      <button
                        className="admin-link-button"
                        type="button"
                        aria-label={`删除字段 ${index + 1}`}
                        onClick={() => removeUnifiedCreationSpecField(index)}
                      >
                        <Trash2 size={15} aria-hidden="true" />
                        删除
                      </button>
                    </div>
                    <div className="admin-contract-field-editor-grid">
                      <label className="admin-field">
                        <span>{`字段 ${index + 1} ID`}</span>
                        <input
                          value={field.fieldId}
                          onChange={(event) =>
                            updateUnifiedCreationSpecField(index, {
                              fieldId: event.target.value,
                            })
                          }
                        />
                      </label>
                      <label className="admin-field">
                        <span>{`字段 ${index + 1} 类型`}</span>
                        <select
                          value={field.kind}
                          onChange={(event) =>
                            updateUnifiedCreationSpecField(index, {
                              kind: event.target
                                .value as UnifiedCreationFieldPayload['kind'],
                            })
                          }
                        >
                          <option value="text">text</option>
                          <option value="select">select</option>
                          <option value="image">image</option>
                          <option value="audio">audio</option>
                        </select>
                      </label>
                      <label className="admin-field">
                        <span>{`字段 ${index + 1} 标签`}</span>
                        <input
                          value={field.label}
                          onChange={(event) =>
                            updateUnifiedCreationSpecField(index, {
                              label: event.target.value,
                            })
                          }
                        />
                      </label>
                      <label className="admin-switch-field admin-contract-required-toggle">
                        <input
                          checked={field.required}
                          type="checkbox"
                          onChange={(event) =>
                            updateUnifiedCreationSpecField(index, {
                              required: event.target.checked,
                            })
                          }
                        />
                        <span>必填</span>
                      </label>
                    </div>
                  </section>
                ))}
              </div>
            </section>

            {unifiedCreationSpecFormError ? (
              <div className="admin-alert" role="status">
                {unifiedCreationSpecFormError}
              </div>
            ) : null}

            <div className="admin-confirm-actions">
              <button
                className="admin-secondary-button"
                type="button"
                onClick={closeUnifiedCreationSpecForm}
              >
                取消
              </button>
              <button className="admin-primary-button" type="submit">
                应用修改
              </button>
            </div>
          </form>
        </div>
      ) : null}
    </section>
  );
}

function sortEntries(entries: AdminCreationEntryTypeConfigPayload[]) {
  return [...entries].sort((left, right) => {
    if (left.sortOrder !== right.sortOrder) {
      return left.sortOrder - right.sortOrder;
    }
    return left.id.localeCompare(right.id);
  });
}

function parseInteger(value: string) {
  const parsed = Number.parseInt(value, 10);
  if (!Number.isFinite(parsed)) {
    return 0;
  }
  return parsed;
}

/** 为公告表单行生成稳定 key，避免编辑时 React 重建输入框。 */
function nextAnnouncementFormItemId() {
  announcementFormItemSequence += 1;
  return `announcement-${announcementFormItemSequence}`;
}

/** 创建公告表单行，后台返回为空时也提供一条可编辑空行。 */
function createAnnouncementFormItem(
  title: string,
  htmlCode: string,
): AnnouncementFormItem {
  return {
    id: nextAnnouncementFormItemId(),
    title,
    htmlCode,
  };
}

/** 把后台公告快照转换成表单行；旧结构化 banner 会降级成 HTML 公告片段。 */
function formatEventBannersFormItems(
  banners: AdminCreationEntryEventBannerPayload[] | null | undefined,
): AnnouncementFormItem[] {
  const formItems = (banners ?? []).map((banner) =>
    createAnnouncementFormItem(
      banner.title,
      banner.renderMode === 'html' && banner.htmlCode
        ? banner.htmlCode
        : buildStructuredAnnouncementHtml(banner),
    ),
  );
  return formItems.length > 0
    ? formItems
    : [createAnnouncementFormItem('', '')];
}

/** 保存前把公告表单序列化为后端传输字段，并先做必填校验。 */
function buildEventBannersJsonFromForm(
  items: AnnouncementFormItem[],
): AnnouncementFormBuildResult {
  const banners = items.map((item) => ({
    title: item.title.trim(),
    htmlCode: item.htmlCode.trim(),
  }));
  if (banners.length === 0) {
    return {ok: false as const, message: '至少需要一条公告'};
  }
  const emptyIndex = banners.findIndex(
    (banner) => !banner.title || !banner.htmlCode,
  );
  if (emptyIndex >= 0) {
    return {
      ok: false as const,
      message: `公告 ${emptyIndex + 1} 标题和 HTML 都不能为空`,
    };
  }

  return {ok: true as const, json: JSON.stringify(banners, null, 2)};
}

/** 将旧结构化公告字段转成可编辑 HTML，避免后台表单丢失历史公告内容。 */
function buildStructuredAnnouncementHtml(
  banner: AdminCreationEntryEventBannerPayload,
): string {
  return `<section><h1>${escapeAnnouncementHtmlText(
    banner.title,
  )}</h1><p>${escapeAnnouncementHtmlText(banner.description)}</p></section>`;
}

/** 转义旧结构化文案，确保迁移到 HTML 表单时不会意外变成标签。 */
function escapeAnnouncementHtmlText(value: string): string {
  return value
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;');
}

function nextUnifiedCreationSpecFieldFormItemId() {
  unifiedCreationSpecFieldSequence += 1;
  return `unified-field-${unifiedCreationSpecFieldSequence}`;
}

function createUnifiedCreationSpecFieldFormItem(
  field?: UnifiedCreationFieldPayload,
): UnifiedCreationSpecFieldFormItem {
  return {
    id: nextUnifiedCreationSpecFieldFormItemId(),
    fieldId: field?.id ?? '',
    kind: field?.kind ?? 'text',
    label: field?.label ?? '',
    required: field?.required ?? true,
  };
}

function buildUnifiedCreationSpecForm(
  spec: UnifiedCreationSpecPayload | null,
  entryId: string,
  entryTitle: string,
): UnifiedCreationSpecFormState {
  const playId = spec?.playId ?? entryId;
  const stages = resolveUnifiedCreationSpecStages(spec, playId);
  return {
    playId,
    title: spec?.title ?? entryTitle,
    mudPointCost: String(normalizeMudPointCost(spec?.mudPointCost)),
    ...stages,
    fields:
      spec?.fields.map((field) => createUnifiedCreationSpecFieldFormItem(field)) ??
      [createUnifiedCreationSpecFieldFormItem()],
  };
}

function resolveUnifiedCreationSpecStages(
  spec: UnifiedCreationSpecPayload | null,
  playId: string,
): UnifiedCreationSpecStageState {
  if (spec?.workspaceStage && spec.generationStage && spec.resultStage) {
    return {
      workspaceStage: spec.workspaceStage,
      generationStage: spec.generationStage,
      resultStage: spec.resultStage,
    };
  }

  return (
    DEFAULT_UNIFIED_CREATION_STAGE_MAP[playId] ?? {
      workspaceStage: '',
      generationStage: '',
      resultStage: '',
    }
  );
}

function buildUnifiedCreationSpecFromForm(form: UnifiedCreationSpecFormState) {
  return validateUnifiedCreationSpec({
    playId: form.playId,
    title: form.title,
    mudPointCost: form.mudPointCost,
    workspaceStage: form.workspaceStage,
    generationStage: form.generationStage,
    resultStage: form.resultStage,
    fields: form.fields.map((field) => ({
      id: field.fieldId,
      kind: field.kind,
      label: field.label,
      required: field.required,
    })),
  });
}

function validateUnifiedCreationSpecForEntry(
  entryId: string,
  spec: UnifiedCreationSpecPayload | null,
) {
  if (!spec) {
    return {ok: true as const, spec: null};
  }
  if (spec.playId !== entryId) {
    return {ok: false as const, message: '统一创作契约 playId 必须与入口 ID 一致'};
  }
  return validateUnifiedCreationSpec(spec);
}

function normalizeMudPointCost(value: number | null | undefined) {
  return typeof value === 'number' && Number.isFinite(value) && value > 0
    ? Math.trunc(value)
    : 10;
}

function formatMudPointCostText(value: number | null | undefined) {
  return `${normalizeMudPointCost(value)}泥点数`;
}

function validateUnifiedCreationSpec(value: unknown) {
  if (!isRecord(value)) {
    return {ok: false as const, message: '统一创作契约必须是对象'};
  }

  const playId = readRequiredString(value, 'playId');
  if (!playId) {
    return {ok: false as const, message: '统一创作契约 playId 不能为空'};
  }

  const title = readRequiredString(value, 'title');
  const mudPointCost = readPositiveInteger(value, 'mudPointCost');
  const workspaceStage = readRequiredString(value, 'workspaceStage');
  const generationStage = readRequiredString(value, 'generationStage');
  const resultStage = readRequiredString(value, 'resultStage');
  if (!title) {
    return {ok: false as const, message: '统一创作契约标题不能为空'};
  }
  if (!workspaceStage || !generationStage || !resultStage) {
    return {ok: false as const, message: '该玩法缺少默认阶段配置，请先由开发接入'};
  }
  if (mudPointCost === null) {
    return {ok: false as const, message: '统一创作契约泥点消耗数量必须是大于 0 的整数'};
  }
  if (new Set([workspaceStage, generationStage, resultStage]).size !== 3) {
    return {ok: false as const, message: '统一创作契约阶段不能重复'};
  }

  if (!Array.isArray(value.fields) || value.fields.length === 0) {
    return {ok: false as const, message: '统一创作契约 fields 不能为空'};
  }

  const fieldIds = new Set<string>();
  const fields: UnifiedCreationFieldPayload[] = [];
  for (const item of value.fields) {
    if (!isRecord(item)) {
      return {ok: false as const, message: '统一创作契约字段必须是对象'};
    }
    const id = readRequiredString(item, 'id');
    const label = readRequiredString(item, 'label');
    if (!id || !label) {
      return {ok: false as const, message: '统一创作契约字段 id 和 label 不能为空'};
    }
    if (fieldIds.has(id)) {
      return {ok: false as const, message: `统一创作契约字段 id 重复：${id}`};
    }
    fieldIds.add(id);
    if (!isUnifiedCreationFieldKind(item.kind)) {
      return {ok: false as const, message: `统一创作契约字段 kind 非法：${id}`};
    }
    if (typeof item.required !== 'boolean') {
      return {ok: false as const, message: `统一创作契约字段 required 非法：${id}`};
    }
    fields.push({
      id,
      kind: item.kind,
      label,
      required: item.required,
    });
  }

  return {
    ok: true as const,
    spec: {
      playId,
      title,
      mudPointCost,
      workspaceStage,
      generationStage,
      resultStage,
      fields,
    },
  };
}

function UnifiedCreationSpecCard({spec}: {spec: UnifiedCreationSpecPayload}) {
  return (
    <div className="admin-contract-card">
      <dl className="admin-info-list">
        <div>
          <dt>玩法</dt>
          <dd>{spec.playId}</dd>
        </div>
        <div>
          <dt>表头</dt>
          <dd>{spec.title}</dd>
        </div>
        <div>
          <dt>泥点消耗</dt>
          <dd>{formatMudPointCostText(spec.mudPointCost)}</dd>
        </div>
      </dl>
      <div className="admin-contract-field-list">
        {spec.fields.map((field) => (
          <div className="admin-contract-field-card" key={field.id}>
            <strong>{field.id}</strong>
            <span>{field.label}</span>
            <span>
              {field.kind} / {field.required ? '必填' : '选填'}
            </span>
          </div>
        ))}
      </div>
    </div>
  );
}

function readRequiredString(value: Record<string, unknown>, key: string) {
  const raw = value[key];
  return typeof raw === 'string' ? raw.trim() : '';
}

function readPositiveInteger(value: Record<string, unknown>, key: string) {
  const raw = value[key];
  const numberValue =
    typeof raw === 'number'
      ? raw
      : typeof raw === 'string'
        ? Number(raw.trim())
        : NaN;
  if (!Number.isInteger(numberValue) || numberValue <= 0) {
    return null;
  }
  return numberValue;
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null && !Array.isArray(value);
}

function isUnifiedCreationFieldKind(
  value: unknown,
): value is UnifiedCreationFieldPayload['kind'] {
  return (
    value === 'text' ||
    value === 'select' ||
    value === 'image' ||
    value === 'audio'
  );
}
