import React3, { useState, useEffect, useCallback, useMemo } from 'react';

// src/festivalCard/core/defaults.ts
var DEFAULT_FESTIVAL_CARD_CONFIG = {
  id: "default-festival-card",
  name: "Holiday Card",
  theme: "winter",
  coverTitle: "Happy Holidays",
  coverSubtitle: "Warm wishes for you",
  background: {
    colorA: "#0c1a34",
    colorB: "#1f4f8a"
  },
  backgroundMusic: {
    src: "",
    loop: true,
    autoPlay: false,
    volume: 0.5
  },
  pages: [
    {
      id: "page-1",
      title: "\u5C01\u9762",
      background: { color: "#11284d" },
      elements: [
        {
          id: "p1-text-1",
          type: "text",
          x: 50,
          y: 20,
          content: "\u65B0\u5E74\u5FEB\u4E50",
          fontSize: 34,
          fontWeight: 700,
          align: "center",
          color: "#f8fafc"
        },
        {
          id: "p1-text-2",
          type: "text",
          x: 50,
          y: 36,
          content: "\u613F\u8FD9\u4E00\u5E74\u5E73\u5B89\u559C\u4E50",
          fontSize: 18,
          fontWeight: 500,
          align: "center",
          color: "#dbeafe"
        },
        {
          id: "p1-image-1",
          type: "image",
          x: 50,
          y: 68,
          width: 72,
          height: 42,
          src: "https://images.unsplash.com/photo-1512389142860-9c449e58a543?auto=format&fit=crop&w=1200&q=80",
          fit: "cover",
          borderRadius: 16,
          alt: "holiday",
          isBackground: false
        }
      ]
    },
    {
      id: "page-2",
      title: "\u795D\u798F",
      background: { color: "#1a3766" },
      elements: [
        {
          id: "p2-text-1",
          type: "text",
          x: 50,
          y: 28,
          content: "\u613F\u4F60\u65B0\u5C81\uFF1A",
          fontSize: 28,
          fontWeight: 700,
          align: "center",
          color: "#fef3c7"
        },
        {
          id: "p2-text-2",
          type: "text",
          x: 50,
          y: 42,
          content: "\u6240\u5F97\u7686\u6240\u671F\uFF0C\u6240\u5931\u4EA6\u65E0\u788D",
          fontSize: 18,
          fontWeight: 500,
          align: "center",
          color: "#f8fafc"
        },
        {
          id: "p2-text-3",
          type: "text",
          x: 50,
          y: 55,
          content: "\u613F\u4F60\u7684\u6BCF\u4E00\u6B65\u90FD\u8D70\u5411\u5149\u4EAE",
          fontSize: 16,
          fontWeight: 400,
          align: "center",
          color: "#dbeafe"
        }
      ]
    },
    {
      id: "page-3",
      title: "\u843D\u6B3E",
      background: { color: "#11284d" },
      elements: [
        {
          id: "p3-image-1",
          type: "image",
          x: 50,
          y: 34,
          width: 60,
          height: 42,
          src: "https://images.unsplash.com/photo-1456324504439-367cee3b3c32?auto=format&fit=crop&w=1200&q=80",
          fit: "cover",
          borderRadius: 14,
          alt: "gift",
          isBackground: false
        },
        {
          id: "p3-text-1",
          type: "text",
          x: 50,
          y: 72,
          content: "Best wishes, from SA2Kit",
          fontSize: 18,
          fontWeight: 600,
          align: "center",
          color: "#f8fafc"
        }
      ]
    }
  ]
};

// src/festivalCard/core/normalize.ts
var ensurePage = (page, index) => ({
  id: page.id || `page-${index + 1}`,
  title: page.title || `\u7B2C ${index + 1} \u9875`,
  elements: Array.isArray(page.elements) ? page.elements : [],
  background: page.background || {}
});
var normalizeFestivalCardConfig = (config) => {
  const pages = config?.pages && config.pages.length > 0 ? config.pages : DEFAULT_FESTIVAL_CARD_CONFIG.pages;
  return {
    ...DEFAULT_FESTIVAL_CARD_CONFIG,
    ...config,
    background: {
      ...DEFAULT_FESTIVAL_CARD_CONFIG.background,
      ...config?.background || {}
    },
    backgroundMusic: {
      ...DEFAULT_FESTIVAL_CARD_CONFIG.backgroundMusic,
      ...config?.backgroundMusic || {},
      src: config?.backgroundMusic?.src ?? DEFAULT_FESTIVAL_CARD_CONFIG.backgroundMusic?.src ?? ""
    },
    pages: pages.map(ensurePage)
  };
};
var resizeFestivalCardPages = (config, pageCount) => {
  const safeCount = Math.max(1, Math.min(12, Math.floor(pageCount || 1)));
  const nextPages = [...config.pages];
  while (nextPages.length < safeCount) {
    const idx = nextPages.length;
    nextPages.push({
      id: `page-${idx + 1}`,
      title: `\u7B2C ${idx + 1} \u9875`,
      elements: [],
      background: {}
    });
  }
  return {
    ...config,
    pages: nextPages.slice(0, safeCount)
  };
};
var useFestivalCardConfig = (options) => {
  const [config, setConfig] = useState(
    () => normalizeFestivalCardConfig(options?.initialConfig || DEFAULT_FESTIVAL_CARD_CONFIG)
  );
  const [loading, setLoading] = useState(Boolean(options?.fetchConfig));
  const [saving, setSaving] = useState(false);
  useEffect(() => {
    const fetchConfig = options?.fetchConfig;
    if (!fetchConfig) return;
    let active = true;
    void fetchConfig().then((value) => {
      if (!active) return;
      setConfig(normalizeFestivalCardConfig(value));
    }).finally(() => {
      if (active) setLoading(false);
    });
    return () => {
      active = false;
    };
  }, [options?.fetchConfig]);
  const save = useCallback(async () => {
    const onSave = options?.onSave;
    if (!onSave) return;
    setSaving(true);
    try {
      await onSave(config);
    } finally {
      setSaving(false);
    }
  }, [config, options?.onSave]);
  return useMemo(
    () => ({
      config,
      setConfig,
      loading,
      saving,
      save
    }),
    [config, loading, save, saving]
  );
};
var elementStyle = (element) => ({
  position: "absolute",
  zIndex: 2,
  left: `${element.x}%`,
  top: `${element.y}%`,
  width: `${element.width ?? 70}%`,
  height: element.height ? `${element.height}%` : void 0,
  transform: "translate(-50%, -50%)"
});
var renderElement = (element) => {
  if (element.type === "text") {
    return /* @__PURE__ */ React3.createElement(
      "div",
      {
        key: element.id,
        style: {
          ...elementStyle(element),
          color: element.color || "#f8fafc",
          fontSize: element.fontSize || 18,
          fontWeight: element.fontWeight || 500,
          textAlign: element.align || "left",
          lineHeight: 1.45,
          whiteSpace: "pre-wrap"
        }
      },
      element.content
    );
  }
  return /* @__PURE__ */ React3.createElement(
    "img",
    {
      key: element.id,
      src: element.src,
      alt: element.alt || "festival-card-image",
      style: {
        ...elementStyle(element),
        objectFit: element.fit || "cover",
        borderRadius: element.borderRadius || 0,
        overflow: "hidden",
        boxShadow: "0 12px 30px rgba(2, 6, 23, 0.32)"
      }
    }
  );
};
var FestivalCardPageRenderer = ({ page }) => {
  const backgroundElement = page.elements.find(
    (element) => element.type === "image" && Boolean(element.isBackground)
  );
  const foregroundElements = page.elements.filter((element) => !(element.type === "image" && element.isBackground));
  return /* @__PURE__ */ React3.createElement(
    "div",
    {
      className: "relative h-full w-full overflow-hidden rounded-2xl",
      style: {
        backgroundColor: page.background?.color || "#0f172a",
        backgroundImage: backgroundElement ? `url(${backgroundElement.src})` : page.background?.image ? `url(${page.background.image})` : void 0,
        backgroundSize: "cover",
        backgroundPosition: "center"
      }
    },
    /* @__PURE__ */ React3.createElement("div", { className: "absolute inset-0 bg-slate-950/20" }),
    foregroundElements.map(renderElement)
  );
};

// src/festivalCard/components/FestivalCardBook3D.tsx
var FestivalCardBook3D = ({ config, className }) => {
  const [currentPage, setCurrentPage] = useState(0);
  const normalized = useMemo(() => normalizeFestivalCardConfig(config), [config]);
  const pages = normalized.pages;
  const canPrev = currentPage > 0;
  const canNext = currentPage < pages.length - 1;
  return /* @__PURE__ */ React3.createElement("div", { className }, /* @__PURE__ */ React3.createElement(
    "div",
    {
      className: "w-full min-h-[560px] rounded-3xl p-6 shadow-2xl shadow-slate-900/50",
      style: {
        background: `linear-gradient(145deg, ${normalized.background?.colorA || "#0c1a34"} 0%, ${normalized.background?.colorB || "#1f4f8a"} 100%)`
      }
    },
    /* @__PURE__ */ React3.createElement("div", { className: "mx-auto w-full max-w-5xl text-center text-slate-100" }, /* @__PURE__ */ React3.createElement("h3", { className: "mb-4 text-lg font-semibold" }, normalized.coverTitle || "Festival Card")),
    /* @__PURE__ */ React3.createElement("div", { className: "mx-auto w-full max-w-5xl" }, /* @__PURE__ */ React3.createElement("div", { className: "relative h-[460px]" }, pages.map((page, index) => /* @__PURE__ */ React3.createElement(
      "div",
      {
        key: page.id,
        className: "absolute inset-0 transition-opacity duration-500 ease-out",
        style: {
          opacity: index === currentPage ? 1 : 0,
          pointerEvents: index === currentPage ? "auto" : "none"
        }
      },
      /* @__PURE__ */ React3.createElement(FestivalCardPageRenderer, { page })
    )))),
    /* @__PURE__ */ React3.createElement("div", { className: "mt-5 flex justify-center gap-3" }, /* @__PURE__ */ React3.createElement(
      "button",
      {
        type: "button",
        disabled: !canPrev,
        onClick: () => setCurrentPage((p) => Math.max(0, p - 1)),
        className: "rounded-full bg-white px-5 py-2 text-sm font-medium text-slate-900 disabled:cursor-not-allowed disabled:opacity-45"
      },
      "\u4E0A\u4E00\u9875"
    ), /* @__PURE__ */ React3.createElement(
      "button",
      {
        type: "button",
        disabled: !canNext,
        onClick: () => setCurrentPage((p) => Math.min(pages.length - 1, p + 1)),
        className: "rounded-full bg-sky-300 px-5 py-2 text-sm font-medium text-slate-900 disabled:cursor-not-allowed disabled:opacity-45"
      },
      "\u4E0B\u4E00\u9875"
    ))
  ), normalized.backgroundMusic?.src ? /* @__PURE__ */ React3.createElement(
    "audio",
    {
      src: normalized.backgroundMusic.src,
      autoPlay: normalized.backgroundMusic.autoPlay,
      loop: normalized.backgroundMusic.loop,
      controls: true,
      className: "mt-3 w-full"
    }
  ) : null);
};
var createTextElement = (pageIndex) => ({
  id: `text-${Date.now()}-${pageIndex}`,
  type: "text",
  x: 50,
  y: 50,
  content: "\u8BF7\u8F93\u5165\u6587\u5B57",
  fontSize: 18,
  fontWeight: 500,
  align: "center",
  color: "#ffffff"
});
var createImageElement = (pageIndex) => ({
  id: `image-${Date.now()}-${pageIndex}`,
  type: "image",
  x: 50,
  y: 50,
  width: 60,
  height: 40,
  src: "https://images.unsplash.com/photo-1482517967863-00e15c9b44be?auto=format&fit=crop&w=1200&q=80",
  fit: "cover",
  borderRadius: 12
});
var FestivalCardConfigEditor = ({ value, onChange }) => {
  const [activePageIndex, setActivePageIndex] = useState(0);
  const page = value.pages[activePageIndex];
  const canEditPage = Boolean(page);
  const pageOptions = useMemo(() => value.pages.map((_, index) => index), [value.pages]);
  const updateElement = (elementId, patch) => {
    onChange({
      ...value,
      pages: value.pages.map(
        (p, pIndex) => pIndex === activePageIndex ? {
          ...p,
          elements: p.elements.map((el) => el.id === elementId ? { ...el, ...patch } : el)
        } : p
      )
    });
  };
  return /* @__PURE__ */ React3.createElement("div", { className: "rounded-2xl border border-slate-200 bg-white p-4 text-slate-900 shadow-sm" }, /* @__PURE__ */ React3.createElement("div", { className: "grid gap-3" }, /* @__PURE__ */ React3.createElement("label", { className: "grid gap-1.5" }, /* @__PURE__ */ React3.createElement("span", { className: "text-sm font-medium text-slate-700" }, "\u9875\u9762\u6570\u91CF"), /* @__PURE__ */ React3.createElement(
    "input",
    {
      type: "number",
      min: 1,
      max: 12,
      value: value.pages.length,
      onChange: (event) => onChange(resizeFestivalCardPages(value, Number(event.target.value))),
      className: "rounded-lg border border-slate-300 bg-white px-3 py-2 text-slate-900 outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
    }
  )), /* @__PURE__ */ React3.createElement("label", { className: "grid gap-1.5" }, /* @__PURE__ */ React3.createElement("span", { className: "text-sm font-medium text-slate-700" }, "\u80CC\u666F\u97F3\u4E50 URL"), /* @__PURE__ */ React3.createElement(
    "input",
    {
      type: "url",
      value: value.backgroundMusic?.src || "",
      onChange: (event) => onChange({
        ...value,
        backgroundMusic: {
          ...value.backgroundMusic,
          src: event.target.value
        }
      }),
      className: "rounded-lg border border-slate-300 bg-white px-3 py-2 text-slate-900 outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
    }
  )), /* @__PURE__ */ React3.createElement("label", { className: "grid gap-1.5" }, /* @__PURE__ */ React3.createElement("span", { className: "text-sm font-medium text-slate-700" }, "\u7F16\u8F91\u9875\u9762"), /* @__PURE__ */ React3.createElement(
    "select",
    {
      value: activePageIndex,
      onChange: (event) => setActivePageIndex(Number(event.target.value)),
      className: "rounded-lg border border-slate-300 bg-white px-3 py-2 text-slate-900 outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
    },
    pageOptions.map((index) => /* @__PURE__ */ React3.createElement("option", { key: index, value: index }, "\u7B2C ", index + 1, " \u9875"))
  ))), canEditPage ? /* @__PURE__ */ React3.createElement("div", { className: "mt-4" }, /* @__PURE__ */ React3.createElement("div", { className: "mb-3 flex gap-2" }, /* @__PURE__ */ React3.createElement(
    "button",
    {
      type: "button",
      onClick: () => onChange({
        ...value,
        pages: value.pages.map(
          (p, index) => index === activePageIndex ? { ...p, elements: [...p.elements, createTextElement(index)] } : p
        )
      }),
      className: "rounded-lg bg-slate-900 px-3 py-2 text-sm font-medium text-white"
    },
    "+ \u6587\u5B57"
  ), /* @__PURE__ */ React3.createElement(
    "button",
    {
      type: "button",
      onClick: () => onChange({
        ...value,
        pages: value.pages.map(
          (p, index) => index === activePageIndex ? { ...p, elements: [...p.elements, createImageElement(index)] } : p
        )
      }),
      className: "rounded-lg bg-sky-600 px-3 py-2 text-sm font-medium text-white"
    },
    "+ \u56FE\u7247"
  )), /* @__PURE__ */ React3.createElement("div", { className: "grid max-h-[340px] gap-2.5 overflow-auto pr-1" }, (page?.elements ?? []).map((element) => /* @__PURE__ */ React3.createElement("div", { key: element.id, className: "rounded-xl border border-slate-200 bg-slate-50 p-3" }, /* @__PURE__ */ React3.createElement("div", { className: "mb-2 text-xs font-semibold tracking-wide text-slate-500" }, element.type.toUpperCase()), element.type === "text" ? /* @__PURE__ */ React3.createElement(
    "textarea",
    {
      value: element.content,
      onChange: (event) => updateElement(element.id, { content: event.target.value }),
      rows: 3,
      className: "w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
    }
  ) : /* @__PURE__ */ React3.createElement("div", { className: "grid gap-2" }, /* @__PURE__ */ React3.createElement(
    "input",
    {
      type: "url",
      value: element.src,
      onChange: (event) => updateElement(element.id, { src: event.target.value }),
      className: "w-full rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
    }
  ), /* @__PURE__ */ React3.createElement("label", { className: "inline-flex items-center gap-2 text-sm text-slate-700" }, /* @__PURE__ */ React3.createElement(
    "input",
    {
      type: "checkbox",
      checked: Boolean(element.isBackground),
      onChange: (event) => updateElement(element.id, { isBackground: event.target.checked }),
      className: "h-4 w-4 rounded border-slate-300 text-sky-600"
    }
  ), "\u4F5C\u4E3A\u672C\u9875\u80CC\u666F\u56FE")))))) : null);
};

// src/festivalCard/components/FestivalCardStudio.tsx
var FestivalCardStudio = ({ initialConfig, fetchConfig, onSave }) => {
  const { config, setConfig, loading, save, saving } = useFestivalCardConfig({
    initialConfig: normalizeFestivalCardConfig(initialConfig),
    fetchConfig,
    onSave
  });
  if (loading) return /* @__PURE__ */ React3.createElement("div", null, "\u52A0\u8F7D\u4E2D...");
  return /* @__PURE__ */ React3.createElement("div", { className: "grid gap-4 lg:grid-cols-[1.45fr_1fr]" }, /* @__PURE__ */ React3.createElement(FestivalCardBook3D, { config, className: "h-full" }), /* @__PURE__ */ React3.createElement("div", null, /* @__PURE__ */ React3.createElement(FestivalCardConfigEditor, { value: config, onChange: setConfig }), onSave ? /* @__PURE__ */ React3.createElement(
    "button",
    {
      type: "button",
      onClick: () => void save(),
      disabled: saving,
      className: "mt-3 w-full rounded-lg bg-slate-900 px-4 py-2.5 text-sm font-medium text-white disabled:opacity-60"
    },
    saving ? "\u4FDD\u5B58\u4E2D..." : "\u4FDD\u5B58\u914D\u7F6E"
  ) : null));
};

// src/festivalCard/components/FestivalCardConfigPage.tsx
var FestivalCardConfigPage = ({
  apiBase = "/api/festivalCard",
  cardId,
  mainPagePath = "/festivalCard"
}) => {
  const [list, setList] = useState([]);
  const [selectedId, setSelectedId] = useState(cardId || "default-festival-card");
  const parseListResponse2 = (data) => {
    if (!data || typeof data !== "object") return [];
    const payload = data.data;
    if (!Array.isArray(payload)) return [];
    return payload.filter((item) => Boolean(item && typeof item === "object" && typeof item.id === "string")).map((item) => ({ id: item.id, name: item.name }));
  };
  const parseConfigResponse2 = (data) => {
    if (!data || typeof data !== "object") return normalizeFestivalCardConfig();
    const payload = data.data;
    if (!payload || typeof payload !== "object") return normalizeFestivalCardConfig();
    return normalizeFestivalCardConfig(payload);
  };
  const reloadList = useCallback(async () => {
    try {
      const response = await fetch(apiBase, { cache: "no-store" });
      if (!response.ok) throw new Error(`\u52A0\u8F7D\u5361\u7247\u5217\u8868\u5931\u8D25: ${response.status}`);
      const data = await response.json();
      setList(parseListResponse2(data));
    } catch (error) {
      window.alert(error.message || "\u52A0\u8F7D\u5361\u7247\u5217\u8868\u5931\u8D25");
    }
  }, [apiBase]);
  useEffect(() => {
    void reloadList();
  }, [reloadList]);
  const fetchConfig = async () => {
    const response = await fetch(`${apiBase}/${encodeURIComponent(selectedId)}`, { cache: "no-store" });
    if (!response.ok) {
      const message = `\u52A0\u8F7D\u914D\u7F6E\u5931\u8D25: ${response.status}`;
      window.alert(message);
      throw new Error(message);
    }
    const data = await response.json();
    return parseConfigResponse2(data);
  };
  const saveConfig = async (config) => {
    try {
      const response = await fetch(`${apiBase}/${encodeURIComponent(selectedId)}`, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ config })
      });
      if (!response.ok) throw new Error(`\u4FDD\u5B58\u5931\u8D25: ${response.status}`);
      await reloadList();
      window.alert("\u4FDD\u5B58\u6210\u529F");
    } catch (error) {
      window.alert(error.message || "\u4FDD\u5B58\u5931\u8D25");
      throw error;
    }
  };
  const createNew = async () => {
    const name = window.prompt("\u8BF7\u8F93\u5165\u65B0\u5361\u7247\u540D\u79F0");
    if (!name) return;
    const id = `festival-${Date.now()}`;
    const config = normalizeFestivalCardConfig({
      id,
      name
    });
    try {
      const response = await fetch(`${apiBase}/${encodeURIComponent(id)}`, {
        method: "PUT",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ config })
      });
      if (!response.ok) throw new Error(`\u521B\u5EFA\u5931\u8D25: ${response.status}`);
      setSelectedId(id);
      await reloadList();
      window.alert("\u65B0\u5361\u7247\u521B\u5EFA\u6210\u529F");
    } catch (error) {
      window.alert(error.message || "\u521B\u5EFA\u5931\u8D25");
    }
  };
  const mainLink = useMemo(() => `${mainPagePath}?cardId=${encodeURIComponent(selectedId)}`, [mainPagePath, selectedId]);
  return /* @__PURE__ */ React3.createElement("div", { className: "grid gap-3" }, /* @__PURE__ */ React3.createElement("div", { className: "flex flex-wrap items-center gap-2" }, /* @__PURE__ */ React3.createElement(
    "select",
    {
      value: selectedId,
      onChange: (event) => setSelectedId(event.target.value),
      className: "min-w-[200px] rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm text-slate-900 outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100"
    },
    list.map((item) => /* @__PURE__ */ React3.createElement("option", { key: item.id, value: item.id }, item.name || item.id))
  ), /* @__PURE__ */ React3.createElement("button", { type: "button", onClick: () => void createNew(), className: "rounded-lg bg-slate-900 px-3 py-2 text-sm font-medium text-white" }, "\u65B0\u5EFA\u5361\u7247"), /* @__PURE__ */ React3.createElement("a", { href: mainLink, className: "rounded-lg border border-sky-200 bg-sky-50 px-3 py-2 text-sm text-sky-700" }, "\u6253\u5F00\u4E3B\u9875\u9762")), /* @__PURE__ */ React3.createElement(FestivalCardStudio, { fetchConfig, onSave: saveConfig }));
};
var isSummary = (value) => {
  if (!value || typeof value !== "object") return false;
  return typeof value.id === "string";
};
var parseListResponse = (data) => {
  if (!data || typeof data !== "object") return [];
  const payload = data.data;
  if (!Array.isArray(payload)) return [];
  return payload.filter(isSummary).map((item) => ({ id: item.id, name: item.name }));
};
var parseConfigResponse = (data) => {
  if (!data || typeof data !== "object") return null;
  const payload = data.data;
  if (!payload || typeof payload !== "object") return null;
  if (!Array.isArray(payload.pages)) return null;
  return payload;
};
var FestivalCardManagedPage = ({
  apiBase = "/api/festivalCard",
  cardId,
  configPagePath = "/festivalCard/config"
}) => {
  const [currentCardId, setCurrentCardId] = useState(cardId || "");
  const [config, setConfig] = useState(null);
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    const fetchList = async () => {
      const response = await fetch(apiBase, { cache: "no-store" });
      const data = await response.json();
      const items = parseListResponse(data);
      const first = items[0];
      if (!currentCardId && first) {
        setCurrentCardId(first.id);
      }
    };
    void fetchList();
  }, [apiBase, currentCardId]);
  useEffect(() => {
    if (!currentCardId) return;
    setLoading(true);
    void fetch(`${apiBase}/${encodeURIComponent(currentCardId)}`, { cache: "no-store" }).then((res) => res.json()).then((data) => setConfig(parseConfigResponse(data))).finally(() => setLoading(false));
  }, [apiBase, currentCardId]);
  const configLink = useMemo(() => {
    if (!currentCardId) return configPagePath;
    return `${configPagePath}?cardId=${encodeURIComponent(currentCardId)}`;
  }, [configPagePath, currentCardId]);
  return /* @__PURE__ */ React3.createElement("div", { className: "space-y-4" }, /* @__PURE__ */ React3.createElement("div", { className: "flex justify-end" }, /* @__PURE__ */ React3.createElement("a", { href: configLink, className: "rounded-lg border border-slate-700 bg-slate-900 px-3 py-1.5 text-sm text-sky-300" }, "\u8FDB\u5165\u914D\u7F6E\u9875")), /* @__PURE__ */ React3.createElement("div", null, loading || !config ? /* @__PURE__ */ React3.createElement("div", { className: "py-12 text-center text-slate-400" }, "\u52A0\u8F7D\u4E2D...") : /* @__PURE__ */ React3.createElement(FestivalCardBook3D, { config })));
};

// src/festivalCard/server/db.ts
var dbAdapter = null;
var getFestivalCardDb = () => dbAdapter;

// src/festivalCard/services/festivalCardService.ts
var FestivalCardService = class {
  constructor(options) {
    this.db = options?.db || getFestivalCardDb();
  }
  async listConfigs() {
    if (!this.db) {
      return [{ id: DEFAULT_FESTIVAL_CARD_CONFIG.id || "default-festival-card", name: DEFAULT_FESTIVAL_CARD_CONFIG.name }];
    }
    if (this.db.listConfigs) {
      const list = await this.db.listConfigs();
      return list.length > 0 ? list : [{ id: DEFAULT_FESTIVAL_CARD_CONFIG.id || "default-festival-card", name: DEFAULT_FESTIVAL_CARD_CONFIG.name }];
    }
    return [{ id: DEFAULT_FESTIVAL_CARD_CONFIG.id || "default-festival-card", name: DEFAULT_FESTIVAL_CARD_CONFIG.name }];
  }
  async getConfig(cardId = "default-festival-card") {
    if (!this.db) return DEFAULT_FESTIVAL_CARD_CONFIG;
    const config = await this.db.getConfig(cardId);
    return normalizeFestivalCardConfig(config);
  }
  async saveConfig(cardId, config) {
    const normalized = normalizeFestivalCardConfig(config);
    if (!this.db) return normalized;
    await this.db.saveConfig(cardId, normalized);
    return normalized;
  }
  async deleteConfig(cardId) {
    if (!this.db?.deleteConfig) return;
    await this.db.deleteConfig(cardId);
  }
};
var memoryStore = /* @__PURE__ */ new Map();
var defaultId = DEFAULT_FESTIVAL_CARD_CONFIG.id || "default-festival-card";
if (!memoryStore.has(defaultId)) {
  memoryStore.set(defaultId, DEFAULT_FESTIVAL_CARD_CONFIG);
}
var createInMemoryFestivalCardDb = () => ({
  listConfigs() {
    return Promise.resolve(
      Array.from(memoryStore.entries()).map(([id, config]) => ({
        id,
        name: config.name || id
      }))
    );
  },
  getConfig(id) {
    return Promise.resolve(memoryStore.get(id) || null);
  },
  saveConfig(id, config) {
    memoryStore.set(id, config);
    return Promise.resolve();
  },
  deleteConfig(id) {
    memoryStore.delete(id);
    return Promise.resolve();
  }
});

export { DEFAULT_FESTIVAL_CARD_CONFIG, FestivalCardBook3D, FestivalCardConfigEditor, FestivalCardConfigPage, FestivalCardManagedPage, FestivalCardPageRenderer, FestivalCardService, FestivalCardStudio, createInMemoryFestivalCardDb, normalizeFestivalCardConfig, resizeFestivalCardPages, useFestivalCardConfig };
//# sourceMappingURL=index.mjs.map
//# sourceMappingURL=index.mjs.map