// product-detail-markdown.jsx — 商品詳細の「購入ボタンより下」をMarkdown 1ファイルで表示する
(() => {
  const { Icon, PRODUCTS, Carousel } = window.LCS;

  const MD_LEVEL_CLASS = { 1: "h1", 2: "h2", 3: "h3", 4: "h4", 5: "h5", 6: "h6" };

  const escapeHtml = (value = "") =>
    value
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#39;");

  const renderInlineMarkdown = (value = "") =>
    escapeHtml(value)
      .replace(/&lt;br\s*\/?\s*&gt;/gi, "<br />")
      .replace(/\[([^\]]+)\]\(((?:https?:\/\/|\/|#)[^)]+)\)/g, '<a class="md-link" href="$2">$1</a>')
      .replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
      .replace(/\*([^*]+)\*/g, "<em>$1</em>");

  const splitTableRow = (line = "") =>
    line.trim().replace(/^\|/, "").replace(/\|$/, "").split("|").map((cell) => cell.trim());

  const isTableDivider = (line = "") => {
    if (!/^\s*\|/.test(line)) return false;
    const cells = splitTableRow(line);
    return cells.length > 0 && cells.every((cell) => /^:?-{3,}:?$/.test(cell));
  };

  const parseMarkdownBlocks = (lines) => {
    const blocks = [];
    let paragraph = [];
    let list = null;

    const flushParagraph = () => {
      if (!paragraph.length) return;
      blocks.push({ type: "p", text: paragraph.join("\n") });
      paragraph = [];
    };
    const flushList = () => {
      if (!list) return;
      blocks.push(list);
      list = null;
    };

    for (let i = 0; i < lines.length; i += 1) {
      const raw = lines[i];
      const line = raw.trimEnd();
      const nextLine = lines[i + 1] || "";
      const unordered = line.match(/^\s*[-*]\s+(.+)$/);
      const ordered = line.match(/^\s*\d+\.\s+(.+)$/);

      if (/^\s*\|/.test(line) && isTableDivider(nextLine)) {
        flushParagraph();
        flushList();
        const headers = splitTableRow(line);
        const rows = [];
        i += 2;
        while (i < lines.length && /^\s*\|/.test(lines[i])) {
          rows.push(splitTableRow(lines[i]));
          i += 1;
        }
        i -= 1;
        blocks.push({ type: "table", headers, rows });
        continue;
      }

      if (!line.trim()) {
        flushParagraph();
        flushList();
        continue;
      }

      if (unordered || ordered) {
        flushParagraph();
        const type = unordered ? "ul" : "ol";
        if (!list || list.type !== type) {
          flushList();
          list = { type, items: [] };
        }
        list.items.push((unordered || ordered)[1]);
        continue;
      }

      flushList();
      paragraph.push(line.trim());
    }

    flushParagraph();
    flushList();
    return blocks;
  };

  const parseMarkdownAccordion = (markdown = "") => {
    const root = { level: 0, children: [], blocks: [] };
    const stack = [root];
    let pending = [];

    const flushPending = () => {
      if (!pending.length) return;
      stack[stack.length - 1].blocks.push(...parseMarkdownBlocks(pending));
      pending = [];
    };

    markdown.replace(/\r\n?/g, "\n").split("\n").forEach((line) => {
      const heading = line.match(/^(#{1,6})\s+(.+)$/);
      if (!heading) {
        pending.push(line);
        return;
      }

      flushPending();
      const level = heading[1].length;
      const node = { level, title: heading[2].trim(), blocks: [], children: [] };
      while (stack.length > 1 && stack[stack.length - 1].level >= level) stack.pop();
      stack[stack.length - 1].children.push(node);
      stack.push(node);
    });

    flushPending();
    return root;
  };

  const MarkdownBlock = ({ block }) => {
    if (block.type === "ul" || block.type === "ol") {
      const Tag = block.type;
      return (
        <Tag>
          {block.items.map((item, i) => (
            <li key={i} dangerouslySetInnerHTML={{ __html: renderInlineMarkdown(item) }} />
          ))}
        </Tag>
      );
    }

    if (block.type === "table") {
      return (
        <table className="spec-table md-table">
          <thead>
            <tr>
              {block.headers.map((cell, i) => (
                <th key={i} dangerouslySetInnerHTML={{ __html: renderInlineMarkdown(cell) }} />
              ))}
            </tr>
          </thead>
          <tbody>
            {block.rows.map((row, rowIndex) => (
              <tr key={rowIndex}>
                {block.headers.map((_, cellIndex) => (
                  <td key={cellIndex} dangerouslySetInnerHTML={{ __html: renderInlineMarkdown(row[cellIndex] || "") }} />
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      );
    }

    return <p dangerouslySetInnerHTML={{ __html: renderInlineMarkdown(block.text).replace(/\n/g, "<br />") }} />;
  };

  const MarkdownAccordionNode = ({ node, path, initiallyOpenSections = [] }) => {
    const isOpen = path.every((index) => index === 0) || node.title === "商品仕様" || initiallyOpenSections.includes(node.title);
    const iconSize = Math.max(8, 15 - node.level);

    return (
      <details className={`md-acc md-acc--${MD_LEVEL_CLASS[node.level]}`} open={isOpen} data-md-title={node.title}>
        <summary className="md-acc__sum">
          <span className="md-acc__title">{node.title}</span>
          {node.level < 6 && (
            <span className="md-acc__chev" aria-hidden="true">
              <Icon name="chev" size={iconSize} />
            </span>
          )}
        </summary>
        <div className="md-acc__body">
          {node.blocks.map((block, i) => <MarkdownBlock key={`b-${i}`} block={block} />)}
          {node.children.map((child, i) => (
            <MarkdownAccordionNode key={`${child.level}-${child.title}-${i}`} node={child} path={[...path, i]} initiallyOpenSections={initiallyOpenSections} />
          ))}
        </div>
      </details>
    );
  };

  const MarkdownProductContent = ({ product }) => {
    const [state, setState] = React.useState({ status: "loading", markdown: "" });
    const markdownPath = product.descriptionMarkdown || `/products/${product.id}.markdown`;

    React.useEffect(() => {
      let active = true;
      setState({ status: "loading", markdown: "" });

      fetch(markdownPath)
        .then((res) => {
          if (!res.ok) throw new Error(`Markdown not found: ${markdownPath}`);
          if (res.headers.get("content-type")?.includes("text/html")) {
            throw new Error(`Markdown request returned HTML: ${markdownPath}`);
          }
          return res.text();
        })
        .then((markdown) => {
          if (active) setState({ status: "ready", markdown });
        })
        .catch(() => {
          if (active) setState({ status: "empty", markdown: "" });
        });

      return () => { active = false; };
    }, [markdownPath, product.id]);

    const handleMarkdownClick = (event) => {
      const anchor = event.target.closest?.('a[href^="#"]');
      if (!anchor) return;
      const href = anchor.getAttribute("href") || "";
      const title = decodeURIComponent(href.slice(1));
      const target = Array.from(event.currentTarget.querySelectorAll("[data-md-title]"))
        .find((element) => element.dataset.mdTitle === title);
      if (!target) return;

      event.preventDefault();
      let current = target;
      while (current && current !== event.currentTarget) {
        if (current.tagName === "DETAILS") current.open = true;
        current = current.parentElement;
      }
      const headerOffset = document.querySelector(".header")?.offsetHeight || 0;
      const targetY = target.getBoundingClientRect().top + window.scrollY - headerOffset - 18;
      window.scrollTo({ top: Math.max(0, targetY), behavior: "smooth" });
    };

    if (state.status === "loading") {
      return <div className="mt-32 desc-md desc-md--loading" aria-live="polite">説明を読み込んでいます...</div>;
    }
    if (state.status === "empty" || !state.markdown.trim()) return null;

    const tree = parseMarkdownAccordion(state.markdown);
    return (
      <div className="mt-32 desc-md" onClick={handleMarkdownClick}>
        {tree.blocks.map((block, i) => <MarkdownBlock key={`root-${i}`} block={block} />)}
        {tree.children.map((node, i) => (
          <MarkdownAccordionNode key={`${node.level}-${node.title}-${i}`} node={node} path={[i]} initiallyOpenSections={product.initiallyOpenSections} />
        ))}
      </div>
    );
  };

  const getProductKind = (product) => product.type === "service" ? "service" : "game";

  const getProductPurchaseRows = (product) => {
    if (Array.isArray(product.purchaseRows)) return product.purchaseRows;
    if (Array.isArray(product.priceRows)) return product.priceRows;
    if (getProductKind(product) === "service") {
      return [
        { label: "入稿方法", value: "購入後メールで専用URLを送付" },
        { label: "制作目安", value: "入稿完了後 7〜14 営業日" },
      ];
    }
    return [
      { label: "送料", value: "商品価格に含む" },
      { label: "発送目安", value: "ご注文から 7〜14 営業日" },
    ];
  };

  const MarkdownProductDetailPage = ({ p, go }) => {
    const gallery = p.images;
    const purchaseRows = getProductPurchaseRows(p);
    const isService = getProductKind(p) === "service";
    const [noticeOpen, setNoticeOpen] = React.useState(false);
    const [purchaseAgreed, setPurchaseAgreed] = React.useState(false);
    const descriptionRef = React.useRef(null);

    React.useEffect(() => {
      setPurchaseAgreed(false);
    }, [p.id]);

    React.useEffect(() => {
      if (!noticeOpen) return;
      const onKeyDown = (e) => {
        if (e.key === "Escape") setNoticeOpen(false);
      };
      window.addEventListener("keydown", onKeyDown);
      return () => window.removeEventListener("keydown", onKeyDown);
    }, [noticeOpen]);

    const scrollToRules = () => {
      if (!descriptionRef.current) return;
      const headerOffset = document.querySelector(".header")?.offsetHeight || 0;
      const targetY = descriptionRef.current.getBoundingClientRect().top + window.scrollY - headerOffset - 18;
      window.scrollTo({ top: Math.max(0, targetY), behavior: "smooth" });
    };

    return (
      <main className="page" data-screen-label="02 Product">
        <div className="shell">
          <div className="crumb">
            <a onClick={() => go("home")}>ホーム</a>
            <span className="crumb__sep">/</span>
            <a onClick={() => go("shop")}>商品一覧</a>
            <span className="crumb__sep">/</span>
            <span className="crumb__cur">{p.name}</span>
          </div>

          <section className={"pdp" + (gallery.length === 1 ? " pdp--single-image" : "")}>
            <div className="pdp__gallery">
              <Carousel
                slides={gallery}
                thumbVisible={4}
                ruleLink={{ label: isService ? "サービス説明を見る" : "ルール説明を見る", onClick: scrollToRules }}
              />
            </div>

            <div className="pdp__side">
              <aside className="pdp__info">
                <div className="pdp__brand">LOWSYS CARD SHOP · {p.en.toUpperCase()}</div>
                <h1 className="pdp__title">{p.name}</h1>
                <div className="pdp__badges">
                  {p.badge?.label && (
                    <span className="badge" style={{ background: p.badge.bg, color: p.badge.color, borderColor: "transparent" }}>{p.badge.label}</span>
                  )}
                  {p.tags.map((t, i) => (
                    <span key={i} className="badge" style={{ background: t.bg, color: t.color, borderColor: "transparent" }}>{t.label}</span>
                  ))}
                </div>

                <div className="price-block">
                  <div className="price-block__main">
                    <div className="price-block__amount">¥{p.price.toLocaleString()}<small>JPY</small></div>
                    <div className="price-block__tax">税込 / Tax incl.</div>
                  </div>
                  {purchaseRows.map((row) => (
                    <div className="price-block__row" key={row.label}><span>{row.label}</span><b>{row.value}</b></div>
                  ))}
                </div>

                {noticeOpen && (
                  <div className="modal-backdrop" onClick={() => setNoticeOpen(false)}>
                    <div className="modal modal--purchase-notice" role="dialog" aria-modal="true" aria-labelledby="production-notice-title" onClick={(e) => e.stopPropagation()}>
                      <button className="modal__close" onClick={() => setNoticeOpen(false)} type="button" aria-label="閉じる">
                        <Icon name="x" size={18} />
                      </button>
                      <div className="modal__headline">
                        <div className="modal__icon">!</div>
                        <h2 id="production-notice-title">ご購入前に必ずお読みください</h2>
                      </div>
                      <p>本商品は、一般的な商品とは仕様や取り扱いが異なります。詳しくは各ページをご確認ください（別タブで開きます）</p>
                      <div className="modal__link-row" aria-label="関連ページ">
                        <a className="modal__text-link" href="/about#about-story" target="_blank" rel="noopener noreferrer">生産背景</a>
                        <a className="modal__text-link" href="/about#about-spec" target="_blank" rel="noopener noreferrer">生産カードの仕様</a>
                        <a className="modal__text-link" href="/terms" target="_blank" rel="noopener noreferrer">利用規約</a>
                      </div>

                      <h3 className="modal__section-title">カードの仕様</h3>
                      <p>ハンドメイドのため、色味やサイズ、状態などに個体差や軽微な差異が出る場合があります。</p>
                      <p>不良品かどうかは、カードゲームとして問題なく遊べる範囲かどうかを目安に判断いたします。</p>

                      <h3 className="modal__section-title">生産背景</h3>
                      <p>高齢者や障がいのある方々と共に、一つひとつ手作業で制作しています。</p>
                      <p>「働きたくても機会に恵まれない方の輝ける場所をつくる」という想いから生まれた商品です。</p>
                      <p>そうした背景から、遊ぶうえで支障のない小さな汚れや個体差については、あたたかくご理解いただけますと幸いです。</p>

                      <h3 className="modal__section-title">利用規約・お取引について</h3>
                      <ul>
                        <li>受注生産のため、ご注文完了（決済完了）後のキャンセル・お客様都合による返品はお受けできません。</li>
                        <li>発送はご注文から7〜14営業日が目安です（配送はクリックポスト／送料は商品価格に含む）。</li>
                        <li>破損・印刷不良など、ゲームとして遊ぶうえで支障のある問題があった場合は、商品到着後7日以内にお問い合わせください。再生産・再発送などの対応を検討いたします。</li>
                        {isService && (
                          <li>ご注文完了後、購入時のメールアドレス宛に画像入稿URLをお送りします。画像入稿完了後の差し替え、修正依頼、再アップロードはお受けできません。</li>
                        )}
                      </ul>

                      <label className="modal__confirm-check">
                        <input
                          type="checkbox"
                          checked={purchaseAgreed}
                          onChange={(event) => setPurchaseAgreed(event.target.checked)}
                        />
                        <span>カードの仕様・生産背景・利用規約を確認し、内容に同意のうえ購入します。</span>
                      </label>

                      <button
                        className="btn btn--primary btn--block"
                        onClick={() => { window.location.href = p.stripeUrl; }}
                        type="button"
                        disabled={!purchaseAgreed}
                      >
                        購入する
                      </button>
                    </div>
                  </div>
                )}

                <button className="btn btn--accent btn--xl btn--block" onClick={() => { setPurchaseAgreed(false); setNoticeOpen(true); }} type="button">
                  <Icon name="lock" size={18} /> Stripe で購入する　¥{p.price.toLocaleString()}
                </button>
                <div className="muted center" style={{ fontSize: 12, marginTop: 10 }}>
                  決済は Stripe の安全なチェックアウト画面に遷移します
                </div>
              </aside>
            </div>

            <div className="pdp__description" ref={descriptionRef}>
              <MarkdownProductContent product={p} />
            </div>
          </section>

          <section className="section">
            <div className="section__head">
              <h2 className="section__title">こちらもおすすめ</h2>
            </div>
            <div className="product-grid">
              {PRODUCTS.filter((x) => x.id !== p.id).slice(0, 4).map((x) => (
                <a key={x.id} className="product-card" onClick={() => go("product", x.id)} style={{ cursor: "pointer" }}>
                  <div className="product-card__media">
                    <img src={x.images[0].src} alt={x.images[0].alt || x.name} />
                    {x.badge?.label && (
                      <span className="badge" style={{ position: "absolute", top: 12, left: 12, background: x.badge.bg, color: x.badge.color, borderColor: "transparent" }}>{x.badge.label}</span>
                    )}
                  </div>
                  <div className="product-card__body">
                    <div style={{ fontSize: 11, fontWeight: 700, color: "var(--c-ink-3)", letterSpacing: "0.16em" }}>{x.en.toUpperCase()}</div>
                    <div className="product-card__title">{x.name}</div>
                    <div className="product-card__meta">
                      <div className="product-card__price">¥{x.price.toLocaleString()}<small> 税込</small></div>
                      {x.tags[0] && (
                        <span className="badge" style={{ background: x.tags[0].bg, color: x.tags[0].color, borderColor: "transparent" }}>{x.tags[0].label}</span>
                      )}
                    </div>
                  </div>
                </a>
              ))}
            </div>
          </section>
        </div>
      </main>
    );
  };

  const MarkdownProductPage = ({ pid, go }) => {
    const product = PRODUCTS.find((item) => item.id === pid);
    if (!product) return <window.LCS.HomePage go={go} />;
    return <MarkdownProductDetailPage key={product.id} p={product} go={go} />;
  };

  window.LCS.ProductPage = MarkdownProductPage;
})();
