// Shared: Farben, Typo, Translations, Node-Graph, Pixel-Icon, Substack Fetch

const KS = {
  coral: '#ff644f',
  mutedRed: '#e55745',
  deepRed: '#cc4c3d',
  blush: '#ffd4cc',
  charcoal: '#494648',
  offwhite: '#f8f7f6',
  mintWhite: '#e6f9ee',
  midGreen: '#4caf50',
  forest: '#2e7d32',
  black: '#0a0a0a',
  border: 'rgba(73,70,72,0.12)',
  borderStrong: 'rgba(73,70,72,0.24)',
  muted: 'rgba(73,70,72,0.62)',
};

const KSFonts = {
  display: `'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif`,
  body: `'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif`,
  mono: `'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace`,
};

const PHOTO_URL = 'https://storage.ghost.io/c/56/87/56877316-23fa-4d45-8b30-b16341502fb3/content/images/2025/10/Kilian-Springer-2.jpg';

// ────────────────────────────────────────────────────────────
// Translations
// ────────────────────────────────────────────────────────────
const COPY = {
  de: {
    role: 'Rechtsanwalt · KI-Experte · Speaker',
    at: 'Head of Legal bei Distart Education',
    tagline: 'KI-Experte, Dozent, Rechtsanwalt & Speaker',
    introShort: 'Ich mache Legal Tech und KI-Adoption praktisch — Vorträge, Keynotes und Workshops, die Komplexes verständlich machen.',
    introLong: 'Ich baue und vermittle Legal Tech und KI-Implementierung in Organisationen. Meine Arbeit: Vorträge, Keynotes und hands-on Workshops rund um Künstliche Intelligenz, Prompting und Automations-Workflows. Komplexes verständlich machen, praktische Impulse geben, gemeinsam Lösungen entwickeln — ohne Buzzword-Bingo.',
    servicesTitle: 'Leistungen',
    services: [
      {
        k: 'Events',
        v: 'Live, hands-on AI — in Workshops, Keynotes und Webinaren.',
        detail: 'Ich biete Vorträge, Keynotes und Workshops rund um Legal Tech, Künstliche Intelligenz und digitale Innovationen. Mein Anspruch: Komplexes verständlich machen, praktische Impulse geben und gemeinsam Lösungen entwickeln — immer hands-on, nie mit Buzzword-Overkill. Zuletzt auf der Bühne: Global Legal Forum, Den Haag.',
      },
      {
        k: 'KI-Beratung',
        v: 'Legal Tech & KI-Implementierung in Organisationen.',
        detail: 'Ich begleite Teams und Kanzleien bei der praktischen Einführung von KI: Tool-Auswahl, Prompt-Bibliotheken, Automations-Workflows und Change-Management. Fokus auf das, was im Alltag Zeit spart — nicht auf Pilotprojekte, die in der Schublade landen.',
      },
      {
        k: 'AI Engineering',
        v: 'Prototypen, Automations und eigene Tools.',
        detail: 'Kein klassisches Service-Angebot, aber Teil meiner täglichen Praxis: Ich baue Prototypen, automatisiere Workflows und teste neue Modelle hands-on. Was dabei entsteht, fließt direkt in Keynotes, Workshops und Beratung zurück.',
      },
      {
        k: 'Rechtsberatung',
        v: 'IT-, Online- und Medienrecht.',
        detail: 'Als Rechtsanwalt berate ich in IT-, Online- und Medienrecht — inkl. Datenschutz, Plattform-Compliance und rechtliche Rahmenbedingungen für KI-Einsatz. Mandate laufen über meine Kanzlei.',
      },
    ],
    connect: 'Kontakt',
    elsewhere: 'Anderswo',
    blog: 'Blog',
    blogSub: 'Hands-On AI and Legal Tech',
    latestPost: 'Neuester Artikel',
    readPost: 'Artikel lesen',
    subscribe: 'Abonnieren',
    address: 'Nürnberger Str. 29 · 04103 Leipzig',
    email: 'hello@kilian-springer.com',
    copyEmail: 'E-Mail kopieren',
    emailCopied: 'Kopiert',
    imprint: 'Impressum',
    privacy: 'Datenschutz',
    about: 'Über mich',
    eventsNav: 'Events & Projekte',
    eventsTitle: 'Events & Projekte',
    eventsKicker: 'Auftritte, Podcasts, Projekte',
    eventsIntro: 'Eine laufende Sammlung: Bühnen, Gespräche, Bauprojekte. Filter nach Format.',
    tagAll: 'Alle',
    downloadsNav: 'Downloads',
    downloadsTitle: 'Downloads & Materialien',
    downloadsKicker: 'Slides, Guides, Templates',
    downloadsIntro: 'Materialien aus Vorträgen und Workshops — zum Mitnehmen. Kostenlos, ohne Anmeldung.',
    downloadLabel: 'Herunterladen',
    downloadContent: 'Content herunterladen',
    downloadUnavailable: 'Kein Content verfügbar',
    relatedMaterials: 'Materialien',
    fromEvent: 'Aus:',
    availableFor: 'Macht KI nutzbar',
    availableList: ['Events', 'KI-Beratung', 'Rechtsberatung'],
    footerNote: 'Visitenkarte · kilian-springer.com',
    nowLabel: 'Gerade jetzt',
    nowText: 'Arbeite an KI-Adoption & Legal-Tech-Curricula bei Distart.',
    cta: 'Lass uns reden',
    scroll: 'scroll',
  },
  en: {
    role: 'Lawyer · AI expert · Speaker',
    at: 'Head of Legal at Distart Education',
    tagline: 'AI expert, lecturer, lawyer & speaker',
    introShort: 'I make Legal Tech and AI adoption practical — talks, keynotes and workshops that turn the complex into something usable.',
    introLong: 'I build and teach Legal Tech and AI implementation inside organizations. My work: talks, keynotes and hands-on workshops on artificial intelligence, prompting and automation workflows. Making the complex understandable, giving practical impulses, developing solutions together — without buzzword bingo.',
    servicesTitle: 'Services',
    services: [
      {
        k: 'Events',
        v: 'Live, hands-on AI — in workshops, keynotes and webinars.',
        detail: 'I deliver talks, keynotes and workshops on Legal Tech, artificial intelligence and digital innovation. The goal: turn complex topics into something usable, spark practical next steps, and build solutions together — always hands-on, never buzzword bingo. Most recently on stage: Global Legal Forum, The Hague.',
      },
      {
        k: 'AI Advisory',
        v: 'Legal Tech & AI implementation in organizations.',
        detail: 'I guide teams and law firms through practical AI adoption: tool selection, prompt libraries, automation workflows and change management. Focused on what saves real time day-to-day — not pilot projects that die in a drawer.',
      },
      {
        k: 'AI Engineering',
        v: 'Prototypes, automations and custom tooling.',
        detail: 'Not a packaged service, but part of my daily practice: I build prototypes, automate workflows and test new models hands-on. Whatever I learn feeds directly back into keynotes, workshops and advisory.',
      },
      {
        k: 'Legal Advice',
        v: 'IT, online and media law.',
        detail: 'As a German-admitted lawyer I advise on IT, online and media law — including data protection, platform compliance and the legal framework for deploying AI. Mandates run through my firm.',
      },
    ],
    connect: 'Contact',
    elsewhere: 'Elsewhere',
    blog: 'Blog',
    blogSub: 'Hands-On AI and Legal Tech',
    latestPost: 'Latest post',
    readPost: 'Read post',
    subscribe: 'Subscribe',
    address: 'Nürnberger Str. 29 · 04103 Leipzig',
    email: 'hello@kilian-springer.com',
    copyEmail: 'Copy email',
    emailCopied: 'Copied',
    imprint: 'Imprint',
    privacy: 'Privacy',
    about: 'About',
    eventsNav: 'Events & Projects',
    eventsTitle: 'Events & Projects',
    eventsKicker: 'Appearances, podcasts, projects',
    eventsIntro: 'A running log: stages, conversations, things I’m building. Filter by format.',
    tagAll: 'All',
    downloadsNav: 'Downloads',
    downloadsTitle: 'Downloads & Materials',
    downloadsKicker: 'Slides, guides, templates',
    downloadsIntro: 'Materials from my talks and workshops — yours to take home. Free, no signup.',
    downloadLabel: 'Download',
    downloadContent: 'Download content',
    downloadUnavailable: 'No content available',
    relatedMaterials: 'Materials',
    fromEvent: 'From:',
    availableFor: 'Making AI usable',
    availableList: ['Events', 'AI Advisory', 'Legal Advice'],
    footerNote: 'Business card · kilian-springer.com',
    nowLabel: 'Right now',
    nowText: 'Working on AI adoption & Legal Tech curricula at Distart.',
    cta: "Let's talk",
    scroll: 'scroll',
  },
};

// ────────────────────────────────────────────────────────────
// Node-Graph background (subtle technical element)
// Deterministic so every render is identical.
// ────────────────────────────────────────────────────────────
function NodeGraph({ color = KS.charcoal, opacity = 0.08, width = 800, height = 600, seed = 1, density = 26 }) {
  const nodes = React.useMemo(() => {
    // simple LCG for deterministic positions
    let s = seed * 9301 + 49297;
    const rand = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
    const arr = [];
    for (let i = 0; i < density; i++) {
      arr.push({ x: rand() * width, y: rand() * height, r: 1.5 + rand() * 2 });
    }
    return arr;
  }, [seed, width, height, density]);

  const edges = React.useMemo(() => {
    const e = [];
    for (let i = 0; i < nodes.length; i++) {
      for (let j = i + 1; j < nodes.length; j++) {
        const dx = nodes[i].x - nodes[j].x;
        const dy = nodes[i].y - nodes[j].y;
        const d = Math.sqrt(dx * dx + dy * dy);
        if (d < 120) e.push({ a: i, b: j, d });
      }
    }
    return e;
  }, [nodes]);

  return (
    <svg
      viewBox={`0 0 ${width} ${height}`}
      preserveAspectRatio="xMidYMid slice"
      style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', opacity, pointerEvents: 'none' }}
      aria-hidden="true"
    >
      {edges.map((e, i) => (
        <line
          key={`e${i}`}
          x1={nodes[e.a].x} y1={nodes[e.a].y}
          x2={nodes[e.b].x} y2={nodes[e.b].y}
          stroke={color} strokeWidth={0.6}
        />
      ))}
      {nodes.map((n, i) => (
        <circle key={`n${i}`} cx={n.x} cy={n.y} r={n.r} fill={color} />
      ))}
    </svg>
  );
}

// ────────────────────────────────────────────────────────────
// Pixel icon — small, charcoal + coral, tiny terminal/robot glyph
// Draws with <rect>s on a 16x16 grid. No pixel fonts.
// ────────────────────────────────────────────────────────────
// 16x16 pixel motifs. 0=transparent, 1=charcoal, 2=coral, 3=offwhite
const PIXEL_MOTIFS = {
  terminal: [
    '0000111111111000',
    '0001333333333100',
    '0013333333333310',
    '0013322333233310',
    '0013333333333310',
    '0013333333333310',
    '0013322333333310',
    '0013333333223310',
    '0013333333333310',
    '0013333333333310',
    '0001333333333100',
    '0000111111111000',
    '0000001111100000',
    '0000011111110000',
    '0000111111111000',
    '0001111111111100',
  ],
  paragraph: [
    '0000011111110000',
    '0000111111111100',
    '0001111222111110',
    '0011112222211110',
    '0011122220011110',
    '0011122001111100',
    '0001122011110000',
    '0000112211100000',
    '0000011111110000',
    '0000111112211100',
    '0001111002211110',
    '0011110022211110',
    '0011100222211110',
    '0011112222111100',
    '0001111111110000',
    '0000011111100000',
  ],
  scroll: [
    '0011111111100000',
    '0111111111110000',
    '1111333333311000',
    '1133322222233100',
    '1133333333333100',
    '1133322222233100',
    '1133333333333100',
    '1133322222233100',
    '1133333333333100',
    '1133322222233100',
    '0111333333311000',
    '0011111111100000',
    '0000001111000000',
    '0000012222100000',
    '0000012222100000',
    '0000001111000000',
  ],
  robot: [
    '0000111111110000',
    '0001111111111000',
    '0011111111111100',
    '0011221111221100',
    '0011221111221100',
    '0011111111111100',
    '0011111221111100',
    '0011111111111100',
    '0001111111111000',
    '0000111111110000',
    '0000011111100000',
    '0001111111111000',
    '0011100000011100',
    '0011000000001100',
    '0011000000001100',
    '0000000000000000',
  ],
  mic: [
    '0000111111000000',
    '0001133311000000',
    '0013332233100000',
    '0013322233100000',
    '0013332233100000',
    '0013322233100000',
    '0013332233100000',
    '0001133311000000',
    '0000111111000000',
    '0000001100000000',
    '0000001100000000',
    '0000111111000000',
    '0011111111110000',
    '0000001100000000',
    '0000001100000000',
    '0000000000000000',
  ],
  headphones: [
    '0001111111110000',
    '0111111111111100',
    '1111000000001110',
    '1100000000000110',
    '1100000000000110',
    '1100000000000110',
    '1111000000001110',
    '1331100000011331',
    '1331100000011331',
    '1331100000011331',
    '1331100000011331',
    '1331100000011331',
    '1331100000011331',
    '1111000000001110',
    '0000000000000000',
    '0000000000000000',
  ],
  people: [
    '0001110000111000',
    '0011331001133100',
    '0011331001133100',
    '0011111001111100',
    '0000110000011000',
    '0001111011111100',
    '0011111111111110',
    '0011111111111110',
    '0011111111111110',
    '0011111111111110',
    '0111111111111111',
    '0111111111111111',
    '0110000000000011',
    '0000000000000000',
    '0000000000000000',
    '0000000000000000',
  ],
  book: [
    '0011111111111000',
    '0113333333331100',
    '0133222222223310',
    '0133222222223310',
    '0133222222223310',
    '0133333333333310',
    '0133222222223310',
    '0133222222223310',
    '0133222222223310',
    '0133222222223310',
    '0133222222223310',
    '0113333333331100',
    '0011111111111000',
    '0001111111110000',
    '0000111111100000',
    '0000000000000000',
  ],
};

function PixelIcon({ size = 64, tone = 'coral', motif = 'terminal' }) {
  const c = tone === 'coral' ? KS.coral : KS.charcoal;
  const dark = KS.charcoal;
  const G = PIXEL_MOTIFS[motif] || PIXEL_MOTIFS.terminal;
  const px = size / 16;
  const cells = [];
  for (let y = 0; y < 16; y++) {
    for (let x = 0; x < 16; x++) {
      const v = G[y][x];
      if (v === '0') continue;
      const fill = v === '1' ? dark : v === '2' ? c : KS.offwhite;
      cells.push(
        <rect key={`${x}-${y}`} x={x * px} y={y * px} width={px} height={px} fill={fill} shapeRendering="crispEdges" />
      );
    }
  }
  return (
    <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ display: 'block' }} aria-hidden="true">
      {cells}
    </svg>
  );
}

// ────────────────────────────────────────────────────────────
// Lang toggle (DE/EN)
// ────────────────────────────────────────────────────────────
function LangToggle({ lang, setLang, style = {}, variant = 'default' }) {
  const pill = (code, label) => {
    const active = lang === code;
    return (
      <button
        key={code}
        onClick={() => setLang(code)}
        style={{
          background: active ? KS.charcoal : 'transparent',
          color: active ? KS.offwhite : KS.charcoal,
          border: 'none',
          padding: '6px 10px',
          fontFamily: KSFonts.mono,
          fontSize: 11,
          letterSpacing: 0.5,
          textTransform: 'uppercase',
          cursor: 'pointer',
          borderRadius: 999,
          transition: 'all 150ms ease',
        }}
      >{label}</button>
    );
  };
  return (
    <div style={{
      display: 'inline-flex',
      padding: 3,
      border: `1px solid ${KS.border}`,
      borderRadius: 999,
      background: variant === 'dark' ? 'rgba(255,255,255,0.04)' : '#fff',
      ...style,
    }}>
      {pill('de', 'DE')}
      {pill('en', 'EN')}
    </div>
  );
}

// ────────────────────────────────────────────────────────────
// Substack latest post — live fetch via rss2json proxy.
// Caches last good result in localStorage so teaser never flashes empty.
// ────────────────────────────────────────────────────────────
const FEED_URL = 'https://kiliansblog.substack.com/feed';
const RSS2JSON = 'https://api.rss2json.com/v1/api.json?rss_url=' + encodeURIComponent(FEED_URL);
const CACHE_KEY = 'ks_latest_post_v1';

function parseFirstImgFromHtml(html) {
  if (!html) return null;
  const m = html.match(/<img[^>]+src=["']([^"']+)["']/i);
  return m ? m[1] : null;
}
function stripHtml(html) {
  if (!html) return '';
  const tmp = document.createElement('div');
  tmp.innerHTML = html;
  return (tmp.textContent || '').trim().replace(/\s+/g, ' ');
}

function useLatestPost() {
  const fallback = {
    title: 'Kilians Blog — Hands-On AI and Legal Tech',
    link: 'https://kiliansblog.substack.com/',
    summary: 'Wöchentliche Notizen zu KI-Adoption, Legal Tech und Prompting.',
    image: null,
    pubDate: null,
  };
  const [state, setState] = React.useState(() => {
    try {
      const cached = JSON.parse(localStorage.getItem(CACHE_KEY) || 'null');
      if (cached && cached.title) return { loading: false, post: cached, error: null };
    } catch (e) {}
    return { loading: true, post: fallback, error: null };
  });

  React.useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const r = await fetch(RSS2JSON);
        if (!r.ok) throw new Error('http ' + r.status);
        const data = await r.json();
        const item = data && data.items && data.items[0];
        if (!item) throw new Error('no items');
        const summary = stripHtml(item.description || '').slice(0, 220);
        const image = item.thumbnail || (item.enclosure && item.enclosure.link) || parseFirstImgFromHtml(item.description) || parseFirstImgFromHtml(item.content);
        const post = {
          title: item.title,
          link: item.link,
          summary,
          image: image || null,
          pubDate: item.pubDate || null,
        };
        if (!cancelled) {
          setState({ loading: false, post, error: null });
          try { localStorage.setItem(CACHE_KEY, JSON.stringify(post)); } catch (e) {}
        }
      } catch (e) {
        if (!cancelled) setState(s => ({ loading: false, post: s.post, error: String(e) }));
      }
    })();
    return () => { cancelled = true; };
  }, []);

  return state;
}

// ────────────────────────────────────────────────────────────
// Copy-email button
// ────────────────────────────────────────────────────────────
function CopyEmailButton({ label, copiedLabel, email = 'hello@kilian-springer.com', style = {} }) {
  const [copied, setCopied] = React.useState(false);
  return (
    <button
      onClick={(e) => {
        e.preventDefault();
        navigator.clipboard?.writeText(email);
        setCopied(true);
        setTimeout(() => setCopied(false), 1500);
      }}
      style={{
        appearance: 'none',
        background: 'transparent',
        border: `1px solid ${KS.border}`,
        color: KS.charcoal,
        padding: '8px 12px',
        fontFamily: KSFonts.mono,
        fontSize: 11,
        letterSpacing: 0.5,
        textTransform: 'uppercase',
        cursor: 'pointer',
        borderRadius: 999,
        display: 'inline-flex',
        alignItems: 'center',
        gap: 8,
        transition: 'all 150ms ease',
        ...style,
      }}
    >
      <span style={{ width: 6, height: 6, borderRadius: 3, background: copied ? KS.midGreen : KS.coral, display: 'inline-block' }} />
      {copied ? copiedLabel : label}
    </button>
  );
}

// ────────────────────────────────────────────────────────────
// Pixel Kilian — the signature character (hand-illustrated pixel art)
// Uses image-rendering: pixelated so it stays crisp at any size.
// Idle animation (subtle up-down wobble) + optional laptop-screen flicker overlay.
// ────────────────────────────────────────────────────────────

const PIXEL_KILIAN_URL = 'images/pixel-kilian.png';

function PixelKilian({
  size = 80,
  idle = false,          // subtle up-down idle wobble (off by default — too subtle to notice)
  flicker = true,        // tiny flicker pulse on the laptop screen
  style = {},
  alt = 'Kilian Springer (pixel art)',
}) {
  // Ensure keyframes exist in DOM once
  React.useEffect(() => {
    if (document.getElementById('pixel-kilian-keyframes')) return;
    const s = document.createElement('style');
    s.id = 'pixel-kilian-keyframes';
    s.textContent = `
      @keyframes ks-idle-wobble {
        0%, 100% { transform: translateY(0); }
        50%      { transform: translateY(-2px); }
      }
      @keyframes ks-screen-flicker {
        0%, 92%, 100% { opacity: 0; }
        94%           { opacity: 0.35; }
        96%           { opacity: 0.12; }
        98%           { opacity: 0.42; }
      }
    `;
    document.head.appendChild(s);
  }, []);

  // Aspect ratio of source: 985 / 880 ≈ 1.12 (wider than tall)
  const w = size;
  const h = Math.round(size * 880 / 985);

  return (
    <div style={{
      position: 'relative',
      width: w, height: h,
      display: 'inline-block',
      animation: idle ? 'ks-idle-wobble 3.2s ease-in-out infinite' : undefined,
      ...style,
    }}>
      <img
        src={PIXEL_KILIAN_URL}
        alt={alt}
        width={w}
        height={h}
        style={{
          display: 'block',
          width: '100%', height: '100%',
          imageRendering: 'pixelated',
          userSelect: 'none',
        }}
        draggable={false}
      />
      {flicker && (
        // Overlay a translucent rectangle roughly over the laptop screen
        // Source image: laptop screen occupies roughly x: 60-95%, y: 68-92%
        <div style={{
          position: 'absolute',
          left: '60%', top: '68%', width: '32%', height: '18%',
          background: '#cfd4d8',
          mixBlendMode: 'screen',
          animation: 'ks-screen-flicker 4.6s ease-in-out infinite',
          pointerEvents: 'none',
        }} />
      )}
    </div>
  );
}

Object.assign(window, {
  KS, KSFonts, COPY, PHOTO_URL, PIXEL_KILIAN_URL, PIXEL_MOTIFS,
  NodeGraph, PixelIcon, PixelKilian, LangToggle, CopyEmailButton, useLatestPost,
});
