// Shared UI components

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

// ---------- Status pill ----------
const StatusPill = ({ state, size = 'sm', label }) => {
  const map = {
    clean: { cls: 'pill-clean', text: label || 'Clean' },
    flag: { cls: 'pill-flag', text: label || 'Flagged' },
    alert: { cls: 'pill-alert', text: label || 'Alert' },
    info: { cls: 'pill-info', text: label || 'Info' },
    neutral: { cls: '', text: label || '—' },
  };
  const conf = map[state] || map.neutral;
  return (
    <span className={`pill ${conf.cls}`} style={size === 'lg' ? { fontSize: 12.5, padding: '4px 11px' } : {}}>
      <span className="dot" />
      {conf.text}
    </span>
  );
};

// ---------- Vessel thumb (image-slot drop-in or placeholder) ----------
const VesselThumb = ({ boat, w = 56, h = 40, radius = 6 }) => {
  return (
    <image-slot
      id={`boat-${boat.id}`}
      shape="rounded"
      radius={radius + 'px'}
      placeholder={`${boat.make} ${boat.model}`}
      src={boat.src || ''}
      style={{ width: w, height: h, flexShrink: 0, display: 'block', background: 'transparent' }}
    ></image-slot>
  );
};

// ---------- Step strip ----------
const StepStrip = ({ steps, current, onStep }) => (
  <div className="step-strip">
    {steps.map((s, i) => {
      const state = i < current ? 'done' : i === current ? 'current' : '';
      return (
        <div
          key={i}
          className={`step ${state}`}
          onClick={() => onStep && i <= current && onStep(i)}
          style={{ cursor: onStep && i <= current ? 'pointer' : 'default' }}
        >
          <div className="step-n">STEP {String(i + 1).padStart(2, '0')}</div>
          <div className="step-l">{s}</div>
        </div>
      );
    })}
  </div>
);

// ---------- Section heading ----------
const SectionHead = ({ eyebrow, title, sub, right }) => (
  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginBottom: 14, gap: 24 }}>
    <div>
      {eyebrow && <div className="mono" style={{ fontSize: 11, color: 'var(--ink-3)', letterSpacing: '0.06em', textTransform: 'uppercase', marginBottom: 6 }}>{eyebrow}</div>}
      <div style={{ fontSize: 20, fontWeight: 600, letterSpacing: '-0.015em', color: 'var(--ink)' }}>{title}</div>
      {sub && <div style={{ color: 'var(--ink-3)', fontSize: 13.5, marginTop: 4, maxWidth: 640 }}>{sub}</div>}
    </div>
    {right}
  </div>
);

// ---------- KV row ----------
const KV = ({ label, value, mono = false, status, alignRight = false }) => (
  <div style={{ display: 'flex', justifyContent: alignRight ? 'space-between' : 'flex-start', gap: 16, padding: '9px 0', borderBottom: '1px solid var(--line)' }}>
    <div style={{ color: 'var(--ink-3)', fontSize: 12.5, minWidth: alignRight ? 0 : 140 }}>{label}</div>
    <div className={mono ? 'mono' : ''} style={{ fontSize: 13, color: 'var(--ink)', display: 'flex', alignItems: 'center', gap: 8, textAlign: alignRight ? 'right' : 'left' }}>
      {status && <StatusPill state={status} />}
      {value}
    </div>
  </div>
);

// ---------- Boat selector dropdown ----------
const BoatSelect = ({ value, onChange, filter, placeholder = 'Search by HIN, name, or registration…' }) => {
  const [open, setOpen] = useState(false);
  const [q, setQ] = useState('');
  const ref = useRef(null);

  useEffect(() => {
    const click = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', click);
    return () => document.removeEventListener('mousedown', click);
  }, []);

  const results = BOATS.filter(b => !filter || filter(b)).filter(b => {
    if (!q) return true;
    const s = (b.hin + b.name + b.reg + b.make + b.model).toLowerCase();
    return s.includes(q.toLowerCase());
  });

  const selected = BOATS.find(b => b.id === value);

  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <button
        type="button"
        onClick={() => setOpen(o => !o)}
        className="input"
        style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer', textAlign: 'left' }}
      >
        {selected ? (
          <span style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <VesselThumb boat={selected} w={36} h={26} radius={4} />
            <span>
              <span style={{ fontWeight: 500 }}>{selected.name}</span>
              <span className="mono" style={{ marginLeft: 8, color: 'var(--ink-3)', fontSize: 12 }}>{selected.hin}</span>
            </span>
          </span>
        ) : (
          <span style={{ color: 'var(--ink-3)' }}>{placeholder}</span>
        )}
        <Icon name="chevronDown" />
      </button>
      {open && (
        <div className="card" style={{ position: 'absolute', top: 'calc(100% + 6px)', left: 0, right: 0, zIndex: 50, padding: 8, maxHeight: 380, overflowY: 'auto', boxShadow: 'var(--shadow-lg)' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '4px 8px 8px', borderBottom: '1px solid var(--line)' }}>
            <Icon name="search" color="var(--ink-3)" />
            <input
              autoFocus
              className="input"
              style={{ border: 'none', padding: 0, fontSize: 13 }}
              placeholder={placeholder}
              value={q}
              onChange={(e) => setQ(e.target.value)}
            />
          </div>
          <div style={{ padding: 4 }}>
            {results.length === 0 && <div style={{ padding: 16, color: 'var(--ink-3)', fontSize: 13 }}>No vessels match.</div>}
            {results.map(b => (
              <button
                key={b.id}
                type="button"
                onClick={() => { onChange(b.id); setOpen(false); setQ(''); }}
                style={{
                  width: '100%', display: 'flex', alignItems: 'center', gap: 10,
                  padding: '8px 8px', borderRadius: 6, background: 'transparent',
                  border: 'none', textAlign: 'left',
                }}
                onMouseEnter={(e) => e.currentTarget.style.background = 'var(--paper-2)'}
                onMouseLeave={(e) => e.currentTarget.style.background = 'transparent'}
              >
                <VesselThumb boat={b} w={42} h={30} radius={5} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                    <span style={{ fontWeight: 500, fontSize: 13 }}>{b.name}</span>
                    <span className="mono" style={{ color: 'var(--ink-3)', fontSize: 11.5 }}>{b.hin}</span>
                  </div>
                  <div style={{ color: 'var(--ink-3)', fontSize: 12 }}>{b.make} {b.model} · {b.year} · {formatGBP(b.value)}</div>
                </div>
                <StatusPill state={b.state} />
              </button>
            ))}
          </div>
        </div>
      )}
    </div>
  );
};

// ---------- Flag card ----------
const FlagCard = ({ flag }) => {
  const sev = flag.severity || 'flag';
  const colorMap = {
    flag: { bg: 'var(--flag-soft)', fg: 'oklch(0.4 0.14 50)', border: 'oklch(0.8 0.1 60)' },
    alert: { bg: 'var(--alert-soft)', fg: 'var(--alert)', border: 'oklch(0.8 0.12 25)' },
  };
  const c = colorMap[sev];
  return (
    <div style={{
      background: c.bg, border: `1px solid ${c.border}`, borderRadius: 8,
      padding: '12px 14px', display: 'flex', gap: 12, alignItems: 'flex-start'
    }}>
      <div style={{ color: c.fg, paddingTop: 2 }}>
        <Icon name={sev === 'alert' ? 'alert' : 'flag'} size={18} strokeWidth={1.8} />
      </div>
      <div style={{ flex: 1 }}>
        <div style={{ fontWeight: 600, fontSize: 13.5, color: c.fg }}>{flag.summary}</div>
        <div style={{ color: 'var(--ink-2)', fontSize: 12.5, marginTop: 3 }}>{flag.detail}</div>
      </div>
    </div>
  );
};

// ---------- Mini stat ----------
const Stat = ({ label, value, sub, accent }) => (
  <div className="card card-pad" style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
    <div style={{ fontSize: 11.5, color: 'var(--ink-3)', textTransform: 'uppercase', letterSpacing: '0.04em', fontWeight: 500 }}>{label}</div>
    <div style={{ fontSize: 24, fontWeight: 600, letterSpacing: '-0.02em', color: accent || 'var(--ink)' }}>{value}</div>
    {sub && <div style={{ fontSize: 12, color: 'var(--ink-3)' }}>{sub}</div>}
  </div>
);

// ---------- Loader ring ----------
const LoadRing = ({ size = 14 }) => (
  <span style={{
    width: size, height: size, display: 'inline-block',
    border: '2px solid var(--line-2)',
    borderTopColor: 'var(--accent)',
    borderRadius: '50%',
    animation: 'spin 0.7s linear infinite',
  }} />
);

// inject spin keyframes once
if (!document.getElementById('__spin_kf')) {
  const s = document.createElement('style');
  s.id = '__spin_kf';
  s.textContent = '@keyframes spin{to{transform:rotate(360deg)}}';
  document.head.appendChild(s);
}

// ---------- Card header ----------
const CardHeader = ({ title, sub, right, icon }) => (
  <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', gap: 12 }}>
    {icon && (
      <div style={{
        width: 30, height: 30, borderRadius: 7,
        background: 'var(--paper-2)', border: '1px solid var(--line)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        color: 'var(--ink-2)',
      }}>
        <Icon name={icon} size={15} />
      </div>
    )}
    <div style={{ flex: 1 }}>
      <div style={{ fontWeight: 600, fontSize: 14, color: 'var(--ink)' }}>{title}</div>
      {sub && <div style={{ fontSize: 12, color: 'var(--ink-3)' }}>{sub}</div>}
    </div>
    {right}
  </div>
);

// ---------- Container ----------
const Container = ({ children, narrow = false, style = {} }) => (
  <div style={{
    maxWidth: narrow ? 880 : 1280,
    margin: '0 auto',
    padding: '0 32px',
    ...style,
  }}>{children}</div>
);

// ---------- Mock signature ----------
const SignatureMark = ({ width = 110, height = 36, color = 'var(--ink-2)' }) => (
  <svg width={width} height={height} viewBox="0 0 110 36" fill="none">
    <path
      d="M5 26 C 12 8, 18 8, 22 22 C 24 28, 28 26, 32 18 C 36 10, 42 14, 46 22 C 50 30, 56 24, 60 14 C 64 6, 72 10, 76 20 C 78 24, 84 22, 90 16 C 95 12, 102 14, 105 22"
      stroke={color} strokeWidth="1.4" strokeLinecap="round" fill="none"
    />
  </svg>
);

Object.assign(window, {
  StatusPill, VesselThumb, StepStrip, SectionHead, KV, BoatSelect,
  FlagCard, Stat, LoadRing, CardHeader, Container, SignatureMark,
});
