// app.jsx — RefurbPing main app

const { useState, useMemo, useEffect, useLayoutEffect, useRef } = React;

// ─── Data ─────────────────────────────────────────────────────────────────────

const PRODUCTS = {
  "mac-mini": {
    id: "mac-mini",
    name: "Mac mini",
    tagline: "Small. Mighty. And often on the refurb shelf.",
    basePrice: 519,
    storeName: "Apple",
    art: () => <MacMiniArt />,
    specs: {
      cpu: ["M4", "M4 Pro"],
      ram: [16, 24, 32, 48, 64],
      storage: [256, 512, 1024, 2048, 4096, 8192],
    },
  },
  "mac-studio": {
    id: "mac-studio",
    name: "Mac Studio",
    tagline: "Outrageously powerful — when it shows up refurbished.",
    basePrice: 1699,
    storeName: "Apple",
    art: () => <MacStudioArt />,
    specs: {
      cpu: ["M2 Max", "M2 Ultra", "M4 Max", "M3 Ultra"],
      ram: [32, 36, 48, 64, 96, 128, 192, 256],
      storage: [512, 1024, 2048, 4096, 8192, 16384],
    },
  },
  "steam-deck": {
    id: "steam-deck",
    name: "Steam Deck",
    tagline: "Valve certified refurbished handhelds, checked every half hour.",
    basePrice: 279,
    storeName: "Steam",
    art: () => <SteamDeckArt />,
    filterLabels: { cpu: "Display", cpuAny: "any display" },
    specs: {
      cpu: ["LCD", "OLED"],
      ram: [],
      storage: [64, 256, 512, 1024],
    },
  },
};

const COMING_SOON = [
  { id: "macbook-pro",  name: "MacBook Pro",  art: () => <MacBookProArt /> },
  { id: "ipad-pro",     name: "iPad Pro",     art: () => <IPadProArt /> },
  { id: "more-devices", name: "More devices", art: () => <MoreDevicesArt />, blurb: "Sony, Microsoft, Nintendo, Framework, and more on the way." },
];

const REGIONS = [
  { id: "us", label: "United States",  flag: "🇺🇸", active: true },
  { id: "ca", label: "Canada",         flag: "🇨🇦", active: true },
  { id: "uk", label: "United Kingdom", flag: "🇬🇧", active: true },
  { id: "de", label: "Germany",        flag: "🇩🇪", active: true },
  { id: "au", label: "Australia",      flag: "🇦🇺", active: true },
  { id: "nz", label: "New Zealand",    flag: "🇳🇿", active: true },
  { id: "jp", label: "Japan",          flag: "🇯🇵", active: true },
  { id: "sg", label: "Singapore",      flag: "🇸🇬", active: true },
  { id: "hk", label: "Hong Kong",      flag: "🇭🇰", active: true },
  { id: "tw", label: "Taiwan",         flag: "🇹🇼", active: true },
  { id: "kr", label: "South Korea",    flag: "🇰🇷", active: true },
  { id: "fr", label: "France",         flag: "🇫🇷", active: true },
  { id: "es", label: "Spain",          flag: "🇪🇸", active: true },
  { id: "it", label: "Italy",          flag: "🇮🇹", active: true },
  { id: "nl", label: "Netherlands",    flag: "🇳🇱", active: true },
  { id: "ie", label: "Ireland",        flag: "🇮🇪", active: true },
  { id: "at", label: "Austria",        flag: "🇦🇹", active: true },
  { id: "ch", label: "Switzerland",    flag: "🇨🇭", active: true },
  { id: "be", label: "Belgium",        flag: "🇧🇪", active: true },
  { id: "pl", label: "Poland",         flag: "🇵🇱", active: true },
  { id: "se", label: "Sweden",         flag: "🇸🇪", active: true },
];

const APPLE_PRODUCT_IDS = new Set(["mac-mini", "mac-studio"]);
const KOFI_TIP_URL = "https://ko-fi.com/refurbping";
const regionById = (id) => REGIONS.find(r => r.id === id) || REGIONS[0];

// ─── Helpers ──────────────────────────────────────────────────────────────────

const formatStorage = (gb) => gb >= 1024 ? `${gb/1024}TB` : `${gb}GB`;
const formatRam = (gb) => `${gb}GB`;
const emptyRange = () => ({ min: null, max: null });
const rangeFromFilters = (filters, key) => ({
  min: filters?.[key] ?? null,
  max: filters?.[`${key}Max`] ?? null,
});
const isAnyRange = (range) => !range || (range.min == null && range.max == null);
const formatRange = (range, format) => {
  if (isAnyRange(range)) return "Any";
  if (range.min === range.max) return format(range.min);
  if (range.min == null) return `≤ ${format(range.max)}`;
  if (range.max == null) return `≥ ${format(range.min)}`;
  return `${format(range.min)} – ${format(range.max)}`;
};
const withFilterRange = (filters, key, range) => ({
  ...filters,
  [key]: range?.min ?? null,
  [`${key}Max`]: range?.max ?? null,
});
const selectedCpuValues = (value) => Array.isArray(value) ? value : (value ? [value] : []);
const formatCpuFilter = (value, anyLabel) => {
  const selected = selectedCpuValues(value);
  return selected.length ? selected.join(" / ") : anyLabel;
};

const summarize = (productId, f) => {
  const p = PRODUCTS[productId];
  const parts = [<span key="p"><strong>{p.name}</strong></span>];
  if (p.specs.cpu.length) {
    const selected = selectedCpuValues(f.cpu);
    parts.push(<span key="c">, {selected.length ? <strong>{selected.join(" / ")}</strong> : (p.filterLabels?.cpuAny || "any chip")}</span>);
  }
  if (p.specs.ram.length) {
    const ram = rangeFromFilters(f, "ram");
    parts.push(<span key="r">, {!isAnyRange(ram) ? <strong>{formatRange(ram, formatRam)} RAM</strong> : "any RAM"}</span>);
  }
  if (p.specs.storage.length) {
    const storage = rangeFromFilters(f, "storage");
    parts.push(<span key="s">, {!isAnyRange(storage) ? <strong>{formatRange(storage, formatStorage)} storage</strong> : "any storage"}</span>);
  }
  return parts;
};

const validEmail = (e) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e);

async function api(path, options = {}) {
  const res = await fetch(path, {
    credentials: "same-origin",
    headers: { "Content-Type": "application/json", ...(options.headers || {}) },
    ...options,
  });
  const data = await res.json().catch(() => ({}));
  if (!res.ok) {
    throw new Error(data.error || "request_failed");
  }
  return data;
}

const sessionAuth = (session) => ({
  signedIn: !!session.signedIn,
  email: session.user?.email || null,
  userId: session.user?.id || null,
});

// ─── Components ───────────────────────────────────────────────────────────────

function Nav({ alertCount, auth, authLoading, onSignIn, onSignOut }) {
  const [menuOpen, setMenuOpen] = useState(false);
  const ref = useRef(null);
  useEffect(() => {
    if (!menuOpen) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setMenuOpen(false); };
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, [menuOpen]);
  const initial = (auth.email || "?").slice(0, 1).toUpperCase();

  return (
    <header className="nav">
      <div className="nav-inner">
        <a className="brand" href="/" aria-label="RefurbPing home">
          <Logo size={26} gap={8} />
        </a>
        <nav className="nav-links" aria-label="Primary">
          <a href="#products">Products</a>
          <a href="#alerts" style={{display:"inline-flex",alignItems:"center",gap:6}}>
            {auth.signedIn ? "Your alerts" : "Alerts"}
            {auth.signedIn && alertCount > 0 && (
              <span style={{
                fontSize:11, fontWeight:600, color:"var(--ink)",
                background:"var(--bg-soft)", border:"1px solid var(--hairline)",
                padding:"1px 7px", borderRadius:999, lineHeight:1.4
              }}>{alertCount}</span>
            )}
          </a>
          <a href="#how">How it works</a>
          <a href="/accessories.html">Accessories</a>
        </nav>
        {authLoading ? (
          <div className="nav-cta" aria-hidden="true" style={{visibility:"hidden"}}>Sign in</div>
        ) : auth.signedIn ? (
          <div ref={ref} style={{position:"relative"}}>
            <button className="user-pill" type="button" onClick={() => setMenuOpen(o => !o)}>
              <span className="avatar">{initial}</span>
              <span>{auth.email}</span>
            </button>
            {menuOpen && (
              <div className="user-menu" role="menu">
                <div className="ident">
                  Signed in as
                  <b>{auth.email}</b>
                </div>
                <button className="item" type="button" onClick={() => { setMenuOpen(false); document.getElementById("alerts")?.scrollIntoView({behavior:"smooth", block:"start"}); }}>Your alerts</button>
                <button className="item" type="button">Email preferences</button>
                <button className="item" type="button">Billing</button>
                <div className="sep"></div>
                <button className="item danger" type="button" onClick={() => { setMenuOpen(false); onSignOut(); }}>Sign out</button>
              </div>
            )}
          </div>
        ) : (
          <button className="nav-cta" type="button" onClick={onSignIn}>Sign in</button>
        )}
      </div>
    </header>
  );
}

function Hero({ watching }) {
  return (
    <section className="hero">
      <div className="wrap">
        <div className="eyebrow">Refurbished inventory · real-time monitor</div>
        <h1 className="h-display">Real-time refurb Mac alerts,<br/>without delay.</h1>
        <div className="meta">
          <span className="live-dot" aria-hidden="true"></span>
          <span>Watching {watching.toLocaleString()} configurations · pushed as soon as matches appear</span>
        </div>
      </div>
    </section>
  );
}

function RegionDropdown({ region, setRegion }) {
  const [open, setOpen] = useState(false);
  const ref = useRef(null);
  const current = REGIONS.find(r => r.id === region) || REGIONS[0];

  useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    const onKey = (e) => { if (e.key === "Escape") setOpen(false); };
    document.addEventListener("mousedown", onDoc);
    document.addEventListener("keydown", onKey);
    return () => {
      document.removeEventListener("mousedown", onDoc);
      document.removeEventListener("keydown", onKey);
    };
  }, [open]);

  return (
    <div className="region-wrap" ref={ref}>
      <button
        type="button" className="region-trigger"
        aria-haspopup="listbox" aria-expanded={open}
        onClick={() => setOpen(o => !o)}
      >
        <span className="flag" aria-hidden="true">{current.flag}</span>
        <span>{current.label}</span>
        <svg className={`chev ${open ? "o" : ""}`} width="10" height="10" viewBox="0 0 10 10" aria-hidden="true">
          <path d="M1.5 3.5 L5 7 L8.5 3.5" stroke="currentColor" strokeWidth="1.5" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
      </button>
      {open && (
        <div className="region-menu" role="listbox" aria-label="Region">
          {REGIONS.map(r => (
            <button
              key={r.id} type="button" role="option"
              className="region-item"
              aria-selected={region === r.id}
              aria-disabled={!r.active}
              onClick={() => { if (r.active) { setRegion(r.id); setOpen(false); } }}
            >
              <span className="flag" aria-hidden="true">{r.flag}</span>
              <span className="region-name">{r.label}</span>
              {r.active
                ? (region === r.id && (
                    <svg width="14" height="14" viewBox="0 0 14 14" aria-hidden="true">
                      <path d="M2 7.5 L5.5 11 L12 3.5" stroke="currentColor" strokeWidth="1.8" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
                    </svg>))
                : <span className="region-soon">Soon</span>}
            </button>
          ))}
          <div className="region-foot">Want another region? <a href="https://tally.so/r/xXvBKy" target="_blank" rel="noopener noreferrer">Tell us</a>.</div>
        </div>
      )}
    </div>
  );
}

function ProductCard({ product, onPick, selected, dim, comingSoon }) {
  return (
    <div
      className={`card ${dim ? "dim" : "interactive"} ${selected ? "selected" : ""}`}
      onClick={() => !dim && onPick && onPick(product.id)}
      role={dim ? undefined : "button"}
      tabIndex={dim ? -1 : 0}
    >
      {comingSoon && <span className="badge">Coming soon</span>}
      <div className="product-art">{product.art()}</div>
      <div className="product-name">{product.name}</div>
      <div className="product-meta">
        {comingSoon
          ? (product.blurb || "We'll let you know when monitoring is on.")
          : `Refurb listings start around $${product.basePrice.toLocaleString()}`}
      </div>
      {!comingSoon && (
        <div className="card-cta">
          Set up alert <span className="arrow">→</span>
        </div>
      )}
    </div>
  );
}

function PillGroup({ label, hint, options, value, onChange, format, prefix }) {
  return (
    <div className="filter-group">
      <div className="label-row">
        <h4>{label}</h4>
        {hint && <span className="hint">{hint}</span>}
      </div>
      <div className="pills" role="radiogroup" aria-label={label}>
        <button
          type="button" className="pill any"
          aria-pressed={value === null ? "true" : "false"}
          onClick={() => onChange(null)}
        >
          Any
        </button>
        {options.map(opt => (
          <button
            key={opt} type="button" className="pill"
            aria-pressed={value === opt ? "true" : "false"}
            onClick={() => onChange(opt)}
          >
            {prefix && <span className="ge">{prefix}</span>}{format ? format(opt) : opt}
          </button>
        ))}
      </div>
    </div>
  );
}

function MultiPillGroup({ label, hint, options, value, onChange, format }) {
  const selected = selectedCpuValues(value);
  const toggle = (option) => {
    if (selected.includes(option)) {
      onChange(selected.filter((item) => item !== option));
      return;
    }
    onChange([...selected, option]);
  };

  return (
    <div className="filter-group">
      <div className="label-row">
        <h4>{label}</h4>
        {hint && <span className="hint">{selected.length ? `${selected.length} selected` : hint}</span>}
      </div>
      <div className="pills" role="group" aria-label={label}>
        <button
          type="button" className="pill any"
          aria-pressed={selected.length === 0 ? "true" : "false"}
          onClick={() => onChange([])}
        >
          Any
        </button>
        {options.map(option => (
          <button
            key={option} type="button" className="pill"
            aria-pressed={selected.includes(option) ? "true" : "false"}
            onClick={() => toggle(option)}
          >
            {format ? format(option) : option}
          </button>
        ))}
      </div>
    </div>
  );
}

function RangePillGroup({ label, options, value, onChange, format }) {
  const range = value || emptyRange();
  const minIndex = range.min == null ? -1 : options.indexOf(range.min);
  const maxIndex = range.max == null ? -1 : options.indexOf(range.max);
  const hasRange = minIndex !== -1 && maxIndex !== -1;
  const lowIndex = Math.min(minIndex, maxIndex);
  const highIndex = Math.max(minIndex, maxIndex);
  const wrapRef = useRef(null);

  const handleClick = (option, index) => {
    if (!hasRange) {
      onChange({ min: option, max: option });
      return;
    }
    if (minIndex === maxIndex) {
      if (index === minIndex) {
        onChange(emptyRange());
        return;
      }
      const low = Math.min(index, minIndex);
      const high = Math.max(index, minIndex);
      onChange({ min: options[low], max: options[high] });
      return;
    }
    onChange({ min: option, max: option });
  };

  const inRange = (index) => hasRange && index >= lowIndex && index <= highIndex;
  const pillClass = (index) => {
    if (!inRange(index)) return "pill";
    let className = "pill sel";
    if (index === lowIndex) className += " sel-l";
    if (index === highIndex) className += " sel-r";
    if (index > lowIndex) className += " join";
    return className;
  };

  useLayoutEffect(() => {
    const root = wrapRef.current;
    if (!root) return;
    const recompute = () => {
      const selected = [...root.querySelectorAll(".pill.sel")];
      selected.forEach((el) => el.classList.remove("row-start", "row-end"));
      for (let index = 1; index < selected.length; index++) {
        if (selected[index].offsetTop !== selected[index - 1].offsetTop) {
          selected[index].classList.add("row-start");
          selected[index - 1].classList.add("row-end");
        }
      }
    };
    recompute();
    window.addEventListener("resize", recompute);
    return () => window.removeEventListener("resize", recompute);
  });

  return (
    <div className="filter-group">
      <div className="label-row">
        <h4>{label}</h4>
        <span className="hint">{isAnyRange(range) ? "Any range" : formatRange(range, format)}</span>
      </div>
      <div className="pills range" role="group" aria-label={label} ref={wrapRef}>
        <button
          type="button" className="pill any"
          aria-pressed={isAnyRange(range) ? "true" : "false"}
          onClick={() => onChange(emptyRange())}
        >
          Any
        </button>
        {options.map((option, index) => (
          <button
            key={option} type="button"
            className={pillClass(index)}
            aria-pressed={inRange(index) ? "true" : "false"}
            onClick={() => handleClick(option, index)}
          >
            {format ? format(option) : option}
          </button>
        ))}
      </div>
    </div>
  );
}

function Configurator({ productId, region, onClose, onCreate, prefilledEmail, lockEmail }) {
  const product = PRODUCTS[productId];
  const selectedRegion = regionById(region);
  const isAppleProduct = APPLE_PRODUCT_IDS.has(productId);
  const [filters, setFilters] = useState({ cpu: [], ram: null, ramMax: null, storage: null, storageMax: null });
  const [email, setEmail] = useState(prefilledEmail || "");
  const [touched, setTouched] = useState(false);
  const [submitting, setSubmitting] = useState(false);
  const [error, setError] = useState(null);

  const emailOk = lockEmail ? validEmail(email) : true;
  const stats = [
    `From $${product.basePrice}`,
    product.specs.cpu.length ? `${product.specs.cpu.length} ${product.filterLabels?.cpu || "chip"}${product.specs.cpu.length === 1 ? "" : "s"} watched` : null,
    product.specs.ram.length ? `${product.specs.ram.length} RAM tiers watched` : null,
    product.specs.storage.length ? `${product.specs.storage.length} storage tiers watched` : null,
  ].filter(Boolean);

  const submit = async () => {
    setTouched(true);
    if (lockEmail && !emailOk) return;
    setSubmitting(true);
    setError(null);
    try {
      await onCreate({
        productId,
        email: lockEmail ? email : null,
        filters: isAppleProduct ? { ...filters, region } : filters,
      });
    } catch (err) {
      setError("Could not create alert. Try again.");
    } finally {
      setSubmitting(false);
    }
    return;
  };

  return (
    <div className="config" id="configurator">
      <div className="config-art">
        <button type="button" className="back-link" onClick={onClose}>
          ← All products
        </button>
        <div>
          <h3 className="h-section">{product.name}</h3>
          <div className="tagline">{product.tagline}</div>
        </div>
        <div className="hero-art">{product.art()}</div>
        <div className="basespecs">
          {stats.map((label, index) => (
            <React.Fragment key={label}>
              {index > 0 && <span className="dot"></span>}
              <span>{label}</span>
            </React.Fragment>
          ))}
        </div>
      </div>

      <div className="config-body">
        <div>
          <div className="eyebrow" style={{marginBottom:6}}>{submitting ? "Creating..." : "Create alert"}</div>
          <h3 className="h-section" style={{fontSize:24, margin:0}}>Tell us what you want.</h3>
          <p className="muted" style={{marginTop:6, fontSize:14}}>
            Pick a range or leave it as Any. We email you when a listing matches every selection.
          </p>
        </div>

        {product.specs.cpu.length > 0 && (
          <MultiPillGroup
            label={product.filterLabels?.cpu || "Chip"}
            hint="Exact matches"
            options={product.specs.cpu}
            value={filters.cpu}
            onChange={(value) => setFilters(f => ({ ...f, cpu: value }))}
          />
        )}
        {product.specs.ram.length > 0 && (
          <RangePillGroup
            label="Memory"
            options={product.specs.ram}
            value={rangeFromFilters(filters, "ram")}
            onChange={(range) => setFilters(f => withFilterRange(f, "ram", range))}
            format={formatRam}
          />
        )}
        <RangePillGroup
          label="Storage"
          options={product.specs.storage}
          value={rangeFromFilters(filters, "storage")}
          onChange={(range) => setFilters(f => withFilterRange(f, "storage", range))}
          format={formatStorage}
        />

        <div className="summary">
          You'll get an email when {product.storeName} lists a {summarize(productId, filters)}{isAppleProduct ? <React.Fragment> in <strong>{selectedRegion.label}</strong></React.Fragment> : null}.
        </div>

        {lockEmail ? (
          <React.Fragment>
            <div className="email-row">
              <input
                className="email-input" type="email" placeholder="you@example.com"
                value={email}
                readOnly
                onChange={(e) => setEmail(e.target.value)}
                onBlur={() => setTouched(true)}
                onKeyDown={(e) => e.key === "Enter" && submit()}
                aria-invalid={touched && !emailOk}
                style={{background:"var(--bg-soft)", color:"var(--ink-2)"}}
              />
              <button className="config-primary-btn" type="button" onClick={submit} disabled={!emailOk || submitting}>
                {submitting ? "Creating..." : "Create alert"}
              </button>
            </div>
            <div style={{fontSize:12, color:"var(--ink-4)", marginTop:-18}}>
              Sending to your Google account email.
            </div>
          </React.Fragment>
        ) : (
          <div className="config-signin-row">
            <button className="config-google-btn" type="button" onClick={submit} disabled={submitting}>
              <svg className="google-g" viewBox="0 0 18 18" aria-hidden="true">
                <path fill="#4285F4" d="M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.88 2.68-6.62z"/>
                <path fill="#34A853" d="M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.8.54-1.84.86-3.04.86-2.34 0-4.32-1.58-5.03-3.7H.96v2.33A9 9 0 0 0 9 18z"/>
                <path fill="#FBBC05" d="M3.97 10.72A5.4 5.4 0 0 1 3.68 9c0-.6.1-1.18.29-1.72V4.95H.96A9 9 0 0 0 0 9c0 1.45.35 2.82.96 4.05l3.01-2.33z"/>
                <path fill="#EA4335" d="M9 3.58c1.32 0 2.51.45 3.45 1.35l2.58-2.58A8.65 8.65 0 0 0 9 0 9 9 0 0 0 .96 4.95l3.01 2.33C4.68 5.16 6.66 3.58 9 3.58z"/>
              </svg>
              <span>{submitting ? "Opening Google..." : "Continue with Google"}</span>
            </button>
            <div className="config-signin-note">Google verifies the email we use for alerts.</div>
          </div>
        )}
        {error && (
          <div style={{fontSize:12.5, color:"#c2410c", marginTop:-18}}>{error}</div>
        )}
        {lockEmail && touched && !emailOk && (
          <div style={{fontSize:12.5, color:"#c2410c", marginTop:-18}}>Enter a valid email.</div>
        )}
      </div>
    </div>
  );
}

function AlertsList({ alerts, onDelete }) {
  return (
    <div className="alerts">
      {alerts.length === 0 && (
        <div className="alerts-empty">
          No alerts yet. Pick a product below to create your first.
        </div>
      )}
      {alerts.map(a => {
        const p = PRODUCTS[a.productId];
        const bits = [];
        if (APPLE_PRODUCT_IDS.has(a.productId)) {
          const r = regionById(a.filters.region || "us");
          bits.push(`${r.flag} ${r.label}`);
        }
        const cpuText = formatCpuFilter(a.filters.cpu, null);
        if (cpuText) bits.push(cpuText);
        const ramRange = rangeFromFilters(a.filters, "ram");
        const storageRange = rangeFromFilters(a.filters, "storage");
        if (p.specs.ram.length) bits.push(!isAnyRange(ramRange) ? `${formatRange(ramRange, formatRam)} RAM` : "any RAM");
        bits.push(!isAnyRange(storageRange) ? `${formatRange(storageRange, formatStorage)} storage` : "any storage");
        return (
          <div key={a.id} className="alert-row">
            <div className="alert-icon">
              <ProductIcon kind={a.productId} />
            </div>
            <div>
              <div className="alert-title">{p.name} · {bits.join(" · ")}</div>
              <div className="alert-meta">Notifying <span className="num">{a.email}</span> · created {a.createdLabel}</div>
            </div>
            <div className="alert-status">
              <span className="dot"></span> Active
            </div>
            <button className="alert-del" type="button" aria-label="Delete alert" onClick={() => onDelete(a.id)}>
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round">
                <path d="M6 6l12 12M18 6l-12 12"/>
              </svg>
            </button>
          </div>
        );
      })}
    </div>
  );
}



function SignInModal({ open, onClose, onGoogleSignIn }) {
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    if (open) {
      setBusy(false);
      setError(null);
    }
  }, [open]);

  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [open, onClose]);

  if (!open) return null;

  const submit = async () => {
    if (busy) return;
    setBusy(true);
    setError(null);
    try {
      await onGoogleSignIn();
    } catch (err) {
      setError("Could not start Google sign-in. Try again.");
      setBusy(false);
    }
  };

  return (
    <div className="modal-backdrop" onClick={onClose}>
      <div className="modal-wrap" onClick={(e) => e.stopPropagation()}>
        <div className="modal auth-modal">
          <button className="x" type="button" onClick={onClose} aria-label="Close">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"><path d="M6 6l12 12M18 6l-12 12"/></svg>
          </button>
          <div className="auth-head">
            <PingMark size={38} />
            <div>
              <h3>Sign in to RefurbPing</h3>
            </div>
          </div>
          <div className="auth-copy">
            <p>Use your Google account so we can attach alerts to a verified email. RefurbPing only stores your email for sign-in and notifications.</p>
          </div>
          <button className="google-btn" type="button" onClick={submit} disabled={busy}>
            <svg className="google-g" viewBox="0 0 18 18" aria-hidden="true">
              <path fill="#4285F4" d="M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.88 2.68-6.62z"/>
              <path fill="#34A853" d="M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.8.54-1.84.86-3.04.86-2.34 0-4.32-1.58-5.03-3.7H.96v2.33A9 9 0 0 0 9 18z"/>
              <path fill="#FBBC05" d="M3.97 10.72A5.4 5.4 0 0 1 3.68 9c0-.6.1-1.18.29-1.72V4.95H.96A9 9 0 0 0 0 9c0 1.45.35 2.82.96 4.05l3.01-2.33z"/>
              <path fill="#EA4335" d="M9 3.58c1.32 0 2.51.45 3.45 1.35l2.58-2.58A8.65 8.65 0 0 0 9 0 9 9 0 0 0 .96 4.95l3.01 2.33C4.68 5.16 6.66 3.58 9 3.58z"/>
            </svg>
            <span>{busy ? "Opening Google..." : "Continue with Google"}</span>
          </button>
          <div className="auth-note">No password to remember. You can revoke access from your Google account at any time.</div>
          {error && <div className="auth-error">{error}</div>}
        </div>
      </div>
    </div>
  );
}

function SignedOutAlerts({ onSignIn }) {
  return (
    <div className="signed-out-card">
      <div>
        <h3>Sign in to manage alerts</h3>
        <div className="copy">
          View, pause, edit, or delete alerts tied to your Google email.
        </div>
      </div>
      <div className="sign-card-actions">
        <button className="google-card-btn" type="button" onClick={onSignIn}>
          <svg className="google-g" viewBox="0 0 18 18" aria-hidden="true">
            <path fill="#4285F4" d="M17.64 9.2c0-.64-.06-1.25-.16-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.72v2.26h2.92c1.7-1.57 2.68-3.88 2.68-6.62z"/>
            <path fill="#34A853" d="M9 18c2.43 0 4.47-.8 5.96-2.18l-2.92-2.26c-.8.54-1.84.86-3.04.86-2.34 0-4.32-1.58-5.03-3.7H.96v2.33A9 9 0 0 0 9 18z"/>
            <path fill="#FBBC05" d="M3.97 10.72A5.4 5.4 0 0 1 3.68 9c0-.6.1-1.18.29-1.72V4.95H.96A9 9 0 0 0 0 9c0 1.45.35 2.82.96 4.05l3.01-2.33z"/>
            <path fill="#EA4335" d="M9 3.58c1.32 0 2.51.45 3.45 1.35l2.58-2.58A8.65 8.65 0 0 0 9 0 9 9 0 0 0 .96 4.95l3.01 2.33C4.68 5.16 6.66 3.58 9 3.58z"/>
          </svg>
          <span>Continue with Google</span>
        </button>
      </div>
    </div>
  );
}

function HowItWorks() {
  const steps = [
    { n: "1", t: "Set your spec", d: "Pick a product, then a chip, minimum RAM, and minimum storage. Or leave any field as Any." },
    { n: "2", t: "We watch in real time", d: "The monitor checks Apple refurb inventory continuously and pushes matching updates without an intentional delay." },
    { n: "3", t: "Email lands immediately", d: "When a listing matches every field of your alert, the notification email includes the direct Apple buy link." },
  ];
  return (
    <div className="grid">
      {steps.map(s => (
        <div className="card" key={s.n} style={{cursor:"default"}}>
          <div style={{
            width:32, height:32, borderRadius:"50%",
            background:"var(--bg-soft)", color:"var(--ink-2)",
            display:"flex", alignItems:"center", justifyContent:"center",
            fontWeight:600, fontSize:14, marginBottom:18,
            border:"1px solid var(--hairline)"
          }}>{s.n}</div>
          <div className="product-name">{s.t}</div>
          <div className="product-meta" style={{marginTop:4, lineHeight:1.5}}>{s.d}</div>
        </div>
      ))}
    </div>
  );
}

// ─── Tweak defaults ───────────────────────────────────────────────────────────

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#0071e3",
  "ping": "#30d158",
  "density": "regular"
}/*EDITMODE-END*/;

// ─── App ──────────────────────────────────────────────────────────────────────

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [region, setRegion] = useState("us");
  const [activeProduct, setActiveProduct] = useState(null);
  const [auth, setAuth] = useState({ signedIn: false, email: null, userId: null });
  const [authLoading, setAuthLoading] = useState(true);
  const [alerts, setAlerts] = useState([]);
  const [toast, setToast] = useState(null);
  const [signInOpen, setSignInOpen] = useState(false);
  const watchingCount = 12834 + alerts.length;

  const showToast = (message, ms = 3200) => {
    setToast(message);
    setTimeout(() => setToast(null), ms);
  };

  const refreshSession = async () => {
    const session = await api("/api/session");
    setAuth(sessionAuth(session));
    setAlerts(session.alerts || []);
    setAuthLoading(false);
    return session;
  };

  // Push tweak values into CSS vars + body classes
  useEffect(() => {
    document.documentElement.style.setProperty("--accent", t.accent);
    document.documentElement.style.setProperty("--ping", t.ping);
    document.body.classList.remove("density-compact", "density-comfy");
    if (t.density === "compact") document.body.classList.add("density-compact");
    if (t.density === "comfy") document.body.classList.add("density-comfy");
  }, [t.accent, t.ping, t.density]);

  useEffect(() => {
    refreshSession().then((session) => {
      const url = new URL(window.location.href);
      const authResult = url.searchParams.get("auth");
      const wantsAlertManager = url.searchParams.get("manage") === "alerts";
      const sessionState = sessionAuth(session);
      if (authResult === "ok") showToast("Signed in");
      if (authResult === "expired") showToast("That sign-in link expired. Request a new one.", 4200);
      if (authResult === "google-expired") showToast("That Google sign-in expired. Try again.", 4200);
      if (authResult === "google-denied") showToast("Google sign-in was cancelled.", 3200);
      if (authResult === "google-unverified") showToast("Your Google email is not verified.", 4200);
      if (authResult === "google-error") showToast("Could not finish Google sign-in. Try again.", 4200);
      if (authResult) {
        url.searchParams.delete("auth");
        window.history.replaceState({}, "", url.pathname + url.search + url.hash);
      }
      if (wantsAlertManager) {
        setTimeout(() => {
          document.getElementById("alerts")?.scrollIntoView({ behavior: "smooth", block: "start" });
        }, 80);
        if (!sessionState.signedIn) setSignInOpen(true);
      }
    }).catch(() => {
      setAuthLoading(false);
      showToast("Could not load your session", 4200);
    });
  }, []);

  const startGoogleAuth = async (payload = { purpose: "sign-in" }) => {
    const nextPayload = { ...payload };
    const url = new URL(window.location.href);
    if (!nextPayload.returnTo && nextPayload.purpose === "sign-in" && url.searchParams.get("manage") === "alerts") {
      nextPayload.returnTo = "/?manage=alerts#alerts";
    }
    const res = await api("/api/auth/google/start", {
      method: "POST",
      body: JSON.stringify(nextPayload),
    });
    window.location.href = res.authorizeUrl;
  };

  const signOut = async () => {
    await api("/api/auth/sign-out", { method: "POST", body: JSON.stringify({}) });
    setAuth({ signedIn: false, email: null, userId: null });
    setAlerts([]);
    setAuthLoading(false);
    showToast("Signed out", 2200);
  };

  const handleCreate = async ({ productId, email, filters }) => {
    if (auth.signedIn && email === auth.email) {
      const res = await api("/api/alerts", {
        method: "POST",
        body: JSON.stringify({ productId, filters }),
      });
      setAlerts(a => [res.alert, ...a]);
      setActiveProduct(null);
      showToast("Alert saved — we'll email " + email + " when it matches.", 3500);
      setTimeout(() => {
        const el = document.getElementById("alerts");
        if (el) window.scrollTo({ top: el.offsetTop - 60, behavior: "smooth" });
      }, 80);
    } else {
      await startGoogleAuth({
        purpose: "alert",
        pendingAlert: { productId, filters },
      });
    }
  };

  const handleDelete = async (id) => {
    await api("/api/alerts/" + encodeURIComponent(id), { method: "DELETE" });
    setAlerts(a => a.filter(x => x.id !== id));
  };

  const pickProduct = (id) => {
    setActiveProduct(id);
    setTimeout(() => {
      const el = document.getElementById("configurator");
      if (el) window.scrollTo({ top: el.offsetTop - 40, behavior: "smooth" });
    }, 60);
  };

  return (
    <React.Fragment>
      <Nav alertCount={alerts.length} auth={auth} authLoading={authLoading} onSignIn={() => setSignInOpen(true)} onSignOut={signOut} />

      <Hero watching={watchingCount} />

      <section className="tight" style={{paddingTop:0}}>
        <div className="wrap" style={{display:"flex", flexDirection:"column", alignItems:"center", gap:10}}>
          <RegionDropdown region={region} setRegion={setRegion} />
          <div style={{fontSize:12, color:"var(--ink-4)"}}>
            21 Apple refurbished stores live
          </div>
        </div>
      </section>

      <section id="products">
        <div className="wrap-wide">
          {activeProduct ? (
            <Configurator
              productId={activeProduct}
              region={region}
              onClose={() => setActiveProduct(null)}
              onCreate={handleCreate}
              prefilledEmail={!authLoading && auth.signedIn ? auth.email : ""}
              lockEmail={!authLoading && auth.signedIn}
            />
          ) : (
            <React.Fragment>
              <div className="section-head">
                <div>
                  <div className="eyebrow">Choose a product</div>
                  <h2 className="h-section">What should we watch?</h2>
                </div>
                <div className="muted" style={{fontSize:13}}>
                  {Object.keys(PRODUCTS).length} products live · {COMING_SOON.length} on the way
                </div>
              </div>
              <div className="grid">
                {Object.values(PRODUCTS).map(product => (
                  <ProductCard key={product.id} product={product} onPick={pickProduct} />
                ))}
                {COMING_SOON.map(p => (
                  <ProductCard key={p.id} product={p} comingSoon dim />
                ))}
              </div>
            </React.Fragment>
          )}
        </div>
      </section>

      <section id="alerts">
        <div className="wrap">
          {authLoading ? (
            <React.Fragment>
              <div className="section-head">
                <div>
                  <div className="eyebrow">Your alerts</div>
                  <h2 className="h-section">Loading...</h2>
                </div>
              </div>
              <div className="alerts">
                <div className="alerts-empty">Checking your session...</div>
              </div>
            </React.Fragment>
          ) : auth.signedIn ? (
            <React.Fragment>
              <div className="section-head">
                <div>
                  <div className="eyebrow">Your alerts</div>
                  <h2 className="h-section">
                    {alerts.length > 0 ? `${alerts.length} alert${alerts.length === 1 ? "" : "s"} live` : "No alerts yet"}
                  </h2>
                </div>
                {alerts.length > 0 && (
                  <div className="muted" style={{fontSize:13}}>
                    Add more anytime · unsubscribe from any email
                  </div>
                )}
              </div>
              <AlertsList alerts={alerts} onDelete={handleDelete} />
            </React.Fragment>
          ) : (
            <React.Fragment>
              <div className="section-head">
                <div>
                  <div className="eyebrow">Manage your alerts</div>
                  <h2 className="h-section">Already created some?</h2>
                </div>
              </div>
              <SignedOutAlerts onSignIn={() => setSignInOpen(true)} />
            </React.Fragment>
          )}
        </div>
      </section>


      <section id="how">
        <div className="wrap-wide">
          <div className="section-head">
            <div>
              <div className="eyebrow">How it works</div>
              <h2 className="h-section">Three steps. Then nothing — until it matters.</h2>
            </div>
          </div>
          <HowItWorks />
        </div>
      </section>

      <footer>
        <div className="wrap-wide foot-row">
          <div className="brand" style={{fontSize:13}}>
            <Logo size={18} gap={7} />
          </div>
          <div className="foot-copy">© 2026 Refurb Ping</div>
          <div className="foot-actions" aria-label="Footer">
            <a href="https://tally.so/r/xXvBKy" target="_blank" rel="noopener noreferrer" className="feedback-link">
              <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                <path d="M21 15a4 4 0 0 1-4 4H8l-5 3v-7a4 4 0 0 1-1-2.6V7a4 4 0 0 1 4-4h11a4 4 0 0 1 4 4Z"/>
                <path d="M7 8h10"/>
                <path d="M7 12h6"/>
              </svg>
              <span>Feedback</span>
            </a>
            <a href={KOFI_TIP_URL} target="_blank" rel="noopener noreferrer" className="tip-link">
              <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                <path d="M18 8h1a4 4 0 0 1 0 8h-1"/>
                <path d="M2 8h16v9a4 4 0 0 1-4 4H6a4 4 0 0 1-4-4Z"/>
                <line x1="6" y1="2" x2="6" y2="4"/>
                <line x1="10" y1="2" x2="10" y2="4"/>
                <line x1="14" y1="2" x2="14" y2="4"/>
              </svg>
              <span>Buy us a coffee</span>
            </a>
            <div className="status-pill">
              <span className="live-dot" aria-hidden="true"></span>
              <span>All systems operational</span>
            </div>
          </div>
        </div>
      </footer>

      {toast && (
        <div className="toast" role="status">
          <span className="dot"></span> {toast}
        </div>
      )}

      <SignInModal
        open={signInOpen}
        onClose={() => setSignInOpen(false)}
        onGoogleSignIn={() => startGoogleAuth({ purpose: "sign-in" })}
      />

      <TweaksPanel>
        <TweakSection label="Theme" />
        <TweakColor label="Accent" value={t.accent}
          options={["#0071e3", "#30d158", "#ff6b00", "#bf5af2", "#1d1d1f"]}
          onChange={(v) => setTweak("accent", v)} />
        <TweakColor label="Ping dot" value={t.ping}
          options={["#30d158", "#ff453a", "#ff9f0a", "#0071e3"]}
          onChange={(v) => setTweak("ping", v)} />
        <TweakSection label="Layout" />
        <TweakRadio label="Density" value={t.density}
          options={["compact", "regular", "comfy"]}
          onChange={(v) => setTweak("density", v)} />
      </TweaksPanel>
    </React.Fragment>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
