import './styles/tokens.css';
import './styles/base.css';
import './styles/components.css';
import './styles/landing.css';
import './styles/editor.css';
import './styles/legal.css';

// self-hosted fonts (no external CDN → CSP-clean + offline)
import '@fontsource/bricolage-grotesque/400.css';
import '@fontsource/bricolage-grotesque/500.css';
import '@fontsource/bricolage-grotesque/600.css';
import '@fontsource/bricolage-grotesque/700.css';
import '@fontsource/bricolage-grotesque/800.css';
import '@fontsource/instrument-sans/400.css';
import '@fontsource/instrument-sans/500.css';
import '@fontsource/instrument-sans/600.css';
import '@fontsource/instrument-sans/700.css';
// Newsreader serif — used for headings + wordmark on the landing page.
import '@fontsource/newsreader/400.css';
import '@fontsource/newsreader/400-italic.css';
import '@fontsource/newsreader/500.css';
import '@fontsource/newsreader/600.css';
import '@fontsource/newsreader/700.css';

import { h } from './core/dom';
import { registerSW } from 'virtual:pwa-register';

// A file handed off from the landing dropzone to the editor.
let pendingFile: File | null = null;

// Whether the landing has been mounted+wired by JS in the current view. The
// build prerenders the landing markup into #app, so a bare `.landing-folio`
// element exists before any JS runs — we can't infer "interactive" from the
// DOM alone. This flag is set once mountLanding() has wired it up, and cleared
// whenever the editor/legal views replace #app.
let landingMounted = false;

const app = document.getElementById('app')!;

function ensureBackground() {
  if (document.querySelector('.bg-field')) return;
  const bg = h('div.bg-field', h('div.blob b1'), h('div.blob b2'), h('div.blob b3'));
  document.body.prepend(bg);
}

window.addEventListener('yeet:open', (e: Event) => {
  const file = (e as CustomEvent).detail?.file as File | undefined;
  if (file) pendingFile = file;
  if (location.hash !== '#/editor') location.hash = '#/editor';
  else route();
});
window.addEventListener('yeet:home', () => {
  location.hash = '#/';
});

async function route() {
  ensureBackground();
  const hash = location.hash || '#/';
  if (hash.startsWith('#/editor')) {
    landingMounted = false;
    app.innerHTML = '';
    app.appendChild(h('div.editor-loading', h('div.spinner spinner-ink'), h('span', 'Opening editor…')));
    const { mountEditor } = await import('./editor/editor');
    const file = pendingFile;
    pendingFile = null;
    await mountEditor(app, file);
  } else if (hash.startsWith('#/privacy') || hash.startsWith('#/terms')) {
    landingMounted = false;
    const { mountLegal } = await import('./legal/legal');
    mountLegal(app, hash.startsWith('#/privacy') ? 'privacy' : 'terms');
  } else {
    const isAnchor = hash.length > 2 && !hash.startsWith('#/');
    // In-page nav (Features/Privacy/How it works) while already showing the
    // live landing page: don't remount. mountLanding() clears and rebuilds the
    // whole DOM (and resets scroll to the top itself), which raced with the
    // scrollIntoView below — the rebuild-triggered reset could land after the
    // scroll, making the very first click of a session appear to do nothing.
    // We gate on `landingMounted` (JS-wired), not on the presence of
    // `.landing-folio` in the DOM: the build prerenders that element, so on a
    // direct load of an anchor URL (e.g. /#features) it exists but isn't wired
    // yet — we must still mount to attach handlers and start the dot canvas.
    if (!(isAnchor && landingMounted)) {
      const { mountLanding } = await import('./landing/landing');
      mountLanding(app);
      landingMounted = true;
    }
    if (isAnchor) {
      // One frame so a freshly-mounted target has actually been laid out
      // before we measure its position.
      requestAnimationFrame(() => {
        document.querySelector(hash)?.scrollIntoView({ behavior: 'smooth' });
      });
    }
  }
}

window.addEventListener('hashchange', route);
route();

// PWA: keep the app fresh, work offline after first load.
registerSW({ immediate: true });
