"use client";

import { useState, useEffect, useCallback } from "react";
import Link from "next/link";
import type { BlogPost } from "@/content/blog";
import { site } from "@/content/site";
import {
  Check,
  Copy,
  ArrowRight,
  ArrowLeft,
  ShieldCheck,
  CheckCircle2,
  ChevronRight,
  Clock,
  Calendar,
  List,
  Bell,
  BellRing,
  AlertCircle,
  Loader2,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { BlogCard } from "./blog-card";
import { BlogCoverArt } from "./blog-cover-art";
import { ScrollReveal, StaggerContainer, StaggerItem } from "@/components/motion";

function LinkedInIcon({ className }: { className?: string }) {
  return (
    <svg className={className} viewBox="0 0 24 24" fill="currentColor" aria-hidden>
      <path d="M19 3a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14m-.5 15.5v-5.3a3.26 3.26 0 0 0-3.26-3.26c-.85 0-1.84.52-2.28 1.3v-1.11h-2.79v8.37h2.79v-4.93c0-.77.62-1.4 1.39-1.4a1.4 1.4 0 0 1 1.4 1.4v4.93h2.75M6.46 10.9v8.37H9.2V10.9H6.46M7.83 6.45a1.64 1.64 0 1 0 0 3.28 1.64 1.64 0 0 0 0-3.28Z" />
    </svg>
  );
}

function XIcon({ className }: { className?: string }) {
  return (
    <svg className={className} viewBox="0 0 24 24" fill="currentColor" aria-hidden>
      <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" />
    </svg>
  );
}

type NeighborPost = { slug: string; title: string };

interface ArticleReaderProps {
  post: BlogPost;
  relatedPosts: BlogPost[];
  prevPost: NeighborPost | null;
  nextPost: NeighborPost | null;
  enablePushOptIn?: boolean;
}

export function ArticleReader({
  post,
  relatedPosts,
  prevPost,
  nextPost,
  enablePushOptIn = false,
}: ArticleReaderProps) {
  const [activeSection, setActiveSection] = useState<string>(post.tableOfContents[0]?.id || "");
  const [copiedLink, setCopiedLink] = useState(false);
  const [copiedCodeId, setCopiedCodeId] = useState<string | null>(null);
  // Canonical share URL — identical on server and client, so no post-mount state.
  const shareUrl = `${site.url}/blog/${post.slug}`;

  // Scroll-spy for the active TOC section (reading progress is the global bar).
  useEffect(() => {
    const handleScroll = () => {
      const sectionElements = post.tableOfContents
        .map((item) => document.getElementById(item.id))
        .filter(Boolean) as HTMLElement[];
      const scrollPosition = window.scrollY + 200;
      for (let i = sectionElements.length - 1; i >= 0; i--) {
        const el = sectionElements[i];
        if (el && el.offsetTop <= scrollPosition) {
          setActiveSection(el.id);
          break;
        }
      }
    };
    window.addEventListener("scroll", handleScroll, { passive: true });
    handleScroll();
    return () => window.removeEventListener("scroll", handleScroll);
  }, [post.tableOfContents]);

  const copyArticleLink = () => {
    if (typeof window !== "undefined") {
      navigator.clipboard.writeText(window.location.href);
      setCopiedLink(true);
      setTimeout(() => setCopiedLink(false), 2000);
    }
  };

  const copyCode = (code: string, id: string) => {
    navigator.clipboard.writeText(code);
    setCopiedCodeId(id);
    setTimeout(() => setCopiedCodeId(null), 2000);
  };

  return (
    <div className="relative w-full">
      {/* ============================ EDITORIAL HERO ============================ */}
      <header className="w-full pt-6 sm:pt-8">
        {/* Meta line: category + featured */}
        <div className="flex flex-wrap items-center gap-2">
          <span className="rounded-full border border-border bg-secondary/80 px-3.5 py-1 text-[11px] font-bold uppercase tracking-wider text-foreground">
            {post.category}
          </span>
          {post.featured && (
            <span className="flex items-center gap-1.5 rounded-full border border-border/70 bg-secondary/60 px-3 py-1 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground">
              <span className="size-1.5 rounded-full bg-foreground motion-safe:animate-pulse" />
              Featured
            </span>
          )}
        </div>

        {/* Editorial headline */}
        <h1 className="mt-5 max-w-4xl font-display text-[2rem] font-extrabold leading-[1.1] tracking-tight text-foreground text-balance sm:text-[2.75rem] lg:text-[3.25rem]">
          {post.title}
        </h1>

        {/* Lead / intro */}
        <p className="mt-5 max-w-3xl text-lg leading-relaxed text-muted-foreground text-pretty sm:text-xl">
          {post.excerpt}
        </p>

        {/* Byline + share */}
        <div className="mt-7 flex flex-col gap-4 border-y border-border/60 py-4 sm:flex-row sm:items-center sm:justify-between">
          <div className="flex items-center gap-3.5">
            <div
              className={cn(
                "flex size-11 shrink-0 items-center justify-center rounded-full bg-gradient-to-br text-xs font-bold text-background shadow-sm ring-2 ring-background",
                post.author.avatarColor,
              )}
            >
              {post.author.avatarText}
            </div>
            <div className="min-w-0">
              <div className="text-sm font-bold text-foreground">{post.author.name}</div>
              <div className="flex flex-wrap items-center gap-x-2.5 gap-y-0.5 text-xs text-muted-foreground">
                <span>{post.author.role}</span>
              </div>
            </div>
          </div>

          <div className="flex flex-wrap items-center gap-x-4 gap-y-2">
            <span className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground">
              <Calendar className="size-3.5 text-muted-foreground/70" />
              {post.publishedDate}
            </span>
            <span className="flex items-center gap-1.5 text-xs font-medium text-muted-foreground">
              <Clock className="size-3.5 text-muted-foreground/70" />
              {post.readTime}
            </span>

            <span className="hidden h-4 w-px bg-border sm:block" />

            <div className="flex items-center gap-1.5">
              <button
                type="button"
                onClick={copyArticleLink}
                className="flex cursor-pointer items-center gap-1.5 rounded-lg border border-border/80 bg-card px-2.5 py-1.5 text-xs font-semibold text-foreground shadow-2xs transition-colors hover:border-foreground/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                aria-label="Copy link to clipboard"
              >
                {copiedLink ? (
                  <>
                    <Check className="size-3.5" />
                    <span>Copied</span>
                  </>
                ) : (
                  <>
                    <Copy className="size-3.5 text-muted-foreground" />
                    <span>Copy link</span>
                  </>
                )}
              </button>
              <a
                href={shareUrl ? `https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(shareUrl)}` : "https://www.linkedin.com"}
                target="_blank"
                rel="noopener noreferrer"
                className="flex size-8 items-center justify-center rounded-lg border border-border/80 bg-card text-muted-foreground shadow-2xs transition-colors hover:border-foreground/40 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                aria-label="Share on LinkedIn"
              >
                <LinkedInIcon className="size-4" />
              </a>
              <a
                href={`https://twitter.com/intent/tweet?text=${encodeURIComponent(post.title)}${shareUrl ? `&url=${encodeURIComponent(shareUrl)}` : ""}`}
                target="_blank"
                rel="noopener noreferrer"
                className="flex size-8 items-center justify-center rounded-lg border border-border/80 bg-card text-muted-foreground shadow-2xs transition-colors hover:border-foreground/40 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                aria-label="Share on X"
              >
                <XIcon className="size-3.5" />
              </a>
            </div>
          </div>
        </div>

        {/* Featured editorial visual */}
        <ScrollReveal personality="scale" distance={0} className="mt-8">
          {post.featuredImage ? (
            <div className="relative aspect-[21/9] sm:aspect-[2.4/1] w-full overflow-hidden rounded-3xl border border-border/80 shadow-xl bg-neutral-100 dark:bg-neutral-800">
              <img
                src={post.featuredImage}
                alt={post.featuredImageAlt || post.title}
                className="h-full w-full object-cover"
              />
            </div>
          ) : (
            <BlogCoverArt
              illustration={post.coverIllustration}
              variant="hero"
              className="group rounded-3xl border border-border/80 shadow-xl"
            />
          )}
        </ScrollReveal>
      </header>

      {/* ============================ BODY (TOC + article) ============================ */}
      <div className="mt-12 w-full pb-4 lg:grid lg:grid-cols-12 lg:gap-12">
        {/* Sticky TOC (desktop) */}
        <aside className="hidden lg:col-span-4 lg:block xl:col-span-3">
          <div className="sticky top-28 space-y-6">
            <nav className="rounded-2xl border border-border/80 bg-card p-5 shadow-xs" aria-label="Table of contents">
              <span className="text-[11px] font-extrabold uppercase tracking-wider text-muted-foreground">
                On this page
              </span>
              <ul className="mt-4 space-y-1">
                {post.tableOfContents.map((item) => {
                  const isActive = activeSection === item.id;
                  return (
                    <li key={item.id}>
                      <a
                        href={`#${item.id}`}
                        className={cn(
                          "block rounded-lg border-l-2 px-2.5 py-1.5 text-xs font-medium transition-all",
                          isActive
                            ? "border-foreground bg-secondary font-bold text-foreground"
                            : "border-transparent text-muted-foreground hover:bg-secondary/60 hover:text-foreground",
                        )}
                      >
                        {item.title}
                      </a>
                    </li>
                  );
                })}
              </ul>
            </nav>

            <div className="rounded-2xl border border-border bg-secondary p-5">
              <h4 className="text-xs font-bold uppercase tracking-wide text-foreground">
                Need custom voice AI?
              </h4>
              <p className="mt-1.5 text-xs leading-relaxed text-muted-foreground">
                Talk with our solutions team to test live call latency on your own carrier trunk.
              </p>
              <Link
                href="/contact"
                className="mt-4 inline-flex w-full items-center justify-center gap-1.5 rounded-full bg-primary py-2 text-xs font-semibold text-primary-foreground shadow-xs transition-colors hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
              >
                <span>Book a call</span>
                <ArrowRight className="size-3" />
              </Link>
            </div>
          </div>
        </aside>

        {/* Article body */}
        <div className="min-w-0 lg:col-span-8 xl:col-span-9">
          {/* Mobile collapsible TOC */}
          {post.tableOfContents.length > 0 && (
            <details className="group mb-8 rounded-2xl border border-border/80 bg-card p-4 lg:hidden">
              <summary className="flex cursor-pointer list-none items-center justify-between text-sm font-bold text-foreground">
                <span className="flex items-center gap-2">
                  <List className="size-4 text-foreground" />
                  On this page
                </span>
                <ChevronRight className="size-4 text-muted-foreground transition-transform group-open:rotate-90" />
              </summary>
              <ul className="mt-3 space-y-1 border-t border-border/60 pt-3">
                {post.tableOfContents.map((item) => (
                  <li key={item.id}>
                    <a
                      href={`#${item.id}`}
                      className="block rounded-lg px-2 py-1.5 text-xs font-medium text-muted-foreground hover:bg-secondary/60 hover:text-foreground"
                    >
                      {item.title}
                    </a>
                  </li>
                ))}
              </ul>
            </details>
          )}

          <div className="space-y-12">
            {/* Executive brief */}
            <div className="rounded-2xl border border-r border-y border-l-4 border-border/80 border-l-foreground bg-card p-6 shadow-xs sm:p-8">
              <div className="flex items-center gap-2 text-xs font-extrabold uppercase tracking-wider text-muted-foreground">
                <ShieldCheck className="size-4.5 text-foreground" />
                <span>Executive Brief</span>
              </div>
              <p className="mt-3 text-base font-medium leading-relaxed text-foreground/90">
                {post.executiveSummary}
              </p>
            </div>

            {/* Rich Text Body (from CMS Tiptap Editor) takes priority over legacy structured sections */}
            {post.contentHtml && post.contentHtml.replace(/<[^>]*>/g, "").trim().length > 0 ? (
              <div
                className="prose prose-neutral dark:prose-invert max-w-none text-[15px] leading-[1.8] text-muted-foreground sm:text-base [&_h2]:scroll-mt-28 [&_h2]:border-b [&_h2]:border-border/50 [&_h2]:pb-2.5 [&_h2]:font-display [&_h2]:text-2xl [&_h2]:font-bold [&_h2]:tracking-tight [&_h2]:text-foreground [&_h2]:mt-10 [&_h2]:mb-4 [&_h3]:scroll-mt-28 [&_h3]:text-xl [&_h3]:font-bold [&_h3]:text-foreground [&_h3]:mt-8 [&_h3]:mb-3 [&_h4]:text-lg [&_h4]:font-bold [&_h4]:text-foreground [&_h4]:mt-6 [&_h4]:mb-2 [&_p]:my-4 [&_p]:leading-relaxed [&_ul]:my-4 [&_ul]:list-disc [&_ul]:pl-6 [&_ul]:space-y-1.5 [&_ol]:my-4 [&_ol]:list-decimal [&_ol]:pl-6 [&_ol]:space-y-1.5 [&_li]:leading-relaxed [&_blockquote]:border-l-4 [&_blockquote]:border-foreground [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:my-6 [&_blockquote]:text-foreground/90 [&_pre]:p-4 [&_pre]:rounded-2xl [&_pre]:bg-neutral-900 [&_pre]:text-neutral-100 [&_pre]:my-6 [&_pre]:overflow-x-auto [&_code]:rounded [&_code]:bg-neutral-100 dark:[&_code]:bg-neutral-800 [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:text-xs [&_code]:font-mono [&_img]:rounded-2xl [&_img]:border [&_img]:border-border/80 [&_img]:shadow-md [&_img]:my-8 [&_img]:w-full [&_img]:max-h-[550px] [&_img]:object-cover [&_hr]:my-10 [&_hr]:border-border/80 [&_a]:text-blue-600 dark:[&_a]:text-blue-400 [&_a]:underline [&_a]:underline-offset-4 hover:[&_a]:opacity-80"
                dangerouslySetInnerHTML={{ __html: post.contentHtml }}
              />
            ) : (
              post.sections?.map((section) => (
                <ScrollReveal key={section.id} distance={18}>
                <section id={section.id} className="scroll-mt-28 space-y-4">
                  <h2 className="border-b border-border/50 pb-2.5 font-display text-2xl font-bold tracking-tight text-foreground sm:text-[1.75rem]">
                    {section.title}
                  </h2>

                  <p className="whitespace-pre-line text-[15px] leading-[1.75] text-muted-foreground sm:text-base">
                    {section.content}
                  </p>

                  {section.bulletPoints && section.bulletPoints.length > 0 && (
                    <ul className="space-y-3 pt-1">
                      {section.bulletPoints.map((point, i) => (
                        <li key={i} className="flex items-start gap-3 text-[15px] leading-relaxed text-foreground/90 sm:text-base">
                          <CheckCircle2 className="mt-0.5 size-4.5 shrink-0 text-foreground" />
                          <span>{point}</span>
                        </li>
                      ))}
                    </ul>
                  )}

                  {section.table && (
                    <div className="my-6 overflow-x-auto rounded-2xl border border-border/80 shadow-xs">
                      <table className="w-full text-left text-xs sm:text-sm">
                        <thead className="bg-secondary/80 font-bold text-foreground">
                          <tr>
                            {section.table.headers.map((header, i) => (
                              <th key={i} scope="col" className="border-b border-border px-3 py-2.5 sm:px-5 sm:py-3.5">
                                {header}
                              </th>
                            ))}
                          </tr>
                        </thead>
                        <tbody className="divide-y divide-border/60 bg-card">
                          {section.table.rows.map((row, rowIndex) => (
                            <tr key={rowIndex} className="transition-colors hover:bg-secondary/40">
                              {row.map((cell, cellIndex) => (
                                <td key={cellIndex} className="px-3 py-2.5 sm:px-5 sm:py-3.5 font-medium text-muted-foreground">
                                  {cell}
                                </td>
                              ))}
                            </tr>
                          ))}
                        </tbody>
                      </table>
                    </div>
                  )}

                  {section.codeBlock && (
                    <div className="relative overflow-hidden rounded-2xl border border-border bg-secondary p-4 font-mono text-xs text-foreground shadow-md sm:p-5">
                      <div className="mb-3 flex items-center justify-between border-b border-border pb-2.5 text-[11px] text-muted-foreground">
                        <span className="font-bold uppercase tracking-wider text-foreground">
                          {section.codeBlock.language}
                        </span>
                        <button
                          type="button"
                          onClick={() => copyCode(section.codeBlock!.code, section.id)}
                          className="flex cursor-pointer items-center gap-1.5 rounded-md border border-border bg-card px-2.5 py-1 text-muted-foreground transition-colors hover:bg-secondary hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                          aria-label="Copy code"
                        >
                          {copiedCodeId === section.id ? (
                            <span className="flex items-center gap-1 font-semibold text-foreground">
                              <Check className="size-3" /> Copied
                            </span>
                          ) : (
                            <span className="flex items-center gap-1">
                              <Copy className="size-3" /> Copy
                            </span>
                          )}
                        </button>
                      </div>
                      <pre className="overflow-x-auto leading-relaxed [scrollbar-color:var(--border)_transparent] [scrollbar-width:thin]">
                        <code>{section.codeBlock.code}</code>
                      </pre>
                    </div>
                  )}

                  {section.callout && (
                    <div className="flex items-start gap-3 rounded-2xl border border-r border-y border-l-4 border-border border-l-foreground bg-secondary p-5 text-sm text-foreground">
                      <ShieldCheck className="mt-0.5 size-5 shrink-0 text-foreground" />
                      <p className="font-semibold leading-relaxed">{section.callout.text}</p>
                    </div>
                  )}
                </section>
              </ScrollReveal>
            )))}

            {/* Key takeaways */}
            {post.keyTakeaways && post.keyTakeaways.length > 0 && (
              <ScrollReveal>
                <div className="rounded-3xl border border-border bg-gradient-to-br from-card via-card to-secondary/30 p-6 shadow-xs sm:p-8">
                  <h3 className="text-lg font-bold text-foreground">Key strategic takeaways</h3>
                  <div className="mt-4 grid grid-cols-1 gap-3.5 sm:grid-cols-2">
                    {post.keyTakeaways.map((takeaway, i) => (
                      <div
                        key={i}
                        className="flex items-start gap-3 rounded-2xl border border-border/70 bg-background/70 p-3.5 text-xs font-medium text-muted-foreground sm:text-sm"
                      >
                        <CheckCircle2 className="mt-0.5 size-4 shrink-0 text-foreground" />
                        <span>{takeaway}</span>
                      </div>
                    ))}
                  </div>
                </div>
              </ScrollReveal>
            )}

            {/* ============================ NOTIFICATION OPT-IN ============================ */}
            {enablePushOptIn && (
              <NotificationOptIn postSlug={post.slug} postTitle={post.title} />
            )}

            {/* Author bio */}
            <div className="flex flex-col items-center gap-5 rounded-3xl border border-border/80 bg-card p-6 text-center shadow-xs sm:flex-row sm:items-start sm:p-7 sm:text-left">
              <div
                className={cn(
                  "flex size-16 shrink-0 items-center justify-center rounded-full bg-gradient-to-br text-lg font-bold text-background shadow-md ring-2 ring-border/50",
                  post.author.avatarColor,
                )}
              >
                {post.author.avatarText}
              </div>
              <div className="space-y-1.5">
                <span className="text-[11px] font-extrabold uppercase tracking-wider text-muted-foreground">
                  Written by
                </span>
                <h4 className="text-base font-bold text-foreground">{post.author.name}</h4>
                <p className="text-xs font-semibold text-muted-foreground">{post.author.role}</p>
                <p className="pt-1 text-xs leading-relaxed text-muted-foreground">{post.author.bio}</p>
              </div>
            </div>

            {/* Prev / next navigation */}
            {(prevPost || nextPost) && (
              <nav className="grid grid-cols-1 gap-4 sm:grid-cols-2" aria-label="More articles">
                {prevPost ? (
                  <Link
                    href={`/blog/${prevPost.slug}`}
                    className="group flex flex-col gap-1.5 rounded-2xl border border-border/80 bg-card p-5 shadow-xs transition-all hover:border-foreground/30 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                  >
                    <span className="flex items-center gap-1.5 text-[11px] font-bold uppercase tracking-wider text-muted-foreground">
                      <ArrowLeft className="size-3.5 transition-transform group-hover:-translate-x-0.5" />
                      Previous
                    </span>
                    <span className="line-clamp-2 text-sm font-bold text-foreground">{prevPost.title}</span>
                  </Link>
                ) : (
                  <span className="hidden sm:block" />
                )}
                {nextPost && (
                  <Link
                    href={`/blog/${nextPost.slug}`}
                    className="group flex flex-col items-end gap-1.5 rounded-2xl border border-border/80 bg-card p-5 text-right shadow-xs transition-all hover:border-foreground/30 hover:shadow-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
                  >
                    <span className="flex items-center gap-1.5 text-[11px] font-bold uppercase tracking-wider text-muted-foreground">
                      Next
                      <ArrowRight className="size-3.5 transition-transform group-hover:translate-x-0.5" />
                    </span>
                    <span className="line-clamp-2 text-sm font-bold text-foreground">{nextPost.title}</span>
                  </Link>
                )}
              </nav>
            )}
          </div>
        </div>
      </div>

      {/* ============================ RELATED ============================ */}
      {relatedPosts.length > 0 && (
        <section className="border-t border-border/60 pt-14 pb-4">
          <div className="mb-8 flex items-end justify-between">
            <div>
              <span className="text-xs font-extrabold uppercase tracking-wider text-muted-foreground">
                Related knowledge
              </span>
              <h3 className="mt-1 font-display text-2xl font-bold tracking-tight text-foreground">
                Further reading
              </h3>
            </div>
            <Link
              href="/blog"
              className="flex shrink-0 items-center gap-1 text-xs font-bold text-foreground hover:underline focus-visible:outline-none focus-visible:underline"
            >
              <span>View all</span>
              <ChevronRight className="size-3" />
            </Link>
          </div>

          <StaggerContainer className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
            {relatedPosts.map((related) => (
              <StaggerItem key={related.slug} className="h-full">
                <BlogCard post={related} />
              </StaggerItem>
            ))}
          </StaggerContainer>
        </section>
      )}
    </div>
  );
}

// ============================================================
// NotificationOptIn — Web Push opt-in UI (blog article only)
// ============================================================

type NotifState = "idle" | "loading" | "subscribed" | "denied" | "unsupported" | "error";

function NotificationOptIn({
  postSlug,
  postTitle,
}: {
  postSlug: string;
  postTitle: string;
}) {
  const [state, setState] = useState<NotifState>("idle");
  const [mounted, setMounted] = useState(false);
  const [errorMessage, setErrorMessage] = useState<string | null>(null);

  useEffect(() => {
    setMounted(true);

    // Double-check: NEVER run on admin pages
    if (typeof window !== "undefined" && window.location.pathname.startsWith("/admin")) {
      setState("unsupported");
      return;
    }

    // Check browser capability
    const hasNotification = typeof window !== "undefined" && "Notification" in window;
    const hasSW = typeof navigator !== "undefined" && "serviceWorker" in navigator;
    const hasPush = typeof window !== "undefined" && "PushManager" in window;
    const isSecure = typeof window !== "undefined" ? window.isSecureContext : false;

    if (process.env.NODE_ENV === "development") {
      console.info("[Quto AI Web Push Diagnostics]", {
        isSecureContext: isSecure,
        hasNotification,
        hasServiceWorker: hasSW,
        hasPushManager: hasPush,
        permission: hasNotification ? Notification.permission : "unsupported",
      });
    }

    if (!hasNotification || !hasSW || !hasPush) {
      setState("unsupported");
      return;
    }

    // Check existing permission state
    if (Notification.permission === "denied") {
      setState("denied");
    } else if (Notification.permission === "granted") {
      // Check if subscription exists in service worker
      checkExistingSubscription();
    } else {
      setState("idle");
    }
  }, []);

  const checkExistingSubscription = useCallback(async () => {
    try {
      if (!("serviceWorker" in navigator)) return;
      const reg = await navigator.serviceWorker.getRegistration("/sw.js");
      if (!reg) {
        setState("idle");
        return;
      }
      const sub = await reg.pushManager.getSubscription();
      if (sub) {
        setState("subscribed");
      } else {
        setState("idle");
      }
    } catch (e) {
      if (process.env.NODE_ENV === "development") {
        console.warn("[Quto AI Web Push] Could not check existing subscription:", e);
      }
      setState("idle");
    }
  }, []);

  const handleSubscribe = useCallback(async () => {
    setErrorMessage(null);

    // Capability check
    if (
      typeof window === "undefined" ||
      !("Notification" in window) ||
      !("serviceWorker" in navigator) ||
      !("PushManager" in window)
    ) {
      setState("unsupported");
      return;
    }

    try {
      // CRITICAL (Section 5): Browser permission prompt MUST be requested
      // directly from this user click gesture.
      const permission = await Notification.requestPermission();

      if (permission === "denied") {
        setState("denied");
        return;
      }

      if (permission !== "granted") {
        setState("idle");
        return;
      }

      // Permission is granted — proceed to subscribe
      setState("loading");

      // Register or retrieve service worker
      const reg = await navigator.serviceWorker.register("/sw.js", {
        scope: "/",
        updateViaCache: "none",
      });
      await navigator.serviceWorker.ready;

      // Get the VAPID public key from the SERVER (authoritative runtime value).
      // We deliberately do NOT trust the build-time-baked NEXT_PUBLIC value first:
      // if that was ever generated/stored incorrectly (e.g. missing the 0x04
      // uncompressed-point prefix), every subscribe() would fail with
      // "applicationServerKey is not valid" until a rebuild. Reading it at runtime
      // means fixing the server env var fixes the flow without a redeploy.
      let vapidPublicKey: string | undefined;
      try {
        const keyRes = await fetch("/api/push/vapid-public-key", { cache: "no-store" });
        if (keyRes.ok) {
          vapidPublicKey = (await keyRes.json()).publicKey;
        }
      } catch {
        /* fall back to the baked value below */
      }
      if (!vapidPublicKey) {
        vapidPublicKey = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY;
      }

      if (!vapidPublicKey) {
        throw new Error("Push notifications are temporarily unavailable.");
      }

      // Create subscription on browser's PushManager
      const sub = await reg.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(vapidPublicKey) as unknown as BufferSource,
      });

      // Send to server
      const saveRes = await fetch("/api/push/subscribe", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(sub.toJSON()),
      });

      if (!saveRes.ok) {
        throw new Error("Server failed to save subscription.");
      }

      setState("subscribed");
    } catch (err: any) {
      console.error("[Quto AI Web Push] Subscription error:", err);
      if (Notification.permission === "denied") {
        setState("denied");
      } else {
        setErrorMessage(err?.message || "Notifications couldn't be enabled. Please try again.");
        setState("error");
      }
    }
  }, []);

  const handleUnsubscribe = useCallback(async () => {
    setState("loading");
    try {
      const reg = await navigator.serviceWorker.getRegistration("/sw.js");
      if (reg) {
        const sub = await reg.pushManager.getSubscription();
        if (sub) {
          const endpoint = sub.endpoint;
          await sub.unsubscribe();
          await fetch("/api/push/subscribe", {
            method: "DELETE",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({ endpoint }),
          });
        }
      }
      setState("idle");
    } catch (err) {
      console.error("[Quto AI Web Push] Unsubscribe error:", err);
      setState("error");
      setErrorMessage("Failed to unsubscribe. Please try again.");
    }
  }, []);


  return (
    <div className="my-10 overflow-hidden rounded-3xl border border-border/90 bg-gradient-to-br from-card via-card to-secondary/30 p-6 shadow-xs sm:p-8">
      <div className="flex flex-col gap-5 sm:flex-row sm:items-center sm:justify-between">
        <div className="flex items-start gap-4">
          <div
            className={cn(
              "flex size-12 shrink-0 items-center justify-center rounded-2xl border text-lg shadow-xs",
              state === "subscribed"
                ? "border-emerald-500/30 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400"
                : state === "denied"
                ? "border-amber-500/30 bg-amber-500/10 text-amber-600 dark:text-amber-400"
                : "border-border bg-background text-foreground"
            )}
          >
            {state === "subscribed" ? (
              <BellRing className="size-5" />
            ) : state === "denied" ? (
              <AlertCircle className="size-5" />
            ) : (
              <Bell className="size-5" />
            )}
          </div>

          <div className="space-y-1">
            <h3 className="font-display text-base font-bold text-foreground">
              {state === "subscribed"
                ? "Notifications Enabled"
                : state === "denied"
                ? "Notifications Blocked"
                : state === "unsupported"
                ? "Stay Updated with Quto AI"
                : "Stay updated with Quto AI"}
            </h3>

            <p className="text-xs leading-relaxed text-muted-foreground sm:text-sm">
              {state === "subscribed" ? (
                "You're subscribed! You'll receive instant alerts when new AI insights and research are published."
              ) : state === "denied" ? (
                "Notifications are blocked in this browser. You can enable them from your browser site settings."
              ) : state === "unsupported" ? (
                "Browser push notifications are not supported in this browsing mode. Switch to standard mode to enable alerts."
              ) : state === "error" && errorMessage ? (
                errorMessage
              ) : (
                "Get notified about new AI insights, guides, architecture breakdowns, and announcements."
              )}
            </p>
          </div>
        </div>

        <div className="flex shrink-0 items-center gap-2 sm:self-center">
          {state === "subscribed" ? (
            <button
              onClick={handleUnsubscribe}
              className="inline-flex items-center justify-center rounded-full border border-border px-4 py-2 text-xs font-semibold text-muted-foreground transition hover:border-foreground/40 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
            >
              Disable
            </button>
          ) : state === "denied" ? (
            <span className="rounded-full bg-amber-500/10 px-3.5 py-1.5 text-xs font-semibold text-amber-700 dark:text-amber-400">
              Blocked in Settings
            </span>
          ) : state === "unsupported" ? (
            <span className="rounded-full bg-secondary px-3.5 py-1.5 text-xs font-semibold text-muted-foreground">
              Unsupported
            </span>
          ) : state === "loading" ? (
            <button
              disabled
              className="inline-flex items-center justify-center gap-2 rounded-full bg-primary px-5 py-2.5 text-xs font-semibold text-primary-foreground opacity-80"
            >
              <Loader2 className="size-3.5 animate-spin" />
              <span>Connecting…</span>
            </button>
          ) : (
            <button
              onClick={handleSubscribe}
              className="inline-flex items-center justify-center gap-2 rounded-full bg-primary px-5 py-2.5 text-xs font-semibold text-primary-foreground shadow-xs transition hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
            >
              <Bell className="size-3.5" />
              <span>{state === "error" ? "Try Again" : "Enable Notifications"}</span>
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

/** Convert a base64url string to a Uint8Array for applicationServerKey. */
function urlBase64ToUint8Array(base64String: string): Uint8Array {
  const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
  const base64 = (base64String + padding).replace(/-/g, "+").replace(/_/g, "/");
  const raw = atob(base64);
  return Uint8Array.from(raw, (c) => c.charCodeAt(0));
}
