// Thin view for the landing page's installer section. It reads the browser's
// platform, asks the pure model (lib/site-install.ts) which build to offer using
// the shared release catalog, and renders the result. All decisions live in the
// model and are unit-tested; this file only touches the DOM and `navigator`.

import {
  detectPlatform,
  buildInstallerOffer,
  type InstallerOffer,
  type InstallerDownload,
} from '@/lib/site-install';
import { HOST_ARTIFACTS, EXPECTED_HOST_VERSION } from '@/lib/host-release';
import { escapeHtml } from '@/lib/escape-html';

// Minimal shape of the (still-experimental) userAgentData high-entropy API, so
// this stays typed without pulling in a browser lib that doesn't ship it yet.
interface UAHints {
  architecture?: string;
  bitness?: string;
}
interface UADataLike {
  getHighEntropyValues?: (hints: string[]) => Promise<UAHints>;
}

/** Build the detection string: the UA plus architecture/bitness hints when the
 *  browser exposes them, because a stock macOS UA can't reveal Apple Silicon. */
async function detectionString(): Promise<string> {
  const parts = [navigator.userAgent];
  const uaData = (navigator as unknown as { userAgentData?: UADataLike }).userAgentData;
  if (uaData?.getHighEntropyValues) {
    try {
      const hints = await uaData.getHighEntropyValues(['architecture', 'bitness']);
      if (hints.architecture) parts.push(hints.architecture);
      if (hints.bitness === '64') parts.push('x64');
    } catch {
      // Hints are best-effort; without them the model degrades to a choices list.
    }
  }
  return parts.join(' ');
}

function downloadButton(d: InstallerDownload, cls: string): string {
  return `<a class="${cls}" href="${escapeHtml(d.url)}">${escapeHtml(d.label)}</a>`;
}

function render(offer: InstallerOffer): string {
  if (offer.kind === 'coming-soon') {
    return `<p class="installer-soon">
      Signed installers are on the way. Check back soon — this page will offer the
      right download for your system automatically.
    </p>`;
  }

  if (offer.kind === 'primary') {
    const fallbacks = offer.fallbacks
      .map((d) => `<li>${downloadButton(d, 'installer-choice')}</li>`)
      .join('');
    return `
      <div class="installer-primary">
        <a class="btn btn-primary" href="${escapeHtml(offer.primary.url)}">
          Download for ${escapeHtml(offer.primary.label)}
        </a>
        <span class="installer-version">helper v${escapeHtml(offer.primary.version)}</span>
      </div>
      <div class="installer-fallbacks">
        <p class="installer-fallbacks-label">Other platforms</p>
        <ul class="installer-list">${fallbacks}</ul>
      </div>`;
  }

  // choices — platform unknown or unlisted: offer every build, no primary.
  const choices = offer.choices
    .map((d) => `<li>${downloadButton(d, 'installer-choice')}</li>`)
    .join('');
  return `
    <p class="installer-fallbacks-label">Choose your platform</p>
    <ul class="installer-list">${choices}</ul>`;
}

async function mount(): Promise<void> {
  const el = document.querySelector<HTMLDivElement>('#installer');
  if (!el) return;
  const platform = detectPlatform(await detectionString());
  const offer = buildInstallerOffer(HOST_ARTIFACTS, EXPECTED_HOST_VERSION, platform);
  el.dataset.state = offer.kind;
  el.innerHTML = render(offer);
}

void mount();
