(() => {
  const TOUR_KEY = 'nv_monitor_mini_tour_seen';
  const AUX_URL = 'https://nodarama.com/coding.html#download';
  const INFO_URL = 'https://nodarama.com/info.html#onboarding';
  const CONTRACT_URL = '/docs/VerbatimRecordingContract.txt';
  const CONTRACT_API = '/docs/recording-contract';

  const byId = id => document.getElementById(id);
  const esc = value => String(value ?? '')
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;');

  const steps = [
    {
      target: '#deck-monitor-stack',
      title: 'Centre Console',
      text: 'This is your control deck. Review status updates, see system activity, and use heads-up controls. Below, read system messages to see what has been recently processed.'
    },
    {
      target: '#input-field',
      title: 'Input Field',
      text: 'Verbatim uses Recording Sheets: structured code instructions AI can produce in Verbatim format. You can paste a Recording Sheet here. If you are running a local AI through LM Studio, you can also send it a message from here.'
    },
    {
      target: '#tabs',
      title: 'Navigation',
      text: 'These are your main navigation tabs. Access project details, a code editor, recent dubs, recommended enhancements and diagnostics, full history, and settings.'
    },
    {
      target: '#project-display',
      title: 'Project Display',
      text: 'The active project is displayed at the top. Project cards let you select which project you are working on. Guardrails keep work inside the active project, keeping Verbatim focused on the task and protecting your system and other projects from unwanted changes.'
    },
    {
      target: ['#nv-launch-sign-in-btn', '#launch-create-open-btn', '#launch-project-name-inline', '#launch-project-name', '#project-display'],
      title: 'Start Up',
      text: 'You are ready to sign in, or begin your first project. Use our onboarding guide to try a guided project, or for the fastest start, grab the Recording Sheet, give it to your AI of choice, and start pasting manifests. Recommended: install the AUX Chrome Extension, then follow onboarding.'
    }
  ];

  let blurPanes = [];
  let index = 0;
  let overlay = null;
  let card = null;
  let highlight = null;

  function toast(msg) {
    window.toast?.(msg);
  }

  function appendLog(text, tone = 'neutral') {
    window.appendLog?.(text, tone);
  }

  async function callApi(path, method = 'GET', body = null) {
    if (typeof window.api !== 'function') return null;
    return await window.api(path, method, body);
  }

  async function copyInputContract() {
    const data = await callApi(CONTRACT_API);
    const text = typeof data === 'string' ? data : String(data?.text || data?.content || '');
    if (!text) {
      toast('Recording Sheet unavailable');
      return false;
    }
    try {
      await navigator.clipboard.writeText(text);
      toast('Recording Sheet copied');
      appendLog('⧉ recording sheet copied from tour', 'pass');
      return true;
    } catch {
      toast('Copy failed');
      appendLog('✗ recording sheet copy failed from tour', 'fail');
      return false;
    }
  }

  function injectStyles() {
    if (byId('nv-tour-style')) return;
    const style = document.createElement('style');
    style.id = 'nv-tour-style';
    style.textContent = `
      .nv-tour-overlay{position:fixed;inset:0;z-index:10000;pointer-events:none;background:transparent;opacity:0;animation:nvTourFadeIn .22s ease forwards}
      .nv-tour-overlay.closing{animation:nvTourFadeOut .18s ease forwards}
      .nv-tour-blur-pane{position:fixed;background:rgba(0,0,0,.34);backdrop-filter:blur(2px);-webkit-backdrop-filter:blur(2px);pointer-events:none;transition:all .22s ease}
      .nv-tour-highlight{position:fixed;border:2px solid rgba(245,145,64,.96);box-shadow:0 0 42px rgba(245,145,64,.32),inset 0 0 0 1px rgba(255,255,255,.18);border-radius:16px;pointer-events:none;transition:all .22s ease}
      .nv-tour-card{box-sizing:border-box;position:fixed;width:min(470px,calc(100vw - 36px));background:linear-gradient(145deg,#f4772f 0%,#d94f1f 100%);border:1px solid rgba(255,255,255,.32);box-shadow:0 26px 62px rgba(0,0,0,.42),0 0 0 1px rgba(80,28,10,.18) inset;border-radius:24px;padding:28px 30px 24px;color:#fff;font:500 20px/1.32 Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;letter-spacing:-.012em;pointer-events:auto;opacity:0;transform:translateY(8px);animation:nvTourCardIn .24s ease forwards}
      .nv-tour-title{color:#fff;font-size:15px;font-weight:800;letter-spacing:.13em;margin:0 0 12px;text-transform:uppercase;text-shadow:0 1px 1px rgba(0,0,0,.18)}
      .nv-tour-text{margin:0;color:#fff;font-size:24px;font-weight:750;line-height:1.22;text-wrap:balance;text-shadow:0 2px 10px rgba(0,0,0,.18)}
      .nv-tour-actions{display:flex;gap:10px;align-items:center;justify-content:flex-end;margin-top:24px;flex-wrap:wrap}
      .nv-tour-actions a,.nv-tour-actions button{border:1px solid rgba(255,255,255,.58);background:rgba(255,255,255,.16);color:#fff;border-radius:999px;padding:10px 15px;font:800 12px/1 Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;letter-spacing:.08em;text-transform:uppercase;text-decoration:none;cursor:pointer;box-shadow:0 8px 22px rgba(0,0,0,.14);transition:transform .14s ease,background .14s ease,border-color .14s ease}
      .nv-tour-actions a:hover,.nv-tour-actions button:hover{background:rgba(255,255,255,.26);border-color:rgba(255,255,255,.78);transform:translateY(-1px)}
      .nv-tour-actions .primary{background:#fff;color:#d9531f;border-color:#fff}
      @keyframes nvTourFadeIn{from{opacity:0}to{opacity:1}}
      @keyframes nvTourFadeOut{from{opacity:1}to{opacity:0}}
      @keyframes nvTourCardIn{from{opacity:0;transform:translateY(8px) scale(.985)}to{opacity:1;transform:translateY(0) scale(1)}}
      @media (max-width:560px){.nv-tour-card{padding:22px 22px 20px;font-size:17px}.nv-tour-text{font-size:20px}.nv-tour-title{font-size:13px}.nv-tour-actions{justify-content:flex-start}}
    `;
    document.head.appendChild(style);
  }

  function targetRects(step) {
    const targets = Array.isArray(step.target) ? step.target : [step.target];

    return targets
      .filter(Boolean)
      .map(selector => document.querySelector(selector))
      .filter(el => el && !el.hidden && el.offsetParent !== null)
      .map(el => el.getBoundingClientRect())
      .filter(rect => rect.width > 0 && rect.height > 0);
  }

  function combinedRect(rects) {
    if (!rects.length) return null;

    const left = Math.min(...rects.map(rect => rect.left));
    const top = Math.min(...rects.map(rect => rect.top));
    const right = Math.max(...rects.map(rect => rect.right));
    const bottom = Math.max(...rects.map(rect => rect.bottom));

    return {
      left,
      top,
      right,
      bottom,
      width: right - left,
      height: bottom - top
    };
  }

  function updateBlurPanes(rect) {
    if (!blurPanes.length) return;

    const vw = window.innerWidth;
    const vh = window.innerHeight;
    const box = rect ? {
      left: Math.max(0, Math.min(vw, rect.left)),
      top: Math.max(0, Math.min(vh, rect.top)),
      right: Math.max(0, Math.min(vw, rect.right)),
      bottom: Math.max(0, Math.min(vh, rect.bottom))
    } : { left: vw / 2, top: vh / 2, right: vw / 2, bottom: vh / 2 };

    const panes = [
      { left: 0, top: 0, width: vw, height: box.top },
      { left: 0, top: box.bottom, width: vw, height: Math.max(0, vh - box.bottom) },
      { left: 0, top: box.top, width: box.left, height: Math.max(0, box.bottom - box.top) },
      { left: box.right, top: box.top, width: Math.max(0, vw - box.right), height: Math.max(0, box.bottom - box.top) }
    ];

    panes.forEach((pane, i) => {
      const el = blurPanes[i];
      if (!el) return;
      el.style.left = `${pane.left}px`;
      el.style.top = `${pane.top}px`;
      el.style.width = `${pane.width}px`;
      el.style.height = `${pane.height}px`;
    });
  }

  function place(step) {
    const rect = combinedRect(targetRects(step));
    const margin = 10;
    let focusRect = null;

    if (rect && highlight) {
      const left = Math.max(8, rect.left - margin);
      const top = Math.max(8, rect.top - margin);
      const width = Math.min(window.innerWidth - left - 8, rect.width + margin * 2);
      const height = Math.min(window.innerHeight - top - 8, rect.height + margin * 2);

      focusRect = {
        left,
        top,
        right: left + width,
        bottom: top + height,
        width,
        height
      };

      highlight.hidden = false;
      highlight.style.left = `${focusRect.left}px`;
      highlight.style.top = `${focusRect.top}px`;
      highlight.style.width = `${focusRect.width}px`;
      highlight.style.height = `${focusRect.height}px`;
    } else if (highlight) {
      highlight.hidden = true;
    }

    updateBlurPanes(focusRect);

    if (!card) return;
    if (!rect) {
      card.style.left = '50%';
      card.style.top = '50%';
      card.style.transform = 'translate(-50%,-50%)';
      return;
    }

    card.style.transform = 'none';
    const cardWidth = Math.min(470, window.innerWidth - 36);
    const cardHeight = Math.min(card.offsetHeight || 260, window.innerHeight - 32);
    const viewportPad = 16;
    const below = rect.bottom + 16;
    const above = rect.top - cardHeight - 16;
    const canFitBelow = below + cardHeight + viewportPad <= window.innerHeight;
    const canFitAbove = above >= viewportPad;
    const top = canFitBelow
      ? below
      : canFitAbove
        ? above
        : Math.max(viewportPad, Math.min(window.innerHeight - cardHeight - viewportPad, below));
    const left = Math.max(viewportPad, Math.min(window.innerWidth - cardWidth - viewportPad, rect.left));

    card.style.left = `${left}px`;
    card.style.top = `${top}px`;
  }
  function render() {
    const step = steps[index];
    if (!step || !overlay || !card) return close(true);

    const final = index === steps.length - 1;

    card.innerHTML = `
      <div class="nv-tour-title">${esc(step.title)}</div>
      <p class="nv-tour-text">${esc(step.text)}</p>
      <div class="nv-tour-actions">
        ${final ? '<a href="' + AUX_URL + '" target="_blank" rel="noopener">Install AUX</a><a href="' + INFO_URL + '" target="_blank" rel="noopener">Onboarding</a><a href="' + CONTRACT_URL + '" target="_blank" rel="noopener">Recording Sheet</a>' : ''}
        <button type="button" data-tour-skip>Skip</button>
        <button class="primary" type="button" data-tour-next>${final ? 'Done' : 'Next'}</button>
      </div>
    `;

    card.querySelector('[data-tour-next]')?.addEventListener('click', () => {
      if (final) close(true);
      else {
        index += 1;
        render();
      }
    });

    card.querySelector('[data-tour-skip]')?.addEventListener('click', () => close(true));
    place(step);
  }

function handleTourKeydown(event) {
  if (!overlay) return;
  if (event.repeat) return;

  const key = event.key;

  if (key === 'Escape') {
    event.preventDefault();
    close(true);
    return;
  }

  if (key === 'Enter' || key === ' ') {
    event.preventDefault();

    if (index >= steps.length - 1) {
      close(true);
      return;
    }

    index += 1;
    render();
  }
}

  function open(force = false) {
    if (!force && localStorage.getItem(TOUR_KEY) === '1') return false;

    injectStyles();
    close(false);

    index = 0;
    overlay = document.createElement('div');
    overlay.className = 'nv-tour-overlay';

    blurPanes = Array.from({ length: 4 }, () => {
      const pane = document.createElement('div');
      pane.className = 'nv-tour-blur-pane';
      return pane;
    });

    highlight = document.createElement('div');
    highlight.className = 'nv-tour-highlight';

    card = document.createElement('div');
    card.className = 'nv-tour-card';

    overlay.append(...blurPanes, highlight, card);
    document.body.appendChild(overlay);

    window.removeEventListener('keydown', handleTourKeydown);
    window.addEventListener('keydown', handleTourKeydown);

    render();
    return true;
  }

function close(markSeen = true) {
  if (markSeen) localStorage.setItem(TOUR_KEY, '1');

  window.removeEventListener('keydown', handleTourKeydown);

  const oldOverlay = overlay;
  overlay = null;
  card = null;
  highlight = null;
  blurPanes = [];

  if (!oldOverlay) return;

  oldOverlay.classList.add('closing');
  setTimeout(() => oldOverlay.remove(), 190);
}

  function maybeAutoStart() {
    if (localStorage.getItem(TOUR_KEY) === '1') return;

    const gate = byId('launch-gate');
    if (!gate || !gate.hidden) return;

    setTimeout(() => open(false), 450);
  }

  window.addEventListener('resize', () => {
    if (overlay) place(steps[index]);
  });

  document.addEventListener('DOMContentLoaded', () => {
    setTimeout(maybeAutoStart, 1400);

    const gate = byId('launch-gate');
    if (!gate) return;

    new MutationObserver(maybeAutoStart).observe(gate, {
      attributes: true,
      attributeFilter: ['hidden']
    });
  });

  window.MonitorTour = {
    open: () => open(true),
    close,
    isActive: () => Boolean(overlay),
    copyInputContract
  };
})();