// 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_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 previewMode = new URLSearchParams(window.location.search).get("preview") || "";
  const isPreviewMode = previewMode === "1";
  const isUploadedPreviewMode = previewMode === "uploaded";
  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 [validationModal, setValidationModal] = React.useState(null);
  const [isSubmitting, setIsSubmitting] = React.useState(false);
  const [hasConfirmedSpec, setHasConfirmedSpec] = React.useState(false);
  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 (isUploadedPreviewMode) {
      setToken("__preview_uploaded__");
      setStatus("uploaded");
      setStatusError("");
      return;
    }
    if (isPreviewMode) {
      setToken("__preview__");
      setStatus("pending");
      setStatusError("");
      return;
    }

    setToken(currentToken);
    if (!currentToken) {
      setStatus("invalid");
      setStatusError("この入稿URLは無効、または有効期限が切れています。購入時のメールに記載された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からの画像入稿はできません。"
            : "この入稿URLは無効、または有効期限が切れています。購入時のメールに記載されたURLをご確認ください。");
          return;
        }
        setStatus(body.status === "uploaded" ? "uploaded" : "pending");
      })
      .catch(() => {
        if (!active) return;
        setStatus("invalid");
        setStatusError("入稿URLを確認できませんでした。時間をおいてもう一度お試しください。");
      });
    return () => { active = false; };
  }, [isPreviewMode, isUploadedPreviewMode]);

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

  const requiredSlots = CARD_UPLOAD_SLOTS;
  const selectedCount = requiredSlots.filter((slot) => files[slot.id]).length;
  const relevantFileErrors = requiredSlots.filter((slot) => fileErrors[slot.id]);
  const currentPreviewPair = CARD_UPLOAD_PAIRS[previewPairIndex] || CARD_UPLOAD_PAIRS[0];
  const previewSlots = [
    { title: `カード ${currentPreviewPair.number} 表`, slot: currentPreviewPair.front },
    { title: `カード ${currentPreviewPair.number} 裏`, slot: currentPreviewPair.back },
  ];

  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 renderFilePicker = (slot, label) => {
    const inputId = `upload-${slot.id}`;
    const hasFile = !!files[slot.id];
    return (
      <div className="card-upload-row__field">
        <span className="card-upload-row__label">{label}</span>
        <input
          id={inputId}
          className="card-upload-file-input"
          type="file"
          accept="image/png,image/jpeg"
          onChange={(event) => setSlotFile(slot, event.target.files[0])}
          aria-invalid={!!fileErrors[slot.id]}
        />
        <label className="card-upload-file-picker" htmlFor={inputId}>
          <span>ファイルを選択</span>
          <b>{hasFile ? "選択済み" : "未選択"}</b>
        </label>
        {fileErrors[slot.id] && <span className="field__err" role="alert">{fileErrors[slot.id]}</span>}
      </div>
    );
  };

  const handleSubmit = async (event) => {
    event.preventDefault();
    setSubmitError("");
    if (isPreviewMode) {
      setValidationModal({
        title: "プレビュー中です",
        message: "プレビュー中はアップロードできません。実際の入稿URLから送信してください。",
      });
      return;
    }
    if (selectedCount < requiredSlots.length) {
      setValidationModal({
        title: "入稿画像が不足しています",
        message: `表面8枚と裏面8枚、合計16枚すべての画像を選択してください。現在は${selectedCount}枚選択されています。`,
      });
      return;
    }
    if (relevantFileErrors.length) {
      setValidationModal({
        title: "画像形式を確認してください",
        message: "画像サイズ、形式、容量に問題がある画像があります。エラー表示のある項目を確認してください。",
      });
      return;
    }
    if (!hasConfirmedSpec) {
      setValidationModal({
        title: "確認と同意が必要です",
        message: "入稿時の注意事項を確認し、「上記の内容を確認し同意します」にチェックを入れてください。",
      });
      return;
    }

    setIsSubmitting(true);
    try {
      const form = new FormData();
      form.append("token", token);
      CARD_UPLOAD_PAIRS.forEach((pair) => {
        form.append(pair.front.id, files[pair.front.id]);
        form.append(pair.back.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>
          {kind === "uploaded" ? (
            <div className="card-upload-message__body">
              <p>このURLでの画像入稿は完了しています。</p>
              <p>送信後、同じ入稿URLを再度使用することはできません。</p>
              <p>送信完了後の画像差し替え、修正依頼、再アップロードは原則としてお受けできません。</p>
              <p>送信済みの画像データをもとに制作を進めさせていただきます。</p>
            </div>
          ) : (
            <p>{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">
          {validationModal && (
            <div className="modal-backdrop" onClick={() => setValidationModal(null)}>
              <div className="modal" role="dialog" aria-modal="true" aria-labelledby="card-upload-validation-title" onClick={(event) => event.stopPropagation()}>
                <button className="modal__close" onClick={() => setValidationModal(null)} type="button" aria-label="閉じる">
                  <Icon name="x" size={18} />
                </button>
                <div className="modal__icon">!</div>
                <h2 id="card-upload-validation-title">{validationModal.title}</h2>
                <p>{validationModal.message}</p>
                <button className="btn btn--primary btn--block" onClick={() => setValidationModal(null)} type="button">確認しました</button>
              </div>
            </div>
          )}
          <form className="card-upload-form" onSubmit={handleSubmit} noValidate>
            <div className="card-upload-progress" aria-live="polite">
              <strong>{selectedCount} / {requiredSlots.length}</strong>
              <span>選択済み</span>
            </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>
            <p className="card-upload-preview-help">切り取り線の内側が実際のカードの内容になります。</p>

            <div className="card-upload-rows">
              {CARD_UPLOAD_PAIRS.map((pair, index) => {
                const hasError = fileErrors[pair.front.id] || fileErrors[pair.back.id];
                return (
                  <div className={"card-upload-row" + (hasError ? " card-upload-row--error" : "")} key={pair.number}>
                    <div className="card-upload-row__num">カード {pair.number}</div>
                    {renderFilePicker(pair.front, "表ファイル読み込み")}
                    {renderFilePicker(pair.back, "裏ファイル読み込み")}
                    <button className="btn card-upload-row__preview" type="button" onClick={() => scrollToPreview(index)}>
                      <Icon name="search" size={16} /> プレビュー
                    </button>
                  </div>
                );
              })}
            </div>

            <section className="card-upload-spec-block" aria-labelledby="card-upload-spec-title">
              <h3 id="card-upload-spec-title">入稿仕様</h3>
              <p>表面8枚と裏面8枚、合計16枚の画像を指定してください。</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-color-note">
                <b>色形式について</b>
                <p>画像データはRGB形式でご入稿ください。sRGB形式を推奨しておりますが、分からない場合は通常のPNG・JPG画像のままで問題ありません。</p>
                <p>CMYK形式の画像は、印刷時に色が暗くなる・くすむ場合があります。</p>
                <p>なお、画面表示と実際の印刷物では、モニター環境・用紙・インクの影響により色味が異なる場合があります。</p>
              </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={isSubmitting}
              aria-busy={isSubmitting}
            >
              {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 });
