// Blog.jsx — Blog index and post pages for StoreOn Web Solutions

const ARTICLES = [
  {
    slug: "how-to-add-supplement-facts-panel-shopify",
    title: "How to Add a Supplement Facts Panel to Your Shopify Product Page",
    category: "Compliance & Labeling",
    readingTime: "9 min",
    publishedAt: "2026-06-06",
    excerpt:
      'If you sell dietary supplements on Shopify, you already know the problem: Shopify was not built for food. There is no native "Supplement Facts" field, no per-serving calculation engine, no compliance check.',
  },
  {
    slug: "how-to-display-nutrition-information-shopify",
    title: "How to Display Nutrition Information on Shopify (Step-by-Step)",
    category: "Getting Started",
    readingTime: "8 min",
    publishedAt: "2026-06-06",
    excerpt:
      "Shopify powers over a million stores worldwide, and a growing share sell food, beverages, or dietary supplements. Yet Shopify has no built-in nutrition data fields — nutrition information is entirely a merchant problem to solve.",
  },
  {
    slug: "fda-supplement-labeling-requirements-shopify-stores",
    title: "FDA Supplement Labeling Requirements for Shopify Stores (2026)",
    category: "Compliance & Labeling",
    readingTime: "11 min",
    publishedAt: "2026-06-06",
    excerpt:
      "The FDA applies the same labeling standards to dietary supplements sold online as to those sold on physical retail shelves. Your Shopify product page is a legal label — missing or incorrect information is a violation.",
  },
  {
    slug: "eu-food-labeling-requirements-shopify-stores",
    title: "EU Food Labeling Requirements for Shopify Stores Selling to Europe",
    category: "Compliance & Labeling",
    readingTime: "10 min",
    publishedAt: "2026-06-06",
    excerpt:
      "If you sell supplements or food to customers in France, Germany, Belgium, Spain, or any EU member state, EU food labeling law applies to you — regardless of where your Shopify store is based.",
  },
  {
    slug: "nutriscore-what-it-is-why-shopify-store-should-display-it",
    title:
      "Nutri-Score: What It Is and Why Your Shopify Store Should Display It",
    category: "Nutri-Score",
    readingTime: "8 min",
    publishedAt: "2026-06-06",
    excerpt:
      "Nutri-Score is a five-letter nutritional grading system — A through E — that tells consumers at a glance how a food or supplement ranks nutritionally. An A-grade product is nutritionally favorable.",
  },
  {
    slug: "stop-managing-nutrition-data-in-excel-shopify",
    title:
      "How to Stop Managing Nutrition Data in Excel (For Shopify Merchants)",
    category: "Catalog Management",
    readingTime: "8 min",
    publishedAt: "2026-06-06",
    excerpt:
      "If you run a supplement or food store on Shopify, there is a reasonable chance you have a spreadsheet somewhere — and it is the workflow that produces incorrect Supplement Facts panels and compliance exposure.",
  },
  {
    slug: "add-nutrition-information-shopify-without-developer",
    title: "How to Add Nutrition Information to Shopify Without a Developer",
    category: "Getting Started",
    readingTime: "7 min",
    publishedAt: "2026-06-06",
    excerpt:
      'Shopify does not have a built-in nutrition panel field. The "correct" way requires a developer. Most supplement merchants do not have a developer on call — this guide covers what they can actually do instead.',
  },
  {
    slug: "best-shopify-apps-supplement-nutrition-labeling",
    title:
      "Best Shopify Apps for Supplement and Food Nutrition Labeling (2026)",
    category: "App Reviews",
    readingTime: "9 min",
    publishedAt: "2026-06-06",
    excerpt:
      "If you sell dietary supplements, protein powders, or functional foods on Shopify, you have discovered the gap: no native Supplement Facts field, no nutrition panel widget, no compliance validation.",
  },
  {
    slug: "how-to-bulk-update-nutrition-data-shopify",
    title: "How to Bulk Update Nutrition Data Across All Shopify Products",
    category: "Catalog Management",
    readingTime: "7 min",
    publishedAt: "2026-06-06",
    excerpt:
      "Supplement merchants hit a specific wall the moment they try to scale: Shopify has no native bulk editing tool for nutrition data. A formula change touching 20 products means 20 individual description edits.",
  },
  {
    slug: "supplement-facts-vs-nutrition-facts-shopify",
    title:
      "Supplement Facts vs Nutrition Facts: What Shopify Merchants Need to Know",
    category: "Compliance & Labeling",
    readingTime: "8 min",
    publishedAt: "2026-06-06",
    excerpt:
      'Walk into any supplement store and you will see two different panel headers: some say "Nutrition Facts," others say "Supplement Facts." They look almost identical, but using the wrong one is a federal labeling violation.',
  },
  {
    slug: "nutrition-data-shopify-product-variants",
    title:
      "How to Handle Nutrition Data for Shopify Product Variants (Different Flavors, Sizes)",
    category: "Catalog Management",
    readingTime: "7 min",
    publishedAt: "2026-06-06",
    excerpt:
      "Vanilla protein powder and chocolate protein powder are the same product in Shopify — one record with two variants. But they are not the same product nutritionally, and displaying one panel for both is a compliance problem.",
  },
  {
    slug: "daily-value-percentages-fda-efsa-health-canada",
    title:
      "Daily Value Percentages Explained for Supplement Merchants (FDA vs EFSA vs Health Canada)",
    category: "Compliance & Labeling",
    readingTime: "9 min",
    publishedAt: "2026-06-06",
    excerpt:
      "The Percent Daily Value on a Supplement Facts panel looks like a simple number. But that percentage is derived from a reference value — and that reference value changes depending on which country you are selling in.",
  },
  {
    slug: "sync-nutrition-data-manufacturer-coa-shopify",
    title:
      "How to Sync Nutrition Data From Manufacturer COAs to Your Shopify Store",
    category: "Catalog Management",
    readingTime: "8 min",
    publishedAt: "2026-06-06",
    excerpt:
      "Every supplement product starts with a Certificate of Analysis (COA) from the manufacturer — the source of truth for your Supplement Facts panel. The problem is what happens between that COA and your Shopify product page.",
  },
];

// ——— Format date ———
function formatDate(iso) {
  const d = new Date(iso + "T00:00:00");
  return d.toLocaleDateString("en-US", {
    year: "numeric",
    month: "long",
    day: "numeric",
  });
}

// ——— Post-process HTML: transform CTA bold links into styled horizontal blocks ———
function processBlogHTML(html) {
  const ctaPattern =
    /<p>\s*<strong>\s*<a\s+href="https:\/\/apps\.shopify\.com\/nutriscore"[^>]*>([^<]*(?:Install NutriScore|Install\s+NutriScore)[^<]*)<\/a>\s*<\/strong>\s*<\/p>/gi;
  return html.replace(ctaPattern, () => {
    return `<div class="article-cta-block">
      <div class="article-cta-block-text">
        <span class="article-cta-block-label">✦ Available now</span>
        <span class="article-cta-block-title">NutriScore for Shopify</span>
      </div>
      <a class="article-cta-block-link" href="https://apps.shopify.com/nutriscore" target="_blank" rel="noopener noreferrer">
        Install on Shopify <span style="font-size:14px">→</span>
      </a>
    </div>`;
  });
}

// ——— Add IDs to headings and return list ———
function processHeadings(el) {
  const headings = [];
  const seen = {};
  el.querySelectorAll("h2, h3").forEach((h) => {
    if (!h.id) {
      let id = h.textContent
        .toLowerCase()
        .replace(/[^a-z0-9\s-]/g, "")
        .trim()
        .replace(/\s+/g, "-")
        .slice(0, 60);
      if (seen[id]) {
        id = id + "-" + ++seen[id];
      } else {
        seen[id] = 1;
      }
      h.id = id;
    }
    headings.push({
      id: h.id,
      text: h.textContent,
      level: parseInt(h.tagName[1]),
    });
  });
  return headings;
}

// ——— ArticleCard ———
const ArticleCard = ({ article, setPage }) => (
  <a
    href={"#blog/" + article.slug}
    className="article-card"
    onClick={(e) => {
      e.preventDefault();
      setPage("blog/" + article.slug);
    }}
  >
    <span className="article-card-category">{article.category}</span>
    <h2 className="article-card-title">{article.title}</h2>
    <p className="article-card-excerpt">{article.excerpt}</p>
    <div className="article-card-footer">
      <span className="article-card-date">
        {formatDate(article.publishedAt)}
      </span>
      <span className="article-card-reading">{article.readingTime}</span>
    </div>
  </a>
);

// ——— Blog Footer CTA ———
const BlogFooterCTA = ({ setPage }) => (
  <section className="blog-footer-cta">
    <div className="container" style={{ position: "relative" }}>
      <div className="blog-footer-cta-moon">
        <Moon size={80} phase={0.5} />
      </div>
      <span className="eyebrow blog-footer-cta-eyebrow">
        ✦ From the observatory
      </span>
      <h2 className="blog-footer-cta-title">
        Ready to bring your
        <br />
        <em>supplement store into compliance?</em>
      </h2>
      <p className="blog-footer-cta-desc">
        NutriScore handles Supplement Facts panels, Nutri-Score grading, and
        structured data — so you can focus on your products.
      </p>
      <div className="blog-footer-cta-actions">
        <a
          className="btn"
          href="https://apps.shopify.com/nutriscore"
          target="_blank"
          rel="noopener noreferrer"
        >
          Install NutriScore <span style={{ fontSize: 14 }}>→</span>
        </a>
        {setPage && (
          <a
            className="btn ghost"
            href="#blog"
            onClick={(e) => {
              e.preventDefault();
              setPage("blog");
              window.scrollTo(0, 0);
            }}
          >
            Read more articles
          </a>
        )}
      </div>
    </div>
  </section>
);

// ——— Blog Index ———
const BlogIndex = ({ setPage }) => {
  const [activeCategory, setActiveCategory] = React.useState("All");

  React.useEffect(() => {
    window.scrollTo(0, 0);
    setTimeout(() => {
      if (typeof initReveal === "function") initReveal();
    }, 120);
  }, []);

  const categories = React.useMemo(() => {
    const cats = [...new Set(ARTICLES.map((a) => a.category))];
    return ["All", ...cats];
  }, []);

  const filteredArticles =
    activeCategory === "All"
      ? ARTICLES
      : ARTICLES.filter((a) => a.category === activeCategory);

  return (
    <div className="blog-article-root">
      {/* ——— Blog Hero ——— */}
      <section className="blog-hero">
        <div className="container">
          <div className="blog-hero-inner reveal">
            <div className="blog-hero-meta">
              <span className="section-idx">§ 04 / Writing</span>
              <span className="eyebrow">From the observatory</span>
            </div>
            <div>
              <h1 className="blog-hero-title">
                Guides, compliance notes, and deep dives for Shopify food &amp;
                supplement merchants.
              </h1>
              <p className="blog-hero-desc" style={{ marginTop: 16 }}>
                {ARTICLES.length} articles — updated as the regulatory landscape
                shifts.
              </p>
            </div>
          </div>

          {/* Category filter bar */}
          <div className="blog-filter-bar reveal">
            <span className="blog-filter-label">Filter:</span>
            {categories.map((cat) => (
              <button
                key={cat}
                className={
                  "blog-filter-btn" + (activeCategory === cat ? " active" : "")
                }
                onClick={() => setActiveCategory(cat)}
              >
                {cat}
              </button>
            ))}
          </div>
        </div>
      </section>

      {/* ——— Constellation Divider ——— */}
      <div className="constellation-divider">
        <svg viewBox="0 0 1200 80" preserveAspectRatio="none">
          <line
            x1="0"
            y1="40"
            x2="1200"
            y2="40"
            stroke="var(--rule-soft)"
            strokeWidth="0.5"
          />
          <circle cx="200" cy="40" r="2" fill="var(--accent)" opacity="0.5" />
          <circle cx="600" cy="40" r="1.5" fill="var(--rule)" opacity="0.8" />
          <circle cx="1000" cy="40" r="2" fill="var(--accent)" opacity="0.5" />
          <text
            x="600"
            y="44"
            textAnchor="middle"
            fontFamily="var(--serif)"
            fontSize="14"
            fill="var(--accent)"
            opacity="0.7"
          >
            ✦
          </text>
        </svg>
      </div>

      {/* ——— Article Grid ——— */}
      <section className="blog-section">
        <div className="container">
          <div className="article-card-grid reveal">
            {filteredArticles.map((article) => (
              <ArticleCard
                key={article.slug}
                article={article}
                setPage={setPage}
              />
            ))}
          </div>

          {/* Footer count bar */}
          <div className="blog-grid-footer reveal">
            <span>
              — {filteredArticles.length} article
              {filteredArticles.length !== 1 ? "s" : ""}{" "}
              {activeCategory !== "All"
                ? "in " + activeCategory
                : "in the archive"}
            </span>
            <span>✦ Blog</span>
          </div>
        </div>
      </section>

      <BlogFooterCTA setPage={setPage} />
    </div>
  );
};

// ——— Blog Post ———
const BlogPost = ({ slug, setPage }) => {
  const [state, setState] = React.useState({
    content: "",
    loading: true,
    error: false,
  });
  const [headings, setHeadings] = React.useState([]);
  const [activeHeading, setActiveHeading] = React.useState("");
  const bodyRef = React.useRef(null);
  const article = ARTICLES.find((a) => a.slug === slug);

  React.useEffect(() => {
    window.scrollTo(0, 0);
    setState({ content: "", loading: true, error: false });
    setHeadings([]);
    setActiveHeading("");

    fetch("/content/blog/" + slug + ".md")
      .then((r) => {
        if (!r.ok) throw new Error("Not found");
        return r.text();
      })
      .then((text) => {
        const stripped = text.replace(/^---[\s\S]*?---\n/, "");
        const raw = marked.parse(stripped, { breaks: true });
        const processed = processBlogHTML(raw);
        setState({ content: processed, loading: false, error: false });
        setTimeout(() => {
          if (typeof initReveal === "function") initReveal();
        }, 120);
      })
      .catch(() => {
        setState({ content: "", loading: false, error: true });
      });
  }, [slug]);

  // Extract headings and wire up IntersectionObserver after content renders
  React.useEffect(() => {
    if (state.loading || state.error || !bodyRef.current) return;

    const extracted = processHeadings(bodyRef.current);
    setHeadings(extracted);
    if (!extracted.length) return;

    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) setActiveHeading(entry.target.id);
        });
      },
      { rootMargin: "-10% 0px -75% 0px", threshold: 0 },
    );

    extracted.forEach(({ id }) => {
      const el = document.getElementById(id);
      if (el) observer.observe(el);
    });

    return () => observer.disconnect();
  }, [state.content]);

  const handleBack = (e) => {
    e.preventDefault();
    setPage("blog");
  };

  return (
    <div className="blog-article-root">
      {/* Back bar */}
      <div className="blog-back-bar">
        <div className="container">
          <a href="#blog" className="blog-back-link" onClick={handleBack}>
            ← All articles
          </a>
        </div>
      </div>

      {/* Breadcrumb */}
      <div className="container">
        <nav className="blog-breadcrumb reveal">
          <a
            href="#"
            onClick={(e) => {
              e.preventDefault();
              setPage("home");
            }}
          >
            Home
          </a>
          <span className="blog-breadcrumb-sep">◦</span>
          <a href="#blog" onClick={handleBack}>
            Blog
          </a>
          {article && (
            <React.Fragment>
              <span className="blog-breadcrumb-sep">◦</span>
              <span className="blog-breadcrumb-current">
                {article.category}
              </span>
            </React.Fragment>
          )}
        </nav>
      </div>

      {/* Article Header */}
      <header className="article-header">
        <div className="container">
          {article && (
            <span className="article-header-category">{article.category}</span>
          )}
          <h1 className="article-header-title reveal">
            {article ? article.title : slug}
          </h1>
          {article && (
            <div className="article-header-meta reveal">
              <div className="article-header-meta-item">
                <span className="meta-glyph">☾</span>
                {formatDate(article.publishedAt)}
              </div>
              <div className="article-header-meta-item">
                <span className="meta-glyph">◐</span>
                {article.readingTime} read
              </div>
            </div>
          )}
        </div>
      </header>

      {/* Decorative rule between header and body */}
      <div className="container">
        <div className="article-section-rule">
          <span className="article-section-rule-glyph">✦</span>
        </div>
      </div>

      {/* Article Layout: TOC sidebar + body */}
      <div
        className="container"
        style={{ paddingBottom: "clamp(60px, 8vw, 120px)" }}
      >
        <div className="article-layout">
          {/* TOC Sidebar — only when ≥3 headings and content is ready */}
          {!state.loading && !state.error && headings.length >= 3 && (
            <aside className="article-toc">
              <span className="article-toc-label">In this article</span>
              <ul className="article-toc-list">
                {headings.map((h) => (
                  <li
                    key={h.id}
                    className={"article-toc-item level-" + h.level}
                  >
                    <a
                      href={"#" + h.id}
                      className={
                        "article-toc-link" +
                        (activeHeading === h.id ? " active" : "")
                      }
                      onClick={(e) => {
                        e.preventDefault();
                        document.getElementById(h.id)?.scrollIntoView({
                          behavior: "smooth",
                          block: "start",
                        });
                      }}
                    >
                      {h.text}
                    </a>
                  </li>
                ))}
              </ul>
            </aside>
          )}

          {/* Article body */}
          {state.loading && (
            <div className="blog-loading">
              <div className="blog-loading-bar" />
              <div className="blog-loading-bar" style={{ width: "80%" }} />
              <div className="blog-loading-bar" style={{ width: "92%" }} />
              <div
                className="blog-loading-bar"
                style={{ width: "70%", marginTop: 32 }}
              />
              <div className="blog-loading-bar" style={{ width: "88%" }} />
            </div>
          )}
          {state.error && (
            <div className="blog-error">
              <p
                style={{
                  fontFamily: "var(--serif)",
                  fontStyle: "italic",
                  fontSize: 22,
                  color: "var(--ink-soft)",
                  marginBottom: 24,
                }}
              >
                This article could not be loaded.
              </p>
              <button className="btn ghost" onClick={() => setPage("blog")}>
                ← Back to Blog
              </button>
            </div>
          )}
          {!state.loading && !state.error && (
            <article
              className="article-body"
              ref={bodyRef}
              dangerouslySetInnerHTML={{ __html: state.content }}
            />
          )}
        </div>
      </div>

      <BlogFooterCTA setPage={setPage} />
    </div>
  );
};

Object.assign(window, { BlogIndex, BlogPost, ARTICLES });
