// Delte UI-primitiver. Retning: "nordisk aurora-tech" – dyp marineblå med
// nordlys-glød (emerald/lime), serif-overskrifter, mono-mikroetiketter.
// Andre filer bruker disse via window.STWORDER.ui – alltid lazy, inne i
// komponent-funksjonene, aldri på toppnivå.
import React, { useSyncExternalStore, useEffect } from 'react';

const NS = window.STWORDER;

/* ---------- hooks ---------- */

function useCart() {
  return useSyncExternalStore(NS.store.subscribe, NS.store.get);
}

function useI18n() {
  useSyncExternalStore(NS.i18n.subscribe, () => NS.i18n.lang);
  return { t: NS.i18n.t, lang: NS.i18n.lang, setLang: NS.i18n.setLang };
}

/* ---------- helpers ---------- */

const fmt = new Intl.NumberFormat('nb-NO', {
  style: 'currency', currency: 'NOK',
  minimumFractionDigits: 0, maximumFractionDigits: 0,
});
function nok(n) { return fmt.format(n); }

function localName(v, lang) {
  if (v && typeof v === 'object') return v[lang] || v.no || v.en;
  return v;
}

/* ---------- små byggeklosser ---------- */

function MonoLabel({ children, className }) {
  return (
    <div className={'font-mono text-[11px] font-medium uppercase tracking-[0.18em] ' + (className || '')}>
      {children}
    </div>
  );
}

function Btn({ variant, className, ...props }) {
  const variants = {
    navy: 'bg-navy text-white hover:bg-navy-soft',
    brand: 'bg-brand text-white hover:bg-emerald-700',
    ghost: 'border border-gray-300 bg-white text-navy hover:border-navy',
    outline: 'border border-navy/20 bg-white text-navy hover:bg-navy hover:text-white',
  };
  return (
    <button
      className={
        'inline-flex cursor-pointer items-center justify-center gap-2 rounded-xl px-4 py-2.5 text-sm font-semibold transition-all disabled:cursor-not-allowed disabled:opacity-40 ' +
        (variants[variant || 'navy']) + ' ' + (className || '')
      }
      {...props}
    />
  );
}

function Spinner({ className }) {
  return (
    <span className={'inline-block h-4 w-4 animate-spin rounded-full border-2 border-gray-300 border-t-brand ' + (className || '')} />
  );
}

function CheckIcon({ className }) {
  return (
    <svg viewBox="0 0 20 20" fill="currentColor" className={'h-5 w-5 ' + (className || '')}>
      <path fillRule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm3.857-9.809a.75.75 0 0 0-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 1 0-1.06 1.061l2.5 2.5a.75.75 0 0 0 1.137-.089l4-5.5Z" clipRule="evenodd" />
    </svg>
  );
}

function MailIcon({ className }) {
  return (
    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className={'h-4 w-4 ' + (className || '')}>
      <path strokeLinecap="round" strokeLinejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 0 1-2.25 2.25h-15a2.25 2.25 0 0 1-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25m19.5 0v.243a2.25 2.25 0 0 1-1.07 1.916l-7.5 4.615a2.25 2.25 0 0 1-2.36 0L3.32 8.91a2.25 2.25 0 0 1-1.07-1.916V6.75" />
    </svg>
  );
}

function StepHeading({ n, children, right }) {
  return (
    <div className="mb-4 flex flex-wrap items-center justify-between gap-4">
      <div className="flex items-center gap-3">
        <span className="font-display text-3xl font-bold text-gray-300">0{n}</span>
        <h2 className="text-2xl font-bold text-navy">{children}</h2>
      </div>
      {right || null}
    </div>
  );
}

function SectionTitle({ label, title, className }) {
  return (
    <div className={'mb-8 ' + (className || '')}>
      {label ? <MonoLabel className="mb-2 text-brand">{label}</MonoLabel> : null}
      <h2 className="font-display text-3xl font-bold text-navy sm:text-4xl">{title}</h2>
    </div>
  );
}

/* ---------- side-hero (mørk, nordlys) ---------- */

function PageHero({ label, title, sub, children, center }) {
  return (
    <section className="hero-bg relative overflow-hidden">
      <div className="hero-grid pointer-events-none absolute inset-0" />
      <div className={'relative mx-auto max-w-6xl px-4 pb-14 pt-10 sm:pt-14 ' + (center ? 'text-center' : '')}>
        {label ? <MonoLabel className="fade-up mb-3 text-brand">{label}</MonoLabel> : null}
        <h1 className="fade-up fade-up-1 font-display text-4xl font-bold text-navy sm:text-5xl">{title}</h1>
        {sub ? <p className={'fade-up fade-up-2 mt-3 max-w-xl text-gray-600 ' + (center ? 'mx-auto' : '')}>{sub}</p> : null}
        {children ? <div className="fade-up fade-up-3 mt-8">{children}</div> : null}
      </div>
    </section>
  );
}

/* ---------- AI-prompt-aktig søkeboks ---------- */

function AISearchBox({ value, onChange, onSubmit, placeholder, chips, onChip, label, children }) {
  return (
    <div className="relative text-left">
      <div className="rounded-2xl bg-white/90 p-2 shadow-[0_8px_50px_-16px_rgba(16,185,129,0.45)] ring-1 ring-gray-200 backdrop-blur-md transition-all focus-within:shadow-[0_8px_60px_-12px_rgba(16,185,129,0.55)] focus-within:ring-brand/50">
        <form onSubmit={(e) => { e.preventDefault(); if (onSubmit) onSubmit(); }}>
          <div className="flex items-center gap-3 px-3">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="h-5 w-5 shrink-0 text-gray-400">
              <path strokeLinecap="round" strokeLinejoin="round" d="m21 21-4.35-4.35M17 10.5a6.5 6.5 0 1 1-13 0 6.5 6.5 0 0 1 13 0Z" />
            </svg>
            <input
              type="text"
              value={value}
              onChange={(e) => onChange(e.target.value)}
              placeholder={placeholder}
              autoCapitalize="none"
              autoCorrect="off"
              spellCheck="false"
              className="min-w-0 flex-1 bg-transparent py-3.5 text-base text-navy outline-none placeholder:text-gray-400 sm:text-lg"
            />
          </div>
          <div className="flex flex-wrap items-center justify-between gap-2 px-2 pb-1.5">
            <div className="flex flex-wrap gap-1.5">
              {(chips || []).map((c) => (
                <button
                  key={c}
                  type="button"
                  onClick={() => onChip && onChip(c)}
                  className="cursor-pointer rounded-full bg-gray-50 px-3 py-1 text-xs font-medium text-gray-600 ring-1 ring-gray-200 transition-colors hover:bg-gray-100 hover:text-navy"
                >
                  {c}
                </button>
              ))}
            </div>
            <button
              type="submit"
              className="cursor-pointer rounded-xl bg-brand px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-emerald-700"
            >
              {label}
            </button>
          </div>
        </form>
      </div>
      {children ? (
        <div className="fade-up mt-3 overflow-hidden rounded-2xl bg-white/95 shadow-xl ring-1 ring-gray-200 backdrop-blur-md">
          {children}
        </div>
      ) : null}
    </div>
  );
}

/* ---------- produktkort (moderne prising, pill-badge) ---------- */

function ProductCard({ badge, tone, icon, title, sub, desc, features, priceLabel, price, cta, onCta, selected, featured }) {
  const pill = tone === 'orange' ? 'bg-orange-500' : 'bg-brand';
  const hot = featured || selected;
  return (
    <div
      className={
        'relative flex flex-col rounded-2xl border bg-white p-6 pt-7 transition-all duration-200 hover:-translate-y-1 hover:shadow-xl ' +
        (hot
          ? 'border-brand shadow-lg shadow-emerald-600/10 ring-1 ring-brand'
          : 'border-gray-200 shadow-sm')
      }
    >
      {badge ? (
        <div className={'absolute -top-3 left-6 rounded-full px-3 py-1 ' + pill}>
          <MonoLabel className="text-white">{badge}</MonoLabel>
        </div>
      ) : null}
      {icon ? (
        <div className="mb-3 flex h-11 w-11 items-center justify-center rounded-xl bg-gray-50 text-xl ring-1 ring-gray-100">{icon}</div>
      ) : null}
      <h3 className="text-2xl font-bold text-navy">{title}</h3>
      {sub ? <MonoLabel className="mt-1 text-gray-400">{sub}</MonoLabel> : null}
      {desc ? <p className="mt-3 text-sm leading-relaxed text-gray-600">{desc}</p> : null}
      {features && features.length ? (
        <ul className="mt-4 space-y-2.5">
          {features.map((f, i) => (
            <li key={i} className="flex items-start gap-2 text-sm text-gray-700">
              <CheckIcon className="mt-0.5 h-4 w-4 shrink-0 text-brand" />
              {f}
            </li>
          ))}
        </ul>
      ) : null}
      <div className="mt-auto pt-6">
        <div className="flex items-baseline gap-1.5">
          {priceLabel ? <span className="text-sm text-gray-500">{priceLabel}</span> : null}
          <span className="text-3xl font-bold tracking-tight text-navy">{price}</span>
        </div>
        {cta ? (
          <Btn variant={hot ? 'brand' : 'outline'} className="mt-4 w-full" onClick={onCta}>
            {cta} <span aria-hidden>→</span>
          </Btn>
        ) : null}
      </div>
    </div>
  );
}

/* ---------- header / footer / banner ---------- */

function DemoBanner() {
  const { t } = useI18n();
  return (
    <div className="bg-accent py-1.5 text-center">
      <MonoLabel className="px-4 text-navy-deep">{t('banner.demo')}</MonoLabel>
    </div>
  );
}

function Header({ route, onCart }) {
  const { t, lang, setLang } = useI18n();
  const cart = useCart();
  const links = [
    { href: '#/domener', route: 'domener', label: t('nav.domains') },
    { href: '#/hosting', route: 'hosting', label: t('nav.hosting') },
    { href: '#/vps', route: 'vps', label: t('nav.vps') },
  ];
  return (
    <header className="sticky top-0 z-40 border-b border-gray-200 bg-white/95 backdrop-blur">
      <div className="mx-auto flex h-16 max-w-6xl items-center justify-between gap-4 px-4">
        <a href="#/" className="shrink-0 text-xl font-bold tracking-tight text-navy">
          servetheworld<span className="text-accent">.</span>
        </a>
        <nav className="hidden items-center gap-6 md:flex">
          {links.map((l) => (
            <a
              key={l.route}
              href={l.href}
              className={
                'text-sm font-medium transition-colors ' +
                (route === l.route ? 'text-brand' : 'text-gray-600 hover:text-navy')
              }
            >
              {l.label}
            </a>
          ))}
        </nav>
        <div className="flex items-center gap-3">
          <div className="hidden items-center gap-1 text-xs font-semibold text-gray-400 sm:flex">
            <button
              onClick={() => setLang('no')}
              className={'cursor-pointer px-1 ' + (lang === 'no' ? 'text-navy' : 'hover:text-gray-600')}
            >NO</button>
            <span>/</span>
            <button
              onClick={() => setLang('en')}
              className={'cursor-pointer px-1 ' + (lang === 'en' ? 'text-navy' : 'hover:text-gray-600')}
            >EN</button>
          </div>
          <a
            href="https://my.servetheworld.net"
            className="hidden text-sm font-medium text-gray-600 hover:text-navy lg:block"
          >
            {t('nav.panel')}
          </a>
          <button
            onClick={onCart}
            className="relative inline-flex cursor-pointer items-center gap-2 rounded-xl bg-brand px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-emerald-700"
          >
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="h-4 w-4">
              <path strokeLinecap="round" strokeLinejoin="round" d="M2.25 3h1.5l2.4 12.3a1.5 1.5 0 0 0 1.47 1.2h9.96a1.5 1.5 0 0 0 1.46-1.14L21 7.5H5.1M9 20.25a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Zm9 0a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0Z" />
            </svg>
            <span className="hidden sm:inline">{t('header.cart')}</span>
            {cart.items.length > 0 ? (
              <span className="absolute -right-2 -top-2 flex h-5 min-w-5 items-center justify-center rounded-full bg-navy px-1 text-[11px] font-bold text-white">
                {cart.items.length}
              </span>
            ) : null}
          </button>
        </div>
      </div>
    </header>
  );
}

function Footer() {
  const { t } = useI18n();
  return (
    <footer className="mt-20 bg-white">
      <div className="h-px bg-gradient-to-r from-transparent via-emerald-500/50 to-transparent" />
      <div className="mx-auto max-w-6xl px-4 py-10 text-center text-sm text-gray-500">
        <div className="mb-1 font-bold text-navy">
          servetheworld<span className="text-accent">.</span>
        </div>
        <div>© 2026 ServeTheWorld AS · {t('footer.demo')}</div>
      </div>
    </footer>
  );
}

/* ---------- trust-linje (konvertering) ---------- */

function TrustBar({ className, dark }) {
  const { t } = useI18n();
  const items = ['trust.registrar', 'trust.support', 'trust.dc', 'trust.cancel'];
  return (
    <div className={'flex flex-wrap items-center justify-center gap-x-6 gap-y-2 ' + (className || '')}>
      {items.map((k) => (
        <span key={k} className={'flex items-center gap-1.5 text-sm ' + (dark ? 'text-gray-300' : 'text-gray-600')}>
          <CheckIcon className={'h-4 w-4 ' + (dark ? 'text-accent' : 'text-brand')} />
          {t(k)}
        </span>
      ))}
    </div>
  );
}

/* ---------- handlevogn ---------- */

/* Flat, domene-gruppert vogn: domene + tilhørende hosting i samme delkort.
   Domener uten hosting får en "Legg til webhotell"-knapp som åpner
   upsell-dialogen ('upsell:open' på bussen). */
function groupCart(items) {
  const groups = [];
  const byDomain = {};
  for (const item of items) {
    if (item.type === 'domain' || item.type === 'transfer') {
      const g = { key: 'd' + item.id, title: item.domain, domainItem: item, products: [], vps: null };
      byDomain[item.domain] = g;
      groups.push(g);
    }
  }
  for (const item of items) {
    if (item.type === 'product') {
      const name = item.domain && item.domain.name;
      if (name && byDomain[name]) {
        byDomain[name].products.push(item);
      } else {
        groups.push({ key: 'p' + item.id, title: name || item.name, domainItem: null, products: [item], vps: null });
      }
    } else if (item.type === 'vps') {
      groups.push({ key: 'v' + item.id, title: item.name, domainItem: null, products: [], vps: item });
    }
  }
  return groups;
}

function groupDue(g) {
  let sum = 0;
  if (g.domainItem) sum += NS.store.itemDue(g.domainItem);
  if (g.vps) sum += NS.store.itemDue(g.vps);
  for (const p of g.products) sum += NS.store.itemDue(p);
  return sum;
}

function RemoveBtn({ onClick, t }) {
  return (
    <button onClick={onClick} className="cursor-pointer text-xs text-gray-400 hover:text-red-600">
      {t('common.remove')}
    </button>
  );
}

function CartItems({ compact, upsell }) {
  const { t } = useI18n();
  const cart = useCart();
  const groups = groupCart(cart.items);
  const cycleLabel = (item) =>
    item.cycle === 'annually' ? t('hosting.cycleAnnually') : t('hosting.cycleMonthly');
  const modeNote = (d) =>
    d.mode === 'new' ? t('cart.domainReg')
    : d.mode === 'transfer' ? t('cart.domainTransfer')
    : d.mode === 'cart' ? t('cart.domainLinked')
    : t('cart.domainOwn');

  return (
    <div className="space-y-3 py-3">
      {groups.map((g) => (
        <div key={g.key} className="rounded-xl border border-gray-200 bg-gray-50/70 p-3">
          <div className="flex items-center justify-between gap-2">
            <span className="truncate text-sm font-bold text-navy">{g.title}</span>
            <span className="shrink-0 text-sm font-bold text-navy">{nok(groupDue(g))}</span>
          </div>

          {g.domainItem ? (
            <div className="mt-1 flex items-center justify-between gap-2">
              <div className="min-w-0">
                <div className="truncate text-xs text-gray-500">
                  {g.domainItem.type === 'transfer'
                    ? t('cart.domainTransfer')
                    : t('cart.domainReg') + ' · ' + t('domains.emailIncluded')}
                </div>
              </div>
              <div className="flex shrink-0 items-center gap-2">
                <span className="text-xs font-semibold text-gray-600">{nok(NS.store.itemDue(g.domainItem))}</span>
                {!compact ? <RemoveBtn t={t} onClick={() => NS.store.remove(g.domainItem.id)} /> : null}
              </div>
            </div>
          ) : null}

          {g.products.map((p) => (
            <div key={p.id} className="mt-2 flex items-center justify-between gap-2 border-t border-gray-200/70 pt-2">
              <div className="min-w-0">
                <div className="text-sm font-semibold text-navy">{p.name}</div>
                <div className="truncate text-xs text-gray-500">
                  {cycleLabel(p)}
                  {!g.domainItem && p.domain ? ' · ' + modeNote(p.domain) : ''}
                </div>
              </div>
              <div className="flex shrink-0 items-center gap-2">
                <span className="text-xs font-semibold text-gray-600">{nok(NS.store.itemDue(p))}</span>
                {!compact ? <RemoveBtn t={t} onClick={() => NS.store.remove(p.id)} /> : null}
              </div>
            </div>
          ))}

          {g.vps ? (
            <div className="mt-1 flex items-center justify-between gap-2">
              <div className="truncate text-xs text-gray-500">
                {cycleLabel(g.vps)} · {g.vps.os}{g.vps.hostname ? ' · ' + g.vps.hostname : ''}
              </div>
              {!compact ? <RemoveBtn t={t} onClick={() => NS.store.remove(g.vps.id)} /> : null}
            </div>
          ) : null}

          {upsell && g.domainItem && g.products.length === 0 ? (
            <button
              onClick={() => NS.bus.emit('upsell:open', g.title)}
              className="mt-2.5 flex w-full cursor-pointer items-center justify-center gap-1.5 rounded-lg border border-dashed border-emerald-300 bg-white py-2 text-sm font-semibold text-brand transition-colors hover:bg-emerald-50"
            >
              <span aria-hidden>+</span> {t('cart.addHosting')}
            </button>
          ) : null}
        </div>
      ))}
    </div>
  );
}

function CartDrawer({ open, onClose }) {
  const { t } = useI18n();
  const cart = useCart();

  useEffect(() => {
    function onKey(e) { if (e.key === 'Escape') onClose(); }
    if (open) window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [open, onClose]);

  if (!open) return null;
  return (
    <div className="fixed inset-0 z-50">
      <div className="absolute inset-0 bg-navy/30 backdrop-blur-sm" onClick={onClose} />
      <div className="absolute inset-y-0 right-0 flex w-full max-w-md flex-col bg-white shadow-2xl">
        <div className="flex items-center justify-between border-b border-gray-200 p-4">
          <h2 className="text-lg font-bold text-navy">{t('cart.title')}</h2>
          <button onClick={onClose} className="cursor-pointer rounded-md p-1 text-gray-400 hover:text-navy" aria-label="Close">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="h-6 w-6">
              <path strokeLinecap="round" strokeLinejoin="round" d="M6 18 18 6M6 6l12 12" />
            </svg>
          </button>
        </div>
        <div className="flex-1 overflow-y-auto px-4">
          {cart.items.length === 0 ? (
            <div className="py-16 text-center">
              <p className="mb-4 text-sm text-gray-500">{t('cart.empty')}</p>
              <Btn variant="brand" onClick={() => { onClose(); location.hash = '#/domener'; }}>
                {t('cart.emptyCta')}
              </Btn>
            </div>
          ) : (
            <CartItems upsell />
          )}
        </div>
        {cart.items.length > 0 ? (
          <div className="border-t border-gray-200 p-4">
            <div className="mb-3 flex items-center justify-between">
              <span className="text-sm font-medium text-gray-600">{t('cart.dueToday')}</span>
              <span className="text-xl font-bold text-navy">{nok(NS.store.cartDue())}</span>
            </div>
            <Btn
              variant="brand"
              className="w-full py-3"
              onClick={() => { onClose(); location.hash = '#/kasse'; }}
            >
              {t('cart.checkout')} <span aria-hidden>→</span>
            </Btn>
            <button
              onClick={onClose}
              className="mt-2 w-full cursor-pointer text-center text-sm text-gray-500 hover:text-navy"
            >
              {t('cart.continue')}
            </button>
          </div>
        ) : null}
      </div>
    </div>
  );
}

/* Kasse-nudge: dukker opp etter at hosting legges i vognen ('checkout:nudge'
   på bussen) – bekrefter og peker mot kassen uten å tvinge. */
function CheckoutToast() {
  const { t } = useI18n();
  const [nudge, setNudge] = React.useState(null);

  useEffect(() => NS.bus.on('checkout:nudge', (payload) => setNudge(payload || {})), []);
  // Skjul toasten når upsell-dialogen åpner – aldri to lag med nudges.
  useEffect(() => {
    const clear = () => setNudge(null);
    const off1 = NS.bus.on('domain:added', clear);
    const off2 = NS.bus.on('upsell:open', clear);
    return () => { off1(); off2(); };
  }, []);
  useEffect(() => {
    if (!nudge) return;
    const id = setTimeout(() => setNudge(null), 7000);
    return () => clearTimeout(id);
  }, [nudge]);

  if (!nudge) return null;
  return (
    <div className="pointer-events-none fixed inset-x-0 bottom-6 z-50 flex justify-center px-4">
      <div className="fade-up pointer-events-auto flex max-w-full items-center gap-3 rounded-full bg-white/95 py-2 pl-4 pr-2 shadow-[0_8px_50px_-12px_rgba(16,185,129,0.5)] ring-1 ring-gray-200 backdrop-blur-md">
        <CheckIcon className="h-5 w-5 shrink-0 text-brand" />
        <div className="min-w-0">
          {nudge.name ? (
            <div className="truncate text-sm font-semibold text-navy">{t('toast.added', { name: nudge.name })}</div>
          ) : null}
          <div className="truncate text-xs text-gray-500">{t('toast.ready')}</div>
        </div>
        <button
          onClick={() => { setNudge(null); location.hash = '#/kasse'; }}
          className="shrink-0 cursor-pointer rounded-full bg-brand px-4 py-2 text-sm font-semibold text-white transition-colors hover:bg-emerald-700"
        >
          {t('cart.checkout')} <span aria-hidden>→</span>
        </button>
        <button
          onClick={() => setNudge(null)}
          className="shrink-0 cursor-pointer rounded-full p-1 text-gray-400 hover:text-navy"
          aria-label="Close"
        >
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" className="h-4 w-4">
            <path strokeLinecap="round" strokeLinejoin="round" d="M6 18 18 6M6 6l12 12" />
          </svg>
        </button>
      </div>
    </div>
  );
}

NS.ui = {
  useCart, useI18n, nok, localName,
  MonoLabel, Btn, Spinner, CheckIcon, MailIcon, StepHeading, SectionTitle, PageHero, ProductCard, AISearchBox,
  DemoBanner, Header, Footer, TrustBar,
  CartItems, CartDrawer, CheckoutToast,
};
