// pages-card-upload.jsx - Card image submission page
const { Icon } = window.LCS;

const CARD_UPLOAD_PAIRS = Array.from({ length: 8 }, (_, index) => {
  const n = String(index + 1).padStart(2, "0");
  return {
    number: index + 1,
    front: { id: `front_${n}`, label: "表ファイル" },
    back: { id: `back_${n}`, label: "裏ファイル" },
  };
});
const CARD_UPLOAD_COMMON_BACK_SLOT = { id: "back_common", label: "共通裏ファイル" };
const CARD_UPLOAD_SLOTS = CARD_UPLOAD_PAIRS.flatMap((pair) => [pair.front, pair.back]);

const CARD_UPLOAD_SPEC = {
  width: 815,
  height: 1122,
  maxSize: 5 * 1024 * 1024,
  maxSizeLabel: "5MB",
  types: ["image/png", "image/jpeg"],
};

const readImageSize = (file) => new Promise((resolve, reject) => {
  const url = URL.createObjectURL(file);
  const img = new Image();
  img.onload = () => {
    URL.revokeObjectURL(url);
    resolve({ width: img.naturalWidth, height: img.naturalHeight });
  };
  img.onerror = () => {
    URL.revokeObjectURL(url);
    reject(new Error("画像を読み込めませんでした。"));
  };
  img.src = url;
});

const CardUploadPage = () => {
  const isPreviewMode = new URLSearchParams(window.location.search).get("preview") === "1";
  const [token, setToken] = React.useState("");
  const [status, setStatus] = React.useState("loading");
  const [statusError, setStatusError] = React.useState("");
  const [files, setFiles] = React.useState({});
  const [fileErrors, setFileErrors] = React.useState({});
  const [previews, setPreviews] = React.useState({});
  const [submitError, setSubmitError] = React.useState("");
  const [isSubmitting, setIsSubmitting] = React.useState(false);
  const [hasConfirmedSpec, setHasConfirmedSpec] = React.useState(false);
  const [backMode, setBackMode] = React.useState("individual");
  const [previewPairIndex, setPreviewPairIndex] = React.useState(0);
  const previewAreaRef = React.useRef(null);
  const previewUrlsRef = React.useRef([]);

  React.useEffect(() => {
    const currentToken = new URLSearchParams(window.location.search).get("token") || "";
    if (isPreviewMode) {
      setToken("__preview__");
      setStatus("pending");
      setStatusError("");
      return;
    }

    setToken(currentToken);
    if (!currentToken) {
      setStatus("invalid");
      setStatusError("この入稿URLは無効、または有効期限が切れています。購入時のメールアドレスを添えてお問い合わせください。");
      return;
    }

    let active = true;
    fetch(`/api/upload-status?token=${encodeURIComponent(currentToken)}`)
      .then((response) => response.json().then((body) => ({ response, body })).catch(() => ({ response, body: {} })))
      .then(({ response, body }) => {
        if (!active) return;
        if (!response.ok || !body.ok) {
          setStatus("invalid");
          setStatusError(body.error === "expired"
            ? "この入稿URLは有効期限が切れています。購入時のメールアドレスを添えてお問い合わせください。"
            : "この入稿URLは無効、または有効期限が切れています。購入時のメールアドレスを添えてお問い合わせください。");
          return;
        }
        setStatus(body.status === "uploaded" ? "uploaded" : "pending");
      })
      .catch(() => {
        if (!active) return;
        setStatus("invalid");
        setStatusError("入稿URLを確認できませんでした。時間をおいてもう一度お試しください。");
      });
    return () => { active = false; };
  }, [isPreviewMode]);

  React.useEffect(() => () => {
    previewUrlsRef.current.forEach((url) => URL.revokeObjectURL(url));
  }, []);

  const isCommonBackMode = backMode === "common";
  const requiredSlots = isCommonBackMode
    ? [...CARD_UPLOAD_PAIRS.map((pair) => pair.front), CARD_UPLOAD_COMMON_BACK_SLOT]
    : CARD_UPLOAD_SLOTS;
  const selectedCount = requiredSlots.filter((slot) => files[slot.id]).length;
  const relevantFileErrors = requiredSlots.filter((slot) => fileErrors[slot.id]);
  const canSubmit = !isPreviewMode && status === "pending" && selectedCount === requiredSlots.length && !relevantFileErrors.length && hasConfirmedSpec && !isSubmitting;
  const currentPreviewPair = CARD_UPLOAD_PAIRS[previewPairIndex] || CARD_UPLOAD_PAIRS[0];
  const currentBackSlot = isCommonBackMode ? CARD_UPLOAD_COMMON_BACK_SLOT : currentPreviewPair.back;
  const previewSlots = [
    { title: `カード ${currentPreviewPair.number} 表`, slot: currentPreviewPair.front },
    { title: isCommonBackMode ? "共通 裏" : `カード ${currentPreviewPair.number} 裏`, slot: currentBackSlot },
  ];

  const scrollToPreview = (index) => {
    setPreviewPairIndex(index);
    window.requestAnimationFrame(() => {
      previewAreaRef.current?.scrollIntoView({ behavior: "smooth", block: "start" });
    });
  };

  const setSlotFile = async (slot, file) => {
    setSubmitError("");
    if (!file) return;

    setFileErrors((current) => {
      const next = { ...current };
      delete next[slot.id];
      return next;
    });

    const nextError = [];
    if (!CARD_UPLOAD_SPEC.types.includes(file.type)) nextError.push("PNGまたはJPGを選択してください。");
    if (file.size > CARD_UPLOAD_SPEC.maxSize) nextError.push(`${CARD_UPLOAD_SPEC.maxSizeLabel}以下の画像を選択してください。`);

    try {
      const size = await readImageSize(file);
      if (size.width !== CARD_UPLOAD_SPEC.width || size.height !== CARD_UPLOAD_SPEC.height) {
        nextError.push(`画像サイズは${CARD_UPLOAD_SPEC.width}px x ${CARD_UPLOAD_SPEC.height}pxにしてください。`);
      }
    } catch (error) {
      nextError.push(error.message);
    }

    setFiles((current) => ({ ...current, [slot.id]: file }));
    setPreviews((current) => {
      if (current[slot.id]) URL.revokeObjectURL(current[slot.id]);
      previewUrlsRef.current = previewUrlsRef.current.filter((url) => url !== current[slot.id]);
      const previewUrl = URL.createObjectURL(file);
      previewUrlsRef.current.push(previewUrl);
      return { ...current, [slot.id]: previewUrl };
    });
    setFileErrors((current) => {
      const next = { ...current };
      if (nextError.length) next[slot.id] = nextError.join(" ");
      else delete next[slot.id];
      return next;
    });
  };

  const handleSubmit = async (event) => {
    event.preventDefault();
    setSubmitError("");
    if (isPreviewMode) {
      setSubmitError("プレビュー中はアップロードできません。実際の入稿URLから送信してください。");
      return;
    }
    if (!canSubmit) {
      setSubmitError("必要な画像をすべて正しい形式で指定し、入稿時の注意事項を確認してください。");
      return;
    }

    setIsSubmitting(true);
    try {
      const form = new FormData();
      form.append("token", token);
      form.append("back_mode", isCommonBackMode ? "common" : "individual");
      CARD_UPLOAD_PAIRS.forEach((pair) => {
        form.append(pair.front.id, files[pair.front.id]);
        form.append(pair.back.id, isCommonBackMode ? files[CARD_UPLOAD_COMMON_BACK_SLOT.id] : files[pair.back.id]);
      });
      const response = await fetch("/api/card-upload", { method: "POST", body: form });
      const body = await response.json().catch(() => ({}));
      if (!response.ok || !body.ok) {
        throw new Error(body.error === "uploaded"
          ? "このURLでの入稿はすでに完了しています。"
          : "アップロードに失敗しました。時間をおいてもう一度お試しください。");
      }
      setStatus("uploaded");
      window.scrollTo({ top: 0, behavior: "smooth" });
    } catch (error) {
      setSubmitError(error.message || "アップロードに失敗しました。時間をおいてもう一度お試しください。");
    } finally {
      setIsSubmitting(false);
    }
  };

  const renderMessage = (kind) => (
    <main className="page">
      <div className="shell">
        <div className="card-upload-message" role="status" aria-live="polite">
          <div className="complete__seal">
            <Icon name={kind === "uploaded" ? "check" : "info"} size={36} />
          </div>
          <h1>{kind === "uploaded" ? "入稿は完了しています" : "入稿URLを確認できません"}</h1>
          <p>{kind === "uploaded"
            ? "このURLでの入稿は完了しています。再入稿が必要な場合は、購入時のメールアドレスを添えてお問い合わせください。"
            : statusError}</p>
        </div>
      </div>
    </main>
  );

  if (status === "loading") {
    return (
      <main className="page">
        <div className="shell">
          <div className="card-upload-message" role="status" aria-live="polite">
            <span className="spinner spinner--dark" aria-hidden="true" />
            <p>入稿URLを確認しています。</p>
          </div>
        </div>
      </main>
    );
  }

  if (status === "uploaded") return renderMessage("uploaded");
  if (status === "invalid") return renderMessage("invalid");

  return (
    <main className="page">
      <div className="shell">
        <div className="page-head">
          <div>
            <div className="page-head__en">CARD UPLOAD</div>
            <h1>カード画像をアップロード</h1>
          </div>
          <div className="page-head__deco">LCS8</div>
        </div>

        <div className="card-upload-layout card-upload-layout--single">
          <form className="card-upload-form" onSubmit={handleSubmit} noValidate>
            <div className="card-upload-progress" aria-live="polite">
              <strong>{selectedCount} / {requiredSlots.length}</strong>
              <span>選択済み</span>
            </div>

            <div className="card-upload-back-mode" role="group" aria-label="裏面デザインの指定方法">
              <span>裏面デザイン</span>
              <label>
                <input
                  type="radio"
                  name="back-mode"
                  value="individual"
                  checked={backMode === "individual"}
                  onChange={() => setBackMode("individual")}
                />
                <span>8枚それぞれ指定</span>
              </label>
              <label>
                <input
                  type="radio"
                  name="back-mode"
                  value="common"
                  checked={backMode === "common"}
                  onChange={() => setBackMode("common")}
                />
                <span>共通デザイン1種類</span>
              </label>
            </div>

            {isPreviewMode && (
              <div className="note card-upload-preview-mode-note" style={{ marginBottom: 0 }}>
                <div className="note__icon">!</div>
                <div>プレビュー表示です。ファイル選択の見た目は確認できますが、アップロードはできません。</div>
              </div>
            )}

            <div className="card-upload-preview-pair" ref={previewAreaRef}>
              {previewSlots.map(({ title, slot }) => (
                <div className={"card-upload-preview-panel" + (fileErrors[slot.id] ? " card-upload-preview-panel--error" : "")} key={slot.id}>
                  <div className="card-upload-preview-panel__head">
                    <span>{title}</span>
                    <small>{slot.id}</small>
                  </div>
                  <div className="card-upload-preview-frame">
                    {previews[slot.id]
                      ? <img src={previews[slot.id]} alt="" />
                      : <div className="card-upload-preview-empty"><Icon name="card" size={24} /><span>未選択</span></div>}
                    <div className="card-upload-preview-cutline" aria-hidden="true" />
                    <div className="card-upload-preview-direction" aria-hidden="true">
                      <span className="card-upload-preview-direction__top">上</span>
                      <span className="card-upload-preview-direction__right">右</span>
                      <span className="card-upload-preview-direction__bottom">下</span>
                      <span className="card-upload-preview-direction__left">左</span>
                    </div>
                  </div>
                  {fileErrors[slot.id] && <span className="field__err" role="alert">{fileErrors[slot.id]}</span>}
                </div>
              ))}
            </div>

            <div className="card-upload-rows">
              {CARD_UPLOAD_PAIRS.map((pair, index) => {
                const hasError = fileErrors[pair.front.id] || (!isCommonBackMode && fileErrors[pair.back.id]);
                return (
                  <div className={"card-upload-row" + (isCommonBackMode ? " card-upload-row--common-back" : "") + (hasError ? " card-upload-row--error" : "")} key={pair.number}>
                    <div className="card-upload-row__num">カード {pair.number}</div>
                    <div className="card-upload-row__field">
                      <label htmlFor={`upload-${pair.front.id}`}>表ファイル読み込み</label>
                      <input
                        id={`upload-${pair.front.id}`}
                        type="file"
                        accept="image/png,image/jpeg"
                        onChange={(event) => setSlotFile(pair.front, event.target.files[0])}
                        aria-invalid={!!fileErrors[pair.front.id]}
                      />
                      {fileErrors[pair.front.id] && <span className="field__err" role="alert">{fileErrors[pair.front.id]}</span>}
                    </div>
                    {!isCommonBackMode && (
                      <div className="card-upload-row__field">
                        <label htmlFor={`upload-${pair.back.id}`}>裏ファイル読み込み</label>
                        <input
                          id={`upload-${pair.back.id}`}
                          type="file"
                          accept="image/png,image/jpeg"
                          onChange={(event) => setSlotFile(pair.back, event.target.files[0])}
                          aria-invalid={!!fileErrors[pair.back.id]}
                        />
                        {fileErrors[pair.back.id] && <span className="field__err" role="alert">{fileErrors[pair.back.id]}</span>}
                      </div>
                    )}
                    <button className="btn card-upload-row__preview" type="button" onClick={() => scrollToPreview(index)}>
                      <Icon name="search" size={16} /> プレビュー
                    </button>
                  </div>
                );
              })}
            </div>

            {isCommonBackMode && (
              <div className={"card-upload-common-back" + (fileErrors[CARD_UPLOAD_COMMON_BACK_SLOT.id] ? " card-upload-common-back--error" : "")}>
                <div>
                  <b>共通裏面デザイン</b>
                  <span>8枚すべての裏面に同じ画像を使用します。</span>
                </div>
                <input
                  id={`upload-${CARD_UPLOAD_COMMON_BACK_SLOT.id}`}
                  type="file"
                  accept="image/png,image/jpeg"
                  onChange={(event) => setSlotFile(CARD_UPLOAD_COMMON_BACK_SLOT, event.target.files[0])}
                  aria-invalid={!!fileErrors[CARD_UPLOAD_COMMON_BACK_SLOT.id]}
                />
                {fileErrors[CARD_UPLOAD_COMMON_BACK_SLOT.id] && <span className="field__err" role="alert">{fileErrors[CARD_UPLOAD_COMMON_BACK_SLOT.id]}</span>}
              </div>
            )}

            <section className="card-upload-spec-block" aria-labelledby="card-upload-spec-title">
              <h3 id="card-upload-spec-title">入稿仕様</h3>
              <p>表面8枚と、裏面8枚または共通裏面1枚を指定してください。</p>
              <div className="card-upload-spec-list">
                <div className="card-upload-spec-item">
                  <b><Icon name="card" size={14} /> 画像サイズ</b>
                  <span>815px x 1122px</span>
                </div>
                <div className="card-upload-spec-item">
                  <b><Icon name="doc" size={14} /> 形式と容量</b>
                  <span>PNGまたはJPG、1枚あたり5MBまで</span>
                </div>
              </div>
              <div className="card-upload-confirm">
                <b>入稿時の注意事項</b>
                <ul>
                  <li>画像データの送信は一度のみです。</li>
                  <li>送信後、購入時に届いた入稿URLは使用できなくなります。</li>
                  <li>送信後の画像差し替え、修正依頼、再アップロードは原則としてお受けできません。</li>
                  <li>画像の内容、向き、枚数、表裏の組み合わせに誤りがないか、必ず確認してから送信してください。</li>
                </ul>
                <label className="card-upload-confirm__check">
                  <input
                    type="checkbox"
                    checked={hasConfirmedSpec}
                    onChange={(event) => setHasConfirmedSpec(event.target.checked)}
                  />
                  <span>上記の内容を確認し同意します</span>
                </label>
              </div>
            </section>

            {submitError && (
              <div className="note card-upload-submit-error" role="alert" style={{ marginBottom: 0 }}>
                <div className="note__icon">!</div>
                <div>{submitError}</div>
              </div>
            )}

            <button
              className="btn btn--accent btn--xl btn--block card-upload-submit"
              type="submit"
              disabled={!canSubmit}
              aria-busy={isSubmitting}
              style={!canSubmit ? { opacity: 0.75, cursor: "not-allowed" } : {}}
            >
              {isPreviewMode
                ? <><Icon name="info" size={18} /> プレビュー中</>
                : isSubmitting
                ? <><span className="spinner" aria-hidden="true" /> アップロード中...</>
                : <><Icon name="arrow-r" size={18} /> 画像をアップロード</>}
            </button>
          </form>
        </div>
      </div>
    </main>
  );
};

window.LCS = Object.assign(window.LCS || {}, { CardUploadPage });
