/* eslint-disable */
const { useState, useEffect, useMemo, useRef, useCallback } = React;
const rootElement = document.getElementById('root');
const marketClient = MarketApi.createClient(rootElement.dataset.marketApiBase);

function formatDate(value, includeYear = true) {
  if (!value) return null;
  const date = new Date(`${String(value).slice(0, 10)}T00:00:00.000Z`);
  if (Number.isNaN(date.getTime())) return value;
  const parts = Object.fromEntries(new Intl.DateTimeFormat('en-GB', {
    day: '2-digit', month: '2-digit',
    ...(includeYear ? { year: '2-digit' } : {}),
    timeZone: 'UTC',
  }).formatToParts(date).map((part) => [part.type, part.value]));
  return includeYear ? `${parts.day}.${parts.month}.${parts.year}` : `${parts.day}.${parts.month}`;
}

function formatNumber(value) {
  return value == null ? null : new Intl.NumberFormat('en-GB').format(value);
}

function formatGeneratedAt(value) {
  if (!value) return 'Awaiting first update';
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return 'Latest published update';
  return new Intl.DateTimeFormat('en-GB', {
    day: '2-digit', month: 'short', year: 'numeric',
    hour: '2-digit', minute: '2-digit',
    timeZone: 'Europe/Oslo', timeZoneName: 'short',
  }).format(date);
}

function formatMarketDate(value) {
  if (!value) return 'Update pending';
  const date = new Date(`${String(value).slice(0, 10)}T00:00:00.000Z`);
  if (Number.isNaN(date.getTime())) return 'Latest update';
  return new Intl.DateTimeFormat('en-GB', {
    day: '2-digit', month: 'short', year: 'numeric', timeZone: 'UTC',
  }).format(date);
}

function formatMarketValue(figure) {
  if (!figure || !Number.isFinite(Number(figure.value))) return '—';
  const fractionDigits = figure.key === 'brent-futures' || figure.key === 'bix-world-mgo' ? 2 : 4;
  return new Intl.NumberFormat('en-GB', {
    minimumFractionDigits: fractionDigits,
    maximumFractionDigits: fractionDigits,
  }).format(Number(figure.value));
}

function marketDirection(changePercent) {
  if (changePercent > 0) return 'up';
  if (changePercent < 0) return 'down';
  return 'flat';
}

function formatMarketChange(changePercent) {
  if (!Number.isFinite(changePercent)) return null;
  const sign = changePercent > 0 ? '+' : changePercent < 0 ? '−' : '';
  return `${sign}${Math.abs(changePercent).toFixed(2)}%`;
}

/* ============================================================
   Small primitives
   ============================================================ */
function Eyebrow({ children }) {
  return <h2 className="section-block__eyebrow">{children}</h2>;
}

function Tabs({ options, value, onChange, label }) {
  return (
    <div className="tabs" role="group" aria-label={label}>
      {options.map(o => (
        <button
          key={o.value}
          type="button"
          aria-pressed={value === o.value}
          className={'tabs__btn' + (value === o.value ? ' is-active' : '')}
          onClick={() => onChange(o.value)}
        >
          {o.label}
          {typeof o.count === 'number' && <span className="tabs__count">({o.count})</span>}
        </button>
      ))}
    </div>
  );
}

function DataState({ loading, error, empty, onRetry, emptyMessage }) {
  if (loading) {
    return <div className="dt-empty" role="status">Loading live market data…</div>;
  }
  if (error) {
    return (
      <div className="dt-empty data-state" role="alert">
        <span>Live market data is temporarily unavailable.</span>
        <button type="button" className="data-state__retry" onClick={onRetry}>Try again</button>
      </div>
    );
  }
  if (empty) return <div className="dt-empty">{emptyMessage}</div>;
  return null;
}

function Check({ on }) {
  return on
    ? <span className="dt__check" aria-label="yes">✓</span>
    : <span className="dt__x" aria-label="no">×</span>;
}

function SpecHeader({ label, unit }) {
  return (
    <span className="dt__spec-header">
      <span>{label}</span>
      <span className="dt__spec-unit">({unit})</span>
    </span>
  );
}

function Status({ status, where }) {
  const cls = status === 'PROMPT'
    ? 'dt__status-label--prompt'
    : 'dt__status-label--available';
  return (
    <span className="dt__status">
      <span className={'dt__status-label ' + cls}>{status}</span>
      {where && <span className="dt__status-where">{where.includes(' ') ? `in ${where.split(' ').slice(-1)[0]}` : `in ${where}`}</span>}
    </span>
  );
}

function StatusFull({ status, where }) {
  // for tables where `where` already includes date or location prefix
  const cls = status === 'PROMPT'
    ? 'dt__status-label--prompt'
    : 'dt__status-label--available';
  // For AVAILABLE rows, where is like "04.01 Bergen" — show as "04.01 in Bergen"
  let renderedWhere = where;
  if (status === 'AVAILABLE' && /^\d{2}\.\d{2}\s/.test(where || '')) {
    const [date, ...rest] = where.split(' ');
    renderedWhere = (<><strong style={{color:'var(--text-primary)'}}>{date}</strong> <span>in {rest.join(' ')}</span></>);
  } else if (where) {
    renderedWhere = <span>in {where}</span>;
  }
  return (
    <span className="dt__status">
      <span className={'dt__status-label ' + cls}>{status}</span>
      {renderedWhere && <span className="dt__status-where">{renderedWhere}</span>}
    </span>
  );
}

function PositionStatus({ status }) {
  if (status.kind === 'prompt') {
    return <StatusFull status="PROMPT" where={status.port} />;
  }

  const date = formatDate(status.date, false) || 'TBA';
  return (
    <span className="dt__status">
      <span className="dt__status-label dt__status-label--available">AVAILABLE</span>
      <span className="dt__status-where">
        <strong className="dt__status-date">{date}</strong>
        {status.port && <> in {status.port}</>}
      </span>
    </span>
  );
}

/* ============================================================
   Section: Fixtures
   ============================================================ */
function FixturesSection({ datasets, loading, error, onRetry, generatedAt }) {
  const [tab, setTab] = useState('spot');
  const rows = datasets[tab] || [];
  return (
    <section className="section-block" id="fixtures">
      <div className="section-block__head">
        <div className="section-block__title-wrap">
          <Eyebrow>Recent Fixtures</Eyebrow>
        </div>
        <div className="section-block__tools">
          <Tabs
            value={tab}
            onChange={setTab}
            label="Fixture term"
            options={[
              { value: 'spot', label: 'Spot', count: datasets.spot.length },
              { value: 'term', label: 'Term', count: datasets.term.length },
            ]}
          />
        </div>
      </div>

      <DataState
        loading={loading}
        error={error}
        empty={rows.length === 0}
        onRetry={onRetry}
        emptyMessage="No published fixtures."
      />
      {!loading && !error && rows.length > 0 && <div className="dt-wrap">
        <table className="dt">
          <thead>
            <tr>
              <th>Date</th><th>Vessel</th><th>Type</th><th>Charterer</th>
              <th>Scope</th><th>Period</th><th>Commencement</th><th>Rate</th>
            </tr>
          </thead>
          <tbody>
            {rows.map((r, i) => (
              <tr key={i}>
                <td>{formatDate(r.date) || <span className="dt__muted">–</span>}</td>
                <td><span className="dt__vessel" style={{cursor:'default'}}>{r.vesselName}</span></td>
                <td>
                  <span className={'dt__type-pill' + (r.term === 'Term' ? ' dt__type-pill--term' : '')}>{r.term}</span>
                </td>
                <td>{r.charterer}</td>
                <td>{r.scope}</td>
                <td>{r.period || <span className="dt__muted">–</span>}</td>
                <td>{formatDate(r.commencement)}</td>
                <td><span className="dt__rate">{r.rate}</span></td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>}
      <div className="dt-foot">
        <span>Total: {rows.length}</span>
        <span>Updated {formatGeneratedAt(generatedAt)}</span>
      </div>
    </section>
  );
}

/* ============================================================
   Section: Requirements
   ============================================================ */
function RequirementsSection({ datasets, loading, error, onRetry, generatedAt }) {
  const [tab, setTab] = useState('spot');
  const rows = datasets[tab] || [];
  return (
    <section className="section-block" id="requirements">
      <div className="section-block__head">
        <div className="section-block__title-wrap">
          <Eyebrow>Open Requirements</Eyebrow>
        </div>
        <div className="section-block__tools">
          <Tabs
            value={tab}
            onChange={setTab}
            label="Requirement term"
            options={[
              { value: 'spot', label: 'Spot', count: datasets.spot.length },
              { value: 'term', label: 'Term', count: datasets.term.length },
            ]}
          />
        </div>
      </div>

      <DataState
        loading={loading}
        error={error}
        empty={rows.length === 0}
        onRetry={onRetry}
        emptyMessage="No published requirements."
      />
      {!loading && !error && rows.length > 0 && <div className="dt-wrap">
          <table className="dt">
            <thead>
              <tr>
                <th>Published</th><th>Charterer</th><th>Scope</th>
                <th>Period</th><th>No. of Vessels</th><th>Commencement</th>
              </tr>
            </thead>
            <tbody>
              {rows.map((r, i) => (
                <tr key={i}>
                  <td>{formatDate(r.published)}</td>
                  <td style={{color:'var(--text-primary)', fontWeight:'var(--font-weight-semibold)'}}>{r.charterer}</td>
                  <td>{r.scope}</td>
                  <td>{r.period || <span className="dt__muted">–</span>}</td>
                  <td>{r.vessels || <span className="dt__muted">–</span>}</td>
                  <td>
                    {formatDate(r.commencement)}
                    {r.commencementEnd ? ` - ${formatDate(r.commencementEnd)}` : ''}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>}
      <div className="dt-foot">
        <span>Total: {rows.length}</span>
        <span>Updated {formatGeneratedAt(generatedAt)}</span>
      </div>
    </section>
  );
}

/* ============================================================
   Section: Positions
   ============================================================ */
function PositionsSection({ view, index, onSelect, selectedKey }) {
  const groups = useMemo(() => MarketApi.groupPositionRows(view.rows), [view.rows]);
  const groupSignature = groups.map((group) => group.vesselType).join('|');
  const [tab, setTab] = useState(groups[0]?.vesselType || '');

  useEffect(() => {
    if (!groups.some((group) => group.vesselType === tab)) {
      setTab(groups[0]?.vesselType || '');
    }
  }, [groupSignature, tab]);

  const activeGroup = groups.find((group) => group.vesselType === tab) || groups[0];
  const rows = activeGroup?.rows || [];
  const vesselType = activeGroup?.vesselType || '';
  const normalizedType = vesselType.toUpperCase();
  const isAhts = normalizedType === 'AHTS' || normalizedType.includes('ANCHOR HANDLING');
  const id = `positions-${index + 1}`;
  return (
    <section className="section-block" id={id}>
      <div className="section-block__head">
        <div className="section-block__title-wrap">
          <Eyebrow>{view.name}</Eyebrow>
        </div>
        {groups.length > 0 && (
          <div className="section-block__tools">
            <Tabs
              value={vesselType}
              onChange={setTab}
              label={`${view.name} vessel type`}
              options={groups.map((group) => ({
                value: group.vesselType,
                label: group.vesselType,
                count: group.rows.length,
              }))}
            />
          </div>
        )}
      </div>

      {groups.length === 0 ? (
        <div className="dt-empty">No vessels in this published position list.</div>
      ) : (
        <div className="dt-wrap">
          <table className="dt">
            <thead>
              <tr>
                <th>Vessel</th>
                {isAhts && <th className="dt__num"><SpecHeader label="BP" unit="t" /></th>}
                <th className="dt__num"><SpecHeader label="BHP" unit="hp" /></th>
                <th className="dt__num"><SpecHeader label="DWT" unit="t" /></th>
                <th className="dt__num"><SpecHeader label="Deck" unit="m²" /></th>
                <th className="dt__center">{isAhts ? 'ROV' : 'Battery'}</th>
                {isAhts && <th className="dt__num"><SpecHeader label="Crane" unit="t" /></th>}
                <th>Current</th>
                <th>Next Charterer</th>
                <th>Status</th>
              </tr>
            </thead>
            <tbody>
              {rows.map((r, i) => {
                const key = `${id}-${r.imo || r.vesselName}-${i}`;
                const isActive = selectedKey === key;
                const isPrompt = r.status?.kind === 'prompt';
                const rowClassName = [isPrompt && 'is-prompt', isActive && 'is-active']
                  .filter(Boolean)
                  .join(' ');
                return (
                  <tr key={key} className={rowClassName}>
                    <td>
                      {r.imo ? (
                        <button
                          type="button"
                          className="dt__vessel dt__vessel-button"
                          onClick={() => onSelect({ ...r, _key: key, region: view.name })}
                          aria-label={`View details for ${r.vesselName}`}
                        >
                          {r.vesselName}
                        </button>
                      ) : (
                        <span className="dt__vessel">{r.vesselName}</span>
                      )}
                    </td>
                    {isAhts && <td className="dt__num">{formatNumber(r.bp) ?? <span className="dt__muted">–</span>}</td>}
                    <td className="dt__num">{formatNumber(r.bhp) ?? <span className="dt__muted">–</span>}</td>
                    <td className="dt__num">{formatNumber(r.dwt) ?? <span className="dt__muted">–</span>}</td>
                    <td className="dt__num">{formatNumber(r.deck) ?? <span className="dt__muted">–</span>}</td>
                    <td className="dt__center"><Check on={isAhts ? r.rov : r.hasBattery} /></td>
                    {isAhts && <td className="dt__num">{formatNumber(r.craneT) ?? <span className="dt__muted">–</span>}</td>}
                    <td>{r.current || <span className="dt__muted">–</span>}</td>
                    <td>{r.next || <span className="dt__muted">–</span>}</td>
                    <td><PositionStatus status={r.status} /></td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}
      <div className="dt-foot">
        <span>Available: {rows.filter(r => r.status.kind === 'date').length || 'None'}</span>
        <span>Showing {vesselType || 'positions'} · Total {rows.length}</span>
      </div>
    </section>
  );
}

/* ============================================================
   Sparkline
   ============================================================ */
function Sparkline({ data, dir, width = 110, height = 30 }) {
  if (!data || data.length < 2) return null;
  const min = Math.min(...data);
  const max = Math.max(...data);
  const range = max - min || 1;
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * width;
    const y = height - ((v - min) / range) * (height - 4) - 2;
    return [x, y];
  });
  const path = pts.map((p, i) => (i === 0 ? `M ${p[0]} ${p[1]}` : `L ${p[0]} ${p[1]}`)).join(' ');
  const area = path + ` L ${width} ${height} L 0 ${height} Z`;
  const stroke = dir === 'up'
    ? 'var(--color-success)'
    : dir === 'down' ? 'var(--color-error)' : 'var(--text-muted)';
  const fill = dir === 'up'
    ? 'var(--market-positive-soft)'
    : dir === 'down' ? 'var(--market-negative-soft)' : 'var(--bg-secondary)';
  const last = pts[pts.length - 1];
  return (
    <svg className="spark" width={width} height={height} viewBox={`0 0 ${width} ${height}`} aria-hidden="true" focusable="false">
      <path d={area} fill={fill} />
      <path d={path} fill="none" stroke={stroke} strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={last[0]} cy={last[1]} r="2.2" fill={stroke} />
    </svg>
  );
}

function Delta({ dir, label }) {
  if (!label) return null;
  const cls = dir === 'up' ? 'delta delta--up' : dir === 'down' ? 'delta delta--down' : 'delta';
  return (
    <span className={cls}>
      {dir !== 'flat' && <svg width="9" height="9" viewBox="0 0 10 10" aria-hidden="true">
        {dir === 'up'
          ? <path d="M5 1 L9 8 L1 8 Z" fill="currentColor" />
          : <path d="M5 9 L9 2 L1 2 Z" fill="currentColor" />}
      </svg>}
      {label}
    </span>
  );
}

function MarketSource({ figure }) {
  if (!figure?.source) return null;
  return (
    <div className="mp-cell__meta">
      <a className="mp-cell__source" href={figure.source.url}>
        {formatMarketDate(figure.asOf)} · {figure.source.name}
      </a>
      {figure.status === 'stale' && <span className="mp-cell__stale">Delayed</span>}
    </div>
  );
}

function MarketMetric({ figure, loading, error }) {
  if (loading || error || !figure) {
    return (
      <div className="mp-metric mp-metric--unavailable" role={error ? 'alert' : 'status'}>
        <span className="mp-metric__value">—</span>
        <span className="mp-metric__status">
          {loading ? 'Loading latest figure…' : error ? 'Temporarily unavailable' : 'Awaiting first observation'}
        </span>
      </div>
    );
  }

  const dir = marketDirection(figure.changePercent);
  const history = figure.history.map((point) => point.value);

  return (
    <div className="mp-metric">
      <div className="mp-metric__head">
        <span className="mp-metric__value">{formatMarketValue(figure)}</span>
        <span className="mp-metric__unit">{figure.unit}</span>
      </div>
      <div className="mp-metric__foot">
        <Delta dir={dir} label={formatMarketChange(figure.changePercent)} />
        <Sparkline data={history} dir={dir} />
      </div>
      <MarketSource figure={figure} />
    </div>
  );
}

/* ============================================================
   Market Pulse strip (replaces right-rail sidebar)
   ============================================================ */
function MarketPulse({ data, loading, error, onRetry }) {
  const fxTop = data.exchangeRates.slice(0, 4);
  return (
    <section className="market-pulse" aria-label="Market pulse">
      <div className="container container--wide">
        <div className="market-pulse__grid">
          <div className="mp-cell mp-cell--broker">
            <span className="mp-cell__eyebrow">Offshore contact</span>
            <div className="mp-office">
              <div className="mp-office__location">{MD.OFFSHORE_DESK.location}</div>
              <div className="mp-office__contact">
                <a href={`tel:${MD.OFFSHORE_DESK.phone.replace(/\s/g,'')}`}>{MD.OFFSHORE_DESK.phone}</a>
                <a href={`mailto:${MD.OFFSHORE_DESK.email}`}>{MD.OFFSHORE_DESK.email}</a>
              </div>
            </div>
          </div>

          <div className="mp-cell">
            <span className="mp-cell__eyebrow">Oil · {data.oil?.label || 'Brent crude'}</span>
            <MarketMetric figure={data.oil} loading={loading} error={error} />
          </div>

          <div className="mp-cell">
            <span className="mp-cell__eyebrow">Bunker · {data.bunker?.label || 'BIX World MGO'}</span>
            <MarketMetric figure={data.bunker} loading={loading} error={error} />
          </div>

          <div className="mp-cell mp-cell--fx">
            <span className="mp-cell__eyebrow">Exchange Rates</span>
            <table className="mp-fx">
              <caption className="sr-only">Latest exchange rates and previous-observation changes</caption>
              <tbody>
                {fxTop.map(r => (
                  <tr key={r.key}>
                    <td className="mp-fx__pair">{r.label}</td>
                    <td className="mp-fx__value">{formatMarketValue(r)}</td>
                    <td className="mp-fx__spark">
                      <Sparkline data={r.history.map((point) => point.value)} dir={marketDirection(r.changePercent)} width={56} height={18} />
                    </td>
                    <td className="mp-fx__delta"><Delta dir={marketDirection(r.changePercent)} label={formatMarketChange(r.changePercent)} /></td>
                  </tr>
                ))}
              </tbody>
            </table>
            {(loading || error || fxTop.length === 0) && (
              <div className="mp-fx__state" role={error ? 'alert' : 'status'}>
                {loading ? 'Loading exchange rates…' : error ? 'Exchange rates are temporarily unavailable.' : 'Awaiting first observations.'}
                {error && <button type="button" className="mp-fx__retry" onClick={onRetry}>Try again</button>}
              </div>
            )}
            {fxTop[0] && <MarketSource figure={fxTop[0]} />}
          </div>
        </div>
      </div>
    </section>
  );
}

/* ============================================================
   Vessel drawer
   ============================================================ */
function LegacyVesselDrawer({ vessel, onClose }) {
  const open = !!vessel;
  // Lock scroll when open
  useEffect(() => {
    document.body.style.overflow = open ? 'hidden' : '';
    document.body.classList.toggle('has-vessel-drawer', open);
    return () => {
      document.body.style.overflow = '';
      document.body.classList.remove('has-vessel-drawer');
    };
  }, [open]);

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

  // Use vessel from previous render while closing to avoid blank flash
  const lastRef = useRef(vessel);
  if (vessel) lastRef.current = vessel;
  const v = lastRef.current;

  const p = v?.particulars || {};

  return (
    <>
      <div className={'drawer-backdrop' + (open ? ' is-open' : '')} onClick={onClose} />
      <aside className={'drawer' + (open ? ' is-open' : '')} aria-hidden={!open}>
        {v && (
          <>
            <header className="drawer__head">
              <div className="drawer__heading-block">
                <span className="drawer__eyebrow">Vessel Detail · {v.region}</span>
                <h2 className="drawer__title">{v.vessel}</h2>
              </div>
              <button className="drawer__close" onClick={onClose} aria-label="Close vessel detail">
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round">
                  <path d="M6 6 L18 18 M18 6 L6 18" />
                </svg>
              </button>
            </header>

            <div className="drawer__body">
              {/* Particulars */}
              <section>
                <h3 className="drawer__section-title">Particulars</h3>
                <div className="vessel-photo" aria-hidden="true">
                  <img className="vessel-photo__img" src="assets/vessel-photo.jpg" alt="" width="800" height="449" loading="lazy" />
                  <div className="vessel-photo__label">{v.vessel} · {p.type || '—'} · Built {p.built || '—'}</div>
                </div>
                <div className="particulars" style={{marginTop:'var(--space-4)'}}>
                  <div className="particulars__cell"><span className="particulars__label">Class</span><span className="particulars__value">{p.class || '—'}</span></div>
                  <div className="particulars__cell"><span className="particulars__label">Deck</span><span className="particulars__value">{p.deck || (v.deck ? v.deck + ' m²' : '—')}</span></div>
                  <div className="particulars__cell"><span className="particulars__label">Design</span><span className="particulars__value">{p.design || '—'}</span></div>
                  <div className="particulars__cell"><span className="particulars__label">DWT</span><span className="particulars__value">{p.dwt || '—'}</span></div>
                  <div className="particulars__cell"><span className="particulars__label">Built</span><span className="particulars__value">{p.built || '—'}</span></div>
                  <div className="particulars__cell"><span className="particulars__label">BHP</span><span className="particulars__value">{p.bhp || '—'}</span></div>
                  <div className="particulars__cell"><span className="particulars__label">Type</span><span className="particulars__value">{p.type || '—'}</span></div>
                  <div className="particulars__cell"><span className="particulars__label">DP</span><span className="particulars__value">{p.dp || '—'}</span></div>
                  <div className="particulars__cell"><span className="particulars__label">Flag</span><span className="particulars__value">{p.flag || '—'}</span></div>
                  <div className="particulars__cell"><span className="particulars__label">BP</span><span className="particulars__value">{p.bp || '—'}</span></div>
                </div>
              </section>

              <div className="drawer__divider" />

              {/* Live AIS */}
              <section>
                <h3 className="drawer__section-title">
                  <span className="dot" /> Live AIS Location
                </h3>
                <div className="map">
                  <img className="map__img" src="assets/ais-map.png" alt="Live AIS position" width="466" height="363" loading="lazy" />
                </div>
                <div className="map__legend-row">
                  <span className="map__legend-item"><span className="map__legend-dot map__legend-dot--vessel" /> Vessel</span>
                  <span className="map__legend-item"><span className="map__legend-dot map__legend-dot--rig" /> Rig</span>
                  <span className="map__legend-item"><span className="map__legend-swatch map__legend-swatch--block" /> Blocks</span>
                  <span className="map__legend-item"><span className="map__legend-swatch map__legend-swatch--quadrant" /> Quadrants</span>
                  <span className="map__legend-item"><span className="map__legend-swatch map__legend-swatch--field" /> Oilfield</span>
                </div>
                <p className="map__hint">Expand the map to view data-point information.</p>
              </section>

              {/* Status strip + identifiers */}
              <section>
                <div className="status-strip">
                  <div className="status-strip__head">Moored</div>
                  <div className="status-strip__cell">
                    <div className="status-strip__label">Speed</div>
                    <div className="status-strip__value">0 <span style={{fontSize:'12px',color:'var(--text-muted)'}}>kn</span></div>
                  </div>
                  <div className="status-strip__cell">
                    <div className="status-strip__label">Heading</div>
                    <div className="status-strip__value">322°</div>
                  </div>
                  <div className="status-strip__cell">
                    <div className="status-strip__label">Course</div>
                    <div className="status-strip__value">6.9°</div>
                  </div>
                </div>
                <div className="ident-row">
                  <div className="ident-row__cell">
                    <div className="ident-row__label">MMSI</div>
                    <div className="ident-row__value">257803000</div>
                  </div>
                  <div className="ident-row__cell">
                    <div className="ident-row__label">IMO</div>
                    <div className="ident-row__value">9765469</div>
                  </div>
                  <div className="ident-row__cell">
                    <div className="ident-row__label">Call Sign</div>
                    <div className="ident-row__value">LGXQ</div>
                  </div>
                </div>
              </section>

              {/* Mandate */}
              {(v.current || v.next) && (
                <section>
                  <h3 className="drawer__section-title">Current &amp; Next Mandate</h3>
                  <div style={{display:'grid',gap:'var(--space-3)',fontSize:'var(--text-sm)'}}>
                    {v.current && (
                      <div>
                        <div style={{fontSize:'10px',letterSpacing:'var(--tracking-widest)',textTransform:'uppercase',color:'var(--text-muted)',marginBottom:'4px'}}>Current</div>
                        <div style={{color:'var(--text-primary)'}}>{v.current}</div>
                      </div>
                    )}
                    {v.next && (
                      <div>
                        <div style={{fontSize:'10px',letterSpacing:'var(--tracking-widest)',textTransform:'uppercase',color:'var(--text-muted)',marginBottom:'4px'}}>Next Charterer</div>
                        <div style={{color:'var(--text-primary)'}}>{v.next}</div>
                      </div>
                    )}
                    {v.status && (
                      <div>
                        <div style={{fontSize:'10px',letterSpacing:'var(--tracking-widest)',textTransform:'uppercase',color:'var(--text-muted)',marginBottom:'4px'}}>Status</div>
                        <StatusFull status={v.status} where={v.where} />
                      </div>
                    )}
                  </div>
                </section>
              )}
            </div>
          </>
        )}
      </aside>
    </>
  );
}

function formatMeasurement(value, unit, maximumFractionDigits = 0) {
  if (value == null) return '—';
  return `${new Intl.NumberFormat('en-GB', { maximumFractionDigits }).format(value)} ${unit}`;
}

function formatDateTime(value) {
  if (!value) return '—';
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return value;
  return new Intl.DateTimeFormat('en-GB', {
    day: '2-digit', month: 'short', hour: '2-digit', minute: '2-digit',
    timeZone: 'Europe/Oslo', timeZoneName: 'short',
  }).format(date);
}

function VesselMap({ ais, vesselName }) {
  const containerRef = useRef(null);
  const [mapError, setMapError] = useState(null);

  useEffect(() => {
    const mapbox = window.mapboxgl;
    const token = rootElement.dataset.mapboxToken;
    const longitude = ais?.longitude;
    const latitude = ais?.latitude;

    if (!containerRef.current || longitude == null || latitude == null) return undefined;
    if (!mapbox || !token || !mapbox.supported()) {
      setMapError('Interactive map unavailable');
      return undefined;
    }

    setMapError(null);
    const map = new mapbox.Map({
      accessToken: token,
      container: containerRef.current,
      style: 'mapbox://styles/mapbox/standard',
      center: [longitude, latitude],
      zoom: 7,
      attributionControl: true,
      cooperativeGestures: true,
    });
    const beacon = document.createElement('span');
    beacon.className = 'ais-beacon';
    beacon.setAttribute('aria-hidden', 'true');
    const marker = new mapbox.Marker({ element: beacon, anchor: 'center' })
      .setLngLat([longitude, latitude])
      .addTo(map);
    map.addControl(new mapbox.NavigationControl({ showCompass: false }), 'top-right');
    const onError = () => setMapError('Interactive map unavailable');
    map.on('error', onError);

    return () => {
      map.off('error', onError);
      marker.remove();
      map.remove();
    };
  }, [ais?.latitude, ais?.longitude]);

  if (mapError) {
    return (
      <div className="map map--fallback" role="img" aria-label={`${vesselName} AIS position`}>
        <span>{mapError}</span>
        <strong>{ais.latitude.toFixed(4)}, {ais.longitude.toFixed(4)}</strong>
      </div>
    );
  }

  return (
    <div
      ref={containerRef}
      className="map map__canvas"
      role="region"
      aria-label={`${vesselName} live AIS position near ${ais.region || 'the reported location'}`}
    />
  );
}

function VesselDetailsDrawer({ selection, onClose }) {
  const open = !!selection;
  const drawerRef = useRef(null);
  const closeRef = useRef(null);
  const lastSelectionRef = useRef(selection);
  const [reloadKey, setReloadKey] = useState(0);
  const [vesselState, setVesselState] = useState({ loading: false, error: null, detail: null });

  if (selection) lastSelectionRef.current = selection;
  const shownSelection = selection || lastSelectionRef.current;

  useEffect(() => {
    if (!selection?.imo) return undefined;
    const controller = new AbortController();
    setVesselState({ loading: true, error: null, detail: null });
    marketClient.loadVessel(selection.imo, controller.signal)
      .then((detail) => setVesselState({ loading: false, error: null, detail }))
      .catch((error) => {
        if (error.name !== 'AbortError') setVesselState({ loading: false, error, detail: null });
      });
    return () => controller.abort();
  }, [selection?.imo, reloadKey]);

  useEffect(() => {
    document.body.style.overflow = open ? 'hidden' : '';
    document.body.classList.toggle('has-vessel-drawer', open);
    return () => {
      document.body.style.overflow = '';
      document.body.classList.remove('has-vessel-drawer');
    };
  }, [open]);

  useEffect(() => {
    if (!open) return undefined;
    const previousFocus = document.activeElement;
    closeRef.current?.focus();

    const onKeyDown = (event) => {
      if (event.key === 'Escape') {
        event.preventDefault();
        onClose();
        return;
      }
      if (event.key !== 'Tab' || !drawerRef.current) return;
      const focusable = Array.from(drawerRef.current.querySelectorAll(
        'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])',
      ));
      if (focusable.length === 0) return;
      const first = focusable[0];
      const last = focusable[focusable.length - 1];
      if (event.shiftKey && document.activeElement === first) {
        event.preventDefault();
        last.focus();
      } else if (!event.shiftKey && document.activeElement === last) {
        event.preventDefault();
        first.focus();
      }
    };

    document.addEventListener('keydown', onKeyDown);
    return () => {
      document.removeEventListener('keydown', onKeyDown);
      previousFocus?.focus?.();
    };
  }, [open, onClose]);

  const detail = vesselState.detail;
  const ais = detail?.ais;
  const imageUrl = detail?.imageUrl ? marketClient.absoluteUrl(detail.imageUrl) : null;
  const owner = detail?.owner || '—';
  const particulars = detail ? [
    ['Type', detail.type || '—'],
    ['Built', detail.built ?? '—'],
    ['Design', detail.design || '—'],
    ['Flag', detail.flag || '—'],
    ['DP', detail.dpClass || '—'],
    ['BHP', formatMeasurement(detail.bhp, 'HP')],
    ['BP', formatMeasurement(detail.bollardPullT, 't')],
    ['DWT', formatMeasurement(detail.dwtT, 't')],
    ['Deck', formatMeasurement(detail.deckAreaM2, 'm²')],
    ['Crane', formatMeasurement(detail.craneCapacityT, 't')],
    ['LOA', formatMeasurement(detail.loaM, 'm', 1)],
    ['Beam', formatMeasurement(detail.beamM, 'm', 1)],
    ['Draught', formatMeasurement(detail.draughtM, 'm', 1)],
    ['Accommodation', detail.accommodationPax == null ? '—' : `${detail.accommodationPax} pax`],
  ] : [];

  return (
    <>
      <div className={'drawer-backdrop' + (open ? ' is-open' : '')} onClick={onClose} aria-hidden="true" />
      <aside
        ref={drawerRef}
        className={'drawer' + (open ? ' is-open' : '')}
        role="dialog"
        aria-modal="true"
        aria-hidden={!open}
        aria-labelledby="vessel-detail-title"
      >
        {shownSelection && (
          <>
            <header className="drawer__head">
              <div className="drawer__heading-block">
                <span className="drawer__eyebrow">Vessel Detail · {shownSelection.region}</span>
                <h2 className="drawer__title" id="vessel-detail-title">
                  {detail?.name || shownSelection.vesselName}
                </h2>
              </div>
              <button ref={closeRef} type="button" className="drawer__close" onClick={onClose} aria-label="Close vessel details">
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" aria-hidden="true">
                  <path d="M6 6 L18 18 M18 6 L6 18" />
                </svg>
              </button>
            </header>

            <div className="drawer__body">
              {vesselState.loading && <div className="drawer__state" role="status">Loading vessel details…</div>}
              {vesselState.error && (
                <div className="drawer__state" role="alert">
                  <span>Vessel details are temporarily unavailable.</span>
                  <button type="button" className="data-state__retry" onClick={() => setReloadKey((key) => key + 1)}>Try again</button>
                </div>
              )}

              {detail && (
                <>
                  <section>
                    <h3 className="drawer__section-title">Particulars</h3>
                    {imageUrl ? (
                      <div className="vessel-photo">
                        <img
                          className="vessel-photo__img"
                          src={imageUrl}
                          alt={`${detail.name} offshore vessel`}
                          width="800"
                          height="450"
                          loading="lazy"
                        />
                        <div className="vessel-photo__label">{detail.name} · {detail.type} · Built {detail.built || '—'}</div>
                      </div>
                    ) : (
                      <div className="vessel-photo vessel-photo--empty">No public vessel image</div>
                    )}
                    <div className="particulars drawer__particulars">
                      <div className="particulars__owner">
                        <span className="particulars__label">Owner</span>
                        <span className="particulars__value">{owner}</span>
                      </div>
                      <div className="particulars__grid">
                        {particulars.map(([label, value]) => (
                          <div className="particulars__cell" key={label}>
                            <span className="particulars__label">{label}</span>
                            <span className="particulars__value">{value}</span>
                          </div>
                        ))}
                      </div>
                    </div>
                  </section>

                  {ais && ais.latitude != null && ais.longitude != null && (
                    <>
                      <div className="drawer__divider" />
                      <section>
                        <h3 className="drawer__section-title"><span className="dot" /> Live AIS Location</h3>
                        <VesselMap ais={ais} vesselName={detail.name} />
                        <p className="map__hint">
                          {ais.region || 'Reported position'}{ais.subregion ? ` · ${ais.subregion}` : ''} · Signal {formatDateTime(ais.signalReceivedAt)}
                        </p>
                        <div className="status-strip">
                          <div className="status-strip__head">{(ais.speedOverGround || 0) > 0.5 ? 'Under way' : 'Stationary'} · {ais.freshness}</div>
                          <div className="status-strip__cell">
                            <div className="status-strip__label">Speed</div>
                            <div className="status-strip__value">{ais.speedOverGround ?? '—'} <span className="status-strip__unit">kn</span></div>
                          </div>
                          <div className="status-strip__cell">
                            <div className="status-strip__label">Heading</div>
                            <div className="status-strip__value">{ais.heading == null ? '—' : `${ais.heading}°`}</div>
                          </div>
                          <div className="status-strip__cell">
                            <div className="status-strip__label">Course</div>
                            <div className="status-strip__value">{ais.courseOverGround == null ? '—' : `${ais.courseOverGround}°`}</div>
                          </div>
                        </div>
                        <div className="ident-row">
                          <div className="ident-row__cell"><div className="ident-row__label">MMSI</div><div className="ident-row__value">{detail.mmsi || '—'}</div></div>
                          <div className="ident-row__cell"><div className="ident-row__label">IMO</div><div className="ident-row__value">{detail.imo}</div></div>
                          <div className="ident-row__cell"><div className="ident-row__label">Destination</div><div className="ident-row__value">{ais.destination || '—'}</div></div>
                        </div>
                        {ais.eta && <p className="drawer__eta">Reported ETA · {formatDateTime(ais.eta)}</p>}
                      </section>
                    </>
                  )}

                  {(shownSelection.current || shownSelection.next || shownSelection.status) && (
                    <>
                      <div className="drawer__divider" />
                      <section>
                        <h3 className="drawer__section-title">Current &amp; Next Mandate</h3>
                        <div className="mandate-grid">
                          {shownSelection.current && <div><span className="mandate-grid__label">Current</span><span>{shownSelection.current}</span></div>}
                          {shownSelection.next && <div><span className="mandate-grid__label">Next Charterer</span><span>{shownSelection.next}</span></div>}
                          {shownSelection.status && <div><span className="mandate-grid__label">Status</span><PositionStatus status={shownSelection.status} /></div>}
                        </div>
                      </section>
                    </>
                  )}
                </>
              )}
            </div>
          </>
        )}
      </aside>
    </>
  );
}

/* ============================================================
   Top-level app
   ============================================================ */
function App() {
  const [selected, setSelected] = useState(null);
  const [reloadKey, setReloadKey] = useState(0);
  const [market, setMarket] = useState({
    loading: true,
    error: null,
    data: {
      fixtures: { spot: [], term: [] },
      requirements: { spot: [], term: [] },
      positionViews: [],
      generatedAt: null,
    },
  });
  const [keyFigures, setKeyFigures] = useState({
    loading: true,
    error: null,
    data: { generatedAt: null, oil: null, bunker: null, exchangeRates: [] },
  });

  const retry = useCallback(() => setReloadKey((key) => key + 1), []);

  useEffect(() => {
    const controller = new AbortController();
    setMarket((current) => ({ ...current, loading: true, error: null }));
    setKeyFigures((current) => ({ ...current, loading: true, error: null }));

    marketClient.loadMarketData(controller.signal)
      .then((data) => setMarket({ loading: false, error: null, data }))
      .catch((error) => {
        if (error.name !== 'AbortError') {
          setMarket((current) => ({ ...current, loading: false, error }));
        }
      });

    marketClient.loadKeyFigures(controller.signal)
      .then((data) => setKeyFigures({ loading: false, error: null, data }))
      .catch((error) => {
        if (error.name !== 'AbortError') {
          setKeyFigures((current) => ({ ...current, loading: false, error }));
        }
      });

    return () => controller.abort();
  }, [reloadKey]);

  const { data, loading, error } = market;
  return (
    <div className="page">
      <a className="skip-link" href="#main-content">Skip to main content</a>
      <header className="site-header">
        <div className="container container--wide site-header__wrap">
          <a href="/" className="site-header__logo">
            <img src="assets/mcp-logo.svg" alt="Maritime Capital Partners" width="1303" height="499" />
          </a>
          <nav className="site-header__nav">
            <a className="site-header__nav-link" href="/">Home</a>
            <a className="site-header__nav-link" href="/#services">Services</a>
            <a className="site-header__nav-link is-active" href="/services/offshore/" aria-current="page">Offshore Market</a>
            <a className="site-header__nav-link" href="/#approach">Approach</a>
            <a className="site-header__nav-link" href="/#track-record">Track Record</a>
            <a className="site-header__nav-link" href="/#global">Global</a>
            <a className="site-header__nav-link" href="/#contact">Contact</a>
          </nav>
        </div>
      </header>

      <section className="page-intro" aria-labelledby="offshore-market-heading">
        <div className="container container--wide page-intro__grid">
          <div>
            <span className="section-block__eyebrow">Offshore Market Data</span>
            <h1 className="page-intro__heading" id="offshore-market-heading">North Sea &amp; UK <em>Continental Shelf</em></h1>
            <p className="page-intro__sub">A consolidated view of recent fixtures, open charterer requirements, and live vessel positions across the AHTS, PSV, and standby segments.</p>
          </div>
          <div className="page-intro__meta">
            <span><span className="page-intro__meta-dot" />Live</span>
            <span className="page-intro__meta-value">
              {loading ? 'Loading latest publication…' : formatGeneratedAt(data.generatedAt)}
            </span>
            <span>Published from MCP Helm</span>
          </div>
        </div>
      </section>

      <MarketPulse
        data={keyFigures.data}
        loading={keyFigures.loading}
        error={keyFigures.error}
        onRetry={retry}
      />

      <main className="layout" id="main-content">
        <div className="container container--wide">
          <FixturesSection
            datasets={data.fixtures}
            loading={loading}
            error={error}
            onRetry={retry}
            generatedAt={data.generatedAt}
          />
          <RequirementsSection
            datasets={data.requirements}
            loading={loading}
            error={error}
            onRetry={retry}
            generatedAt={data.generatedAt}
          />
          {loading || error || data.positionViews.length === 0 ? (
            <section className="section-block" id="positions">
              <div className="section-block__head">
                <div className="section-block__title-wrap"><Eyebrow>Published Positions</Eyebrow></div>
              </div>
              <DataState
                loading={loading}
                error={error}
                empty={data.positionViews.length === 0}
                onRetry={retry}
                emptyMessage="No position lists are currently published."
              />
            </section>
          ) : data.positionViews.map((view, index) => (
            <PositionsSection
              key={`${index}-${view.name}`}
              view={view}
              index={index}
              onSelect={setSelected}
              selectedKey={selected?._key}
            />
          ))}
        </div>
      </main>

      <footer className="page-foot">
        <div className="container container--wide" style={{display:'flex',justifyContent:'space-between',width:'100%',gap:'var(--space-4)',flexWrap:'wrap'}}>
          <span>(c) 2026 Maritime Capital Partners. Indicative data - for discussion purposes.</span>
          <span>Greenwich · Dubai · Kristiansand</span>
        </div>
      </footer>

      <VesselDetailsDrawer selection={selected} onClose={() => setSelected(null)} />
    </div>
  );
}

ReactDOM.createRoot(rootElement).render(<App />);
