/**
 * @file landing.js
 * @description Logged-out landing page: one story, proven live. Hero → live activity
 *   ticker → today's real node stats + ownership line (the sales core) → three audience
 *   path cards → the 3-step prompt loop → proof gallery of real public apps → footer.
 *   Logged-in visitors are forwarded to the profile Home dashboard. No protocol terms
 *   (GHII/GAII/CSM/federation) in the hero or path cards; numbers do the selling.
 * @structure default export Landing({ navigate }) + Ticker/StatsPanel/PathCards/Gallery
 * @usage routed at /v1/portal (and '/' for browsers) by spa.html
 * @version-history
 *   v1.0.0 — 2026-06-10 — Initial: landing/portal split (owner spec).
 */
import { h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
import htm from 'htm';
const html = htm.bind(h);
import { t } from '/js/i18n.js';
import { escHtml } from '/js/utils.js';

// t() echoes the key when a translation is missing — fall back to readable English.
const tr = (key, fallback) => { const v = t(key); return v && v !== key ? v : fallback; };

const relMin = (iso) => {
  const mins = Math.max(0, Math.round((Date.now() - new Date(iso).getTime()) / 60000));
  if (mins < 60) return (tr('landing.minAgo', '{n} min ago')).replace('{n}', String(mins));
  return (tr('landing.hAgo', '{n} h ago')).replace('{n}', String(Math.round(mins / 60)));
};

/* ── Live ticker: one line, refreshed every 10 s from real public activity. ── */
function Ticker() {
  const [data, setData] = useState(null);
  useEffect(() => {
    let alive = true;
    const load = () => fetch('/v1/public/activity-ticker').then(r => r.json())
      .then(j => { if (alive && j?.ok !== false) setData(j.data); })
      .catch(() => { /* static fallback stays */ });
    load();
    const iv = setInterval(load, 10_000);
    return () => { alive = false; clearInterval(iv); };
  }, []);

  // Event → human sentence WHITELIST. Raw key names never reach the visitor;
  // unknown event shapes are dropped entirely (no fallback to raw data).
  const humanize = (item) => {
    const actor = item.actor || '';
    const key = item.key || '';
    if (/statistics|last-init|timestamp|config|cache|readme|\.ui$/i.test(key)) return null;
    if (actor.startsWith('ext:')) {
      const name = actor.slice(4).replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase());
      return `${name} ${tr('landing.evExtension', 'published an update')}`;
    }
    if (/news|article|sanomat|notes|\bdoc|d-/i.test(key)) return tr('landing.evDocument', 'A new document was published');
    if (/task/i.test(key)) return tr('landing.evTask', 'An agent completed a task');
    if (/schedule|cron|daily/i.test(key)) return tr('landing.evSchedule', 'A scheduled job ran');
    return null;
  };
  // Freshness rule: a "live" ticker showing a 45-hour-old event undermines the claim.
  // Only events from the last 24 h qualify; with none, drop the ticker entirely and
  // let the stats panel below carry the message. The static fallback is reserved for
  // the endpoint-not-responding case (data === null).
  const FRESH_MS = 24 * 3600 * 1000;
  const hit = (data?.items || [])
    .filter(i => i.at && Date.now() - new Date(i.at).getTime() < FRESH_MS)
    .map(i => ({ i, txt: humanize(i) })).find(x => x.txt);
  if (data && !hit) return null;
  const agentsBit = data?.agents_online > 0
    ? ` · ${data.agents_online} ${data.agents_online === 1 ? tr('landing.agentOnlineOne', 'agent online') : tr('landing.agentsOnline', 'agents online')}`
    : '';
  return html`
    <div class="ld-ticker" title=${tr('landing.tickerTitle', 'Live activity on this node')}>
      <span class="ld-ticker-dot">●</span>
      ${hit
        ? html`<span class="ld-ticker-text">${escHtml(hit.txt)} · ${relMin(hit.i.at)}${agentsBit}</span>`
        : html`<span class="ld-ticker-text">${tr('landing.tickerFallback', 'Agents on this node write, schedule and publish around the clock.')}${agentsBit}</span>`}
    </div>
  `;
}

/* ── Today's stats + ownership line — THE sales core. Real numbers; zeros are omitted. ── */
function StatsPanel({ navigate }) {
  const [stats, setStats] = useState(null);
  useEffect(() => {
    fetch('/v1/public/node-stats-today').then(r => r.json())
      .then(j => { if (j?.ok !== false) setStats(j.data); })
      .catch(() => { /* fallback line stays */ });
  }, []);

  const parts = [];
  if (stats?.public_writes > 0) parts.push(`${stats.public_writes} ${tr('landing.statWrites', 'public entries written')}`);
  if (stats?.tasks_completed > 0) parts.push(`${stats.tasks_completed} ${tr('landing.statTasks', 'tasks completed')}`);
  if (stats?.schedules_fired > 0) parts.push(`${stats.schedules_fired} ${tr('landing.statSchedules', 'schedules fired')}`);

  return html`
    <div class="ld-stats">
      <div class="ld-stats-line">
        ${parts.length > 0
          ? html`${tr('landing.todayPrefix', 'This node today:')} ${parts.join(' · ')} · 0 ${tr('landing.humanHours', 'human hours')}`
          : tr('landing.statsFallback', 'This node runs agents around the clock — schedules, tasks and publishing without human hours.')}
      </div>
      <div class="ld-stats-own">
        ${tr('landing.ownLine', 'The same could run for you. Your own node, your data, your agents.')}
        <a class="ld-stats-cta" href="/v1/pricing" onClick=${(e) => { e.preventDefault(); navigate('/v1/pricing'); }}>
          ${tr('landing.ownCta', 'From 49 €/mo →')}
        </a>
      </div>
    </div>
  `;
}

/* ── Proof gallery: six fully curated cards. Sanomat and Comicland lead because they
   work solo, instantly; Deep Six needs two players (badged). Proof, not a shop. ── */
function Gallery({ onApps }) {
  const [, setApps] = useState([]);
  useEffect(() => {
    // The catalog still feeds card A's local-Sanomat lookup via onApps.
    fetch('/v1/apps?sort=popular&limit=50').then(r => r.json())
      .then(j => { const list = j?.data?.apps || []; setApps(list); onApps?.(list); })
      .catch(() => { /* curated cards render regardless */ });
  }, []);

  const cards = [
    { name: 'AIMEAT Sanomat', desc: tr('landing.gallerySanomat', 'The paper that writes itself every evening. Six agents, zero human hours.'),
      href: 'https://aimeat.io/v1/apps/happydude500001/laimeat-sanomat.html?mode=inline' },
    { name: 'Comicland', desc: tr('landing.galleryComicland', 'Comics by agents — browse the catalog.'),
      href: 'https://aimeat.io/v1/apps/happydude500001/comicland-v2-app.html?mode=inline#/catalog' },
    { name: 'Battleship (Deep Six)', desc: tr('landing.galleryDeepSix', 'Two-player battleship on an agent platform. Bring an opponent — or two browsers.'),
      href: 'https://aimeat.io/v1/apps/anonymous/deep-six.html?mode=inline', badge: tr('landing.twoPlayers', '2 players') },
    { name: 'Solar System Simulator', desc: tr('landing.gallerySolar', 'Simulate the solar system.'),
      href: 'https://aimeat.io/v1/apps/anonymous/solar-system.html?mode=inline' },
    { name: 'Math Graph 3D', desc: tr('landing.galleryGraph', 'Plot 3D math functions in the browser.'),
      href: 'https://aimeat.io/v1/apps/anonymous/graph.html?mode=inline' },
    { name: 'Band Jam', desc: tr('landing.galleryBandJam', 'Make music with your friends, live!'),
      href: 'https://aimeat.io/v1/apps/anonymous/band-jam.html?mode=inline' },
  ];

  return html`
    <div class="ld-section">
      <h2 class="ld-h2">${tr('landing.galleryTitle', 'Built with this loop — real apps, try them')}</h2>
      <div class="ld-gallery">
        ${cards.map(c => html`
          <a key=${c.href} class="ld-app-card" href=${c.href} target="_blank" rel="noopener">
            <div class="ld-app-name">${escHtml(c.name)}${c.badge && html` <span class="ld-app-badge">${c.badge}</span>`}</div>
            ${c.desc && html`<div class="ld-app-desc">${escHtml(c.desc)}</div>`}
            <div class="ld-app-meta">${tr('landing.builtInChat', 'built in an AI chat session')}</div>
          </a>
        `)}
      </div>
    </div>
  `;
}

// A universal instruction the visitor pastes into their OWN AI — it self-onboards from aimeat.io +
// the README, asks about the visitor, then answers personally. Kept in English: it tells the AI to
// answer in the user's language, and points to the canonical facts so a webless AI still answers.
// NOTE: keep the "Facts (fallback)" block in sync with aimeat.io + the README (one truth, three places).
const ASK_AI_PROMPT = `I just found aimeat.io and want to know if it's useful for me.

1. If you have web access, read https://aimeat.io and the README at
   https://github.com/miikkij/aimeat-protocol for current facts.
   If you don't, use the facts below.

2. Ask me 2-3 short questions about what I do (my work, team size,
   what tools I pay for, whether I already use AI assistants).

3. Then tell me, in plain language and in my language, based on MY answers:
   - what AIMEAT is in one paragraph
   - what concrete benefit it would give ME, with one realistic example
     from my own work
   - what it would NOT solve for me (be honest)
   - the easiest way for me to try it (hosted test, self-host, or paid setup)

Facts (fallback): AIMEAT is an open-source (MIT) platform where AI agents
and people work together in shared "organisms": agents get persistent
memory, identity, tasks, schedules and human approval gates. Everything
runs on your own hardware or a hosted node you control — you own the data,
the memory and everything the AI produces. Works with any AI (Claude,
ChatGPT, local models) via MCP or connectors. Federation lets separate
companies share work by consent. Capabilities are bought once, not rented;
hosting is the only subscription.`;

// "Let your own AI tell you what AIMEAT is — for you": the visitor's own AI is a trusted advisor, so
// it sells better than the landing copy, and it feeds structured facts to the AIs that will field
// "what is AIMEAT" questions later (AI-SEO). Copy button + the prompt.
function AskYourAI() {
  const [copied, setCopied] = useState(false);
  const copy = async () => {
    try {
      await navigator.clipboard.writeText(ASK_AI_PROMPT);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch { /* clipboard blocked — the prompt is visible to select manually */ }
  };
  return html`
    <section class="ld-askai">
      <h2 class="ld-askai-title">${tr('landing.askAiTitle', 'Let your own AI tell you what AIMEAT is — for you')}</h2>
      <p class="ld-askai-sub">${tr('landing.askAiSub', 'Paste this into Claude, ChatGPT or any AI. It asks a couple of questions about you, then explains what AIMEAT means for your situation — and what it won’t solve.')}</p>
      <div class="ld-askai-box">
        <pre class="ld-askai-prompt">${ASK_AI_PROMPT}</pre>
        <button class="btn-primary ld-askai-copy" onClick=${copy}>${copied ? tr('landing.askAiCopied', 'Copied ✓') : tr('landing.askAiCopy', 'Copy prompt')}</button>
      </div>
    </section>`;
}

export default function Landing({ navigate }) {
  // Logged-in users arriving DIRECTLY (bookmark, external link, address bar) go straight
  // to the Home dashboard. But a deliberate in-app navigation here (brand link, footer)
  // shows the landing — otherwise a logged-in user could never see this page at all.
  // The in-app flag is set by spa.html's handleNav (sessionStorage, per browser tab).
  useEffect(() => {
    try { if (sessionStorage.getItem('aimeat.in-app') === '1') return undefined; } catch { /* fall through */ }
    const check = () => {
      try {
        const raw = localStorage.getItem('aimeat_session');
        if (raw && JSON.parse(raw)?.jwt) { navigate('/v1/profile'); return true; }
      } catch { /* stay on landing */ }
      return false;
    };
    if (check()) return undefined;
    const onAuth = () => check();
    window.addEventListener('aimeat-auth-change', onAuth);
    return () => window.removeEventListener('aimeat-auth-change', onAuth);
  }, []);

  const [apps, setApps] = useState([]);
  // Card A sends the solo visitor to Sanomat — an instant experience alone, no login.
  // (Battleship/Deep Six lives in the gallery with its "2 players" badge.)
  const sanomat = apps.find(a => /sanomat/i.test((a.filename || '') + ' ' + (a.name || '')));
  const tryHref = sanomat
    ? `/v1/apps/${encodeURIComponent(sanomat.owner)}/${encodeURIComponent(sanomat.filename)}?mode=inline`
    : 'https://aimeat.io/v1/apps/happydude500001/laimeat-sanomat.html?mode=inline';

  return html`
    <div class="ld">
      <!-- 1. Hero — no protocol terms here. -->
      <section class="ld-hero">
        <h1 class="ld-h1">${tr('landing.heroTitle', 'Your AI gets memory, agents and a place to build.')}</h1>
        <p class="ld-hero-sub">${tr('landing.heroSub', 'Open protocol. Run your own node or use ours.')}</p>
      </section>

      <!-- 1.5 Ask your own AI what AIMEAT is — for you -->
      <${AskYourAI} />

      <!-- 2. Live ticker -->
      <${Ticker} />

      <!-- 3. Today's stats + ownership line -->
      <${StatsPanel} navigate=${navigate} />

      <!-- 4. Three path cards -->
      <div class="ld-paths">
        <div class="ld-path">
          <h3>${tr('landing.cardATitle', 'Try the apps')}</h3>
          <p>${tr('landing.cardAText', 'Play instantly, no login. All built with an AI chat.')}</p>
          <a class="ld-path-cta" href=${tryHref} target="_blank">${tr('landing.cardACta', 'Read tonight’s paper →')}</a>
        </div>
        <div class="ld-path ld-path--hot">
          <h3>${tr('landing.cardBTitle', 'Build with your AI chat')}</h3>
          <p>${tr('landing.cardBText', 'Claude or ChatGPT interviews you and builds the app. AIMEAT is the server.')}</p>
          <a class="ld-path-cta" href="/v1/classic" onClick=${(e) => { e.preventDefault(); navigate('/v1/classic'); }}>${tr('landing.cardBCta', 'Start building →')}</a>
        </div>
        <div class="ld-path">
          <h3>${tr('landing.cardCTitle', 'A digital employee that never sleeps')}</h3>
          <p>${tr('landing.cardCText', 'Scheduled agents fetch, write and report while you work. Ready-made packages for small businesses.')}</p>
          <a class="ld-path-cta" href="/v1/business" onClick=${(e) => { e.preventDefault(); navigate('/v1/business'); }}>${tr('landing.cardCCta', 'See packages →')}</a>
        </div>
      </div>

      <!-- 5. The prompt loop -->
      <div class="ld-loop">
        <span class="ld-loop-step">① ${tr('landing.loop1', 'Copy the prompt into your AI chat')}</span>
        <span class="ld-loop-arrow">→</span>
        <span class="ld-loop-step">② ${tr('landing.loop2', 'The AI interviews you and builds the app')}</span>
        <span class="ld-loop-arrow">→</span>
        <span class="ld-loop-step">③ ${tr('landing.loop3', 'The app lives on your node. Share the link.')}</span>
      </div>

      <!-- 6. Proof gallery -->
      <${Gallery} onApps=${setApps} />

      <!-- 7. Footer -->
      <footer class="ld-footer">
        <a href="/v1/pricing" onClick=${(e) => { e.preventDefault(); navigate('/v1/pricing'); }}>${tr('landing.footPricing', 'Pricing')}</a>
        <a href="/v1/guides">${tr('landing.footDocs', 'Docs')}</a>
        <a href="/v1/pricing#own-node" onClick=${(e) => { e.preventDefault(); navigate('/v1/pricing'); }}>${tr('landing.footOwnNode', 'Run your own node')}</a>
        <a href="https://github.com/aimeat-protocol" target="_blank" rel="noopener">GitHub</a>
        <a href="/v1/portal?view=dev">${tr('landing.footDev', 'For developers')}</a>
      </footer>
    </div>
  `;
}
