// ── LAUNCH / PROJECT GATE ────────────────────────────────────────────────────

window.LaunchState = {
  auth: null,
  settings: null,
  projects: [],
  activeProject: '',
  activeProjectSerial: '',
  backstage: false,
  enteredWorkspace: false,
  signupOpened: false
};

const LaunchState = window.LaunchState;
const MIN_BOOT_SPLASH_MS = 2500;
const MAX_SCREEN_SPLASH_MS = 15000;

function isBackstageAuth(auth) {
  const tier = String(auth?.tier || auth?.accessTier || '').trim().toLowerCase();
  return tier === 'backstage';
}

function isSignedInAuth(auth) {
  return Boolean(auth?.status === 'signed_in' || auth?.authenticated || auth?.userId || auth?.email);
}

async function refreshAccountUI() {
  if (typeof syncAccount === 'function') return await syncAccount();
  return await window.AuthSession?.loadStatus?.() || null;
}

async function enforceAgreementGate(settings, auth) {
  return false;
}
function isRealProject(project) {
  if (!project) return false;
  const name = String(project.name || '').trim().toLowerCase();
  return Boolean(project.serialNo || project.location || project.path) && !['system', 'backstage', 'universal'].includes(name);
}

function launchSetHidden(id, hidden) {
  const el = byId(id);
  if (el) el.hidden = Boolean(hidden);
}

function launchShowOnly(panelId) {
  ['launch-account-required', 'launch-project-select'].forEach(id => {
    launchSetHidden(id, id !== panelId);
  });
}

function setLaunchVisible(visible) {
  const gate = byId('launch-gate');
  if (!gate) return;
  gate.hidden = !visible;
  document.body.classList.toggle('launch-active', Boolean(visible));
}

function setLaunchSubtitle(text) {
  const el = byId('launch-subtitle');
  if (el) el.textContent = text || '';
}

function launchSignedOutMode(enabled) {
  document.body.classList.toggle('auth-signed-out', Boolean(enabled));
  ensureLaunchSignInButton(Boolean(enabled));
}

function ensureLaunchSignInButton(show) {
  let btn = byId('nv-launch-sign-in-btn');

  if (!show) {
    if (btn) btn.hidden = true;
    return;
  }

  if (!btn) {
    btn = document.createElement('button');
    btn.id = 'nv-launch-sign-in-btn';
    btn.type = 'button';
    btn.className = 'launch-sign-in-btn';
    btn.textContent = 'SIGN IN';
    btn.addEventListener('click', () => {
      showSoftAccountGate('manual_sign_in');
    });

    const host =
      byId('project-switch-auth-slot') ||
      byId('project-switch-controls') ||
      byId('project-switcher') ||
      document.querySelector('.project-switch-controls') ||
      document.querySelector('.project-switcher') ||
      document.querySelector('header') ||
      document.body;

    host.appendChild(btn);
  }

  btn.hidden = false;
}

function enterLocalLaunchMode(reason = 'local_mode') {
  LaunchState.enteredWorkspace = true;
  setLaunchVisible(false);
  launchSignedOutMode(true);

  if (typeof appendLog === 'function') appendLog(`⚪ startup continued without account — ${reason}`, 'info');

  if (typeof activateTab === 'function') {
    activateTab('project');
  }
}

function runBootSplash(text, loadTask) {
  const splash = byId('project-switch-splash');
  const label = byId('project-splash-text');
  const tapeFront = byId('project-splash-tape-front');
  const tapeLeft = byId('project-splash-tape-left');
  const tapeRight = byId('project-splash-tape-right');
  const startedAt = Date.now();
  const roll = Math.random();
  const tapeIndex = Math.floor(Math.random() * 5) + 1;
  const variant = roll < 0.65 ? 'eq' : `tape${tapeIndex}`;

  const tapeAssets = {
    front: `/assets/tape${tapeIndex}front.png`,
    tape: `/assets/tape${tapeIndex}tape.png`,
    back: `/assets/tape${tapeIndex}back.png`
  };

  function applySplashImage(img, src, allowMissing = false) {
    if (!img || !src) return;
    img.hidden = false;
    img.removeAttribute('aria-hidden');
    img.onerror = () => {
      if (allowMissing) img.hidden = true;
    };
    img.onload = () => {
      img.hidden = false;
    };
    img.src = src;
  }

  function ensureTapeBackLayer() {
    const stage = tapeFront?.closest?.('.project-splash-tape-stage');
    if (!stage) return null;

    let back = byId('project-splash-tape-back');
    if (!back) {
      back = document.createElement('img');
      back.id = 'project-splash-tape-back';
      back.className = 'project-splash-tape-back';
      back.alt = '';
      back.setAttribute('aria-hidden', 'true');
      stage.insertBefore(back, stage.firstChild);
    }

    Object.assign(back.style, {
      position: 'absolute',
      inset: '0',
      width: '100%',
      height: '100%',
      objectFit: 'contain',
      pointerEvents: 'none',
      userSelect: 'none',
      zIndex: '100'
    });

    return back;
  }

  function positionTapeWheels() {
    const stage = tapeFront?.closest?.('.project-splash-tape-stage');
    if (!stage) return;

    stage.style.setProperty('--splash-wheel-size', '120px');
    stage.style.setProperty('--splash-left-x', '42px');
    stage.style.setProperty('--splash-right-x', '42px');
    stage.style.setProperty('--splash-wheel-y', '60px');

    if (tapeLeft) {
      tapeLeft.style.left = '42px';
      tapeLeft.style.right = 'auto';
      tapeLeft.style.top = '60px';
      tapeLeft.style.width = '120px';
      tapeLeft.style.height = '120px';
      tapeLeft.style.zIndex = '500';
    }

    if (tapeRight) {
      tapeRight.style.left = 'auto';
      tapeRight.style.right = '42px';
      tapeRight.style.top = '60px';
      tapeRight.style.width = '120px';
      tapeRight.style.height = '120px';
      tapeRight.style.zIndex = '500';
    }

    if (tapeFront) {
      tapeFront.style.zIndex = '1000';
    }
  }

  if (label && text) label.textContent = text;

  if (splash) {
    splash.dataset.splashVariant = variant;
    splash.dataset.tapeStyle = variant.startsWith('tape') ? String(tapeIndex) : '';
    splash.classList.add('active');
    splash.setAttribute('aria-hidden', 'false');
  }

  if (variant !== 'eq') {
    const tapeBack = ensureTapeBackLayer();
    applySplashImage(tapeBack, tapeAssets.back, true);
    applySplashImage(tapeLeft, tapeAssets.tape);
    applySplashImage(tapeRight, tapeAssets.tape);
    applySplashImage(tapeFront, tapeAssets.front);
    positionTapeWheels();
  }

  const waitMinimum = () => new Promise(resolve => {
    const elapsed = Date.now() - startedAt;
    setTimeout(resolve, Math.max(0, MIN_BOOT_SPLASH_MS - elapsed));
  });

  const maxScreenWait = new Promise(resolve => {
    setTimeout(() => resolve({ timedOut: true }), MAX_SCREEN_SPLASH_MS);
  });

  const bootWork = Promise.resolve()
    .then(() => loadTask())
    .catch(err => {
      appendLog?.(`⚪ launch work skipped: ${err?.message || err}`, 'warn');
      return { failed: true };
    });

  return Promise.race([bootWork, maxScreenWait])
    .then(result => {
      if (result?.timedOut && !LaunchState.enteredWorkspace) enterLocalLaunchMode('launch_timeout_escape');
      return result;
    })
    .finally(() => waitMinimum().then(() => {
      if (splash) splash.remove();
    }));
}
function projectCardSummary(project) {
  return String(project.summary || project.description || project.notes || 'no recent activity')
    .trim()
    .slice(0, 120);
}

function projectCardMeta(project) {
  const location = String(project.location || project.path || '').trim();
  if (project.updatedAt) return `Updated ${new Date(project.updatedAt).toLocaleDateString()}`;
  if (location) return location;
  return project.serialNo ? `serial ${project.serialNo}` : 'project';
}

function renderLaunchProjectCards(projects) {
  const grid = byId('launch-project-grid');
  if (!grid) return;

  const realProjects = (projects || []).filter(isRealProject);
  grid.innerHTML = realProjects.map((project, index) => {
    const name = esc(project.name || 'Untitled Project');
    const summary = esc(projectCardSummary(project));
    const meta = esc(projectCardMeta(project));
    const serial = esc(project.serialNo || '');
    const color = String((index % 4) + 1);

    return `
      <button class="launch-project-card" type="button" data-launch-project="${serial || esc(project.name || '')}" data-color="${color}">
        <div class="launch-project-card-title">${name}</div>
        <div class="launch-project-card-summary">${summary}</div>
        <div class="launch-project-card-meta">${meta}</div>
      </button>
    `;
  }).join('');

  grid.querySelectorAll('[data-launch-project]').forEach(btn => {
    btn.addEventListener('click', () => {
      const key = btn.getAttribute('data-launch-project') || '';
      void launchSelectProject(key);
    });
  });
}

async function fetchLaunchStatus() {
  const status = await api('/status');
  if (!status?.ok) return status;
  const controller = status.controller?.state || status.controller || {};
  const serial = String(status.activeProjectSerial || status.scopeSerial || controller.projectSerial || '').trim();
  const name = String(status.activeProject || status.project || controller.activeProject || controller.projectName || '').trim();
  const mode = String(status.startupMode || status.projectMode || controller.projectMode || '').trim().toLowerCase();
  if (serial && !LaunchState.activeProjectSerial) LaunchState.activeProjectSerial = serial;
  if (name && !LaunchState.activeProject) LaunchState.activeProject = name;
  if (LaunchState.backstage && (serial === 'system' || serial === '00' || mode === 'system')) {
    LaunchState.activeProjectSerial = 'system';
    LaunchState.activeProject = 'System';
  }
  return status;
}

async function fetchLaunchProjects() {
  const data = await api('/projects');
  if (!data?.ok) return [];
  LaunchState.activeProject = String(data.activeProject || data.project?.name || '').trim();
  LaunchState.activeProjectSerial = String(data.projectSerial || data.activeProjectSerial || data.project?.serialNo || data.serialNo || '').trim();
  const projects = Array.isArray(data.projects) ? data.projects : [];
  return projects.filter(isRealProject);
}

async function launchSelectProject(projectKey) {
  const key = String(projectKey || '').trim();
  if (!key) return;

  const data = window.DeckProject?.initiateProjectSwitch
    ? await window.DeckProject.initiateProjectSwitch({ serialNo: key, name: key, source: 'launch' })
    : await api('/projects/select', 'POST', { serialNo: key, name: key, source: 'launch' });

  if (!data?.ok) {
    toast(data?.message || data?.error || 'Project select failed');
    appendLog(`✗ project select failed: ${data?.message || data?.error || 'unknown'}`, 'fail');
    return;
  }

  LaunchState.enteredWorkspace = true;
  appendLog(`✓ project selected: ${data.project?.name || data.activeProject || key}`, 'pass');
  if (!window.DeckProject?.initiateProjectSwitch && window.MonitorProject?.renderProject) await window.MonitorProject.renderProject(data.projectState || data);
  setLaunchVisible(false);
  activateTab('project');
}

async function launchCreateProject(nameInputId, errorId) {
  const input = byId(nameInputId);
  const error = byId(errorId);
  const name = String(input?.value || '').trim();

  if (error) error.textContent = '';
  if (!name) {
    if (error) error.textContent = 'Enter a project name.';
    return;
  }

  const data = await api('/projects/create', 'POST', { name });
  if (!data?.ok) {
    const msg = data?.message || data?.error || 'Project creation failed';
    if (error) error.textContent = msg;
    toast(msg);
    return;
  }

  const projects = await fetchLaunchProjects();
  LaunchState.projects = projects;

  const created = projects.find(p => String(p.name || '').trim().toLowerCase() === name.toLowerCase()) || projects[projects.length - 1];
  if (created) {
    await launchSelectProject(created.serialNo || created.name);
    return;
  }

  await renderLaunchState();
}

async function enterActiveLaunchProject() {
  LaunchState.enteredWorkspace = true;
  setLaunchVisible(false);
  if (window.MonitorProject?.renderProject) {
    const data = await api('/project/header-meta');
    if (data?.ok) window.MonitorProject.renderProject(data);
  }
  activateTab('project');
}

function showLaunchAccountRequired() {
  showSoftAccountGate('account_required');
}

function monitorTourComplete() {
  return localStorage.getItem('nv_monitor_mini_tour_seen') === '1';
}

function monitorTourActive() {
  return Boolean(window.MonitorTour?.isActive?.() || document.querySelector('.nv-tour-overlay'));
}

function signedOutGateIsActive() {
  return !isSignedInAuth(LaunchState.auth || {});
}

function showSoftAccountGate(reason = 'protected_action') {
  setLaunchSubtitle('Sign in to continue');
  launchShowOnly('launch-account-required');
  setLaunchVisible(true);
  launchSignedOutMode(true);
  LaunchState.lastGateReason = reason;
  const accountButton = byId('launch-account-settings-btn');
  if (accountButton) accountButton.focus({ preventScroll: true });
}

function closeSoftAccountGate(reason = 'escape_bypass') {
  setLaunchVisible(false);
  launchSignedOutMode(true);
  if (!LaunchState.enteredWorkspace) enterLocalLaunchMode(reason);
}

function allowSignedOutClick(target) {
  if (!target) return true;
  if (target.closest('#launch-gate')) return true;
  if (target.closest('.nv-sysmenu-overlay, .nv-sysmenu-panel')) return true;
  if (target.closest('#panel-settings')) return true;
  if (target.closest('#tabs [data-tab="settings"]')) return true;
  if (target.closest('#nv-launch-sign-in-btn')) return true;
  return false;
}

function installSignedOutSoftGate() {
  if (window.__NV_SIGNED_OUT_SOFT_GATE__) return;
  window.__NV_SIGNED_OUT_SOFT_GATE__ = true;

  document.addEventListener('click', event => {
    if (!LaunchState.enteredWorkspace) return;
    if (!signedOutGateIsActive()) return;
    if (!monitorTourComplete() || monitorTourActive()) return;
    const target = event.target;
    if (allowSignedOutClick(target)) return;
    event.preventDefault();
    event.stopPropagation();
    showSoftAccountGate('signed_out_click');
  }, true);

  window.LaunchGate = {
    ...(window.LaunchGate || {}),
    isSignedIn: () => !signedOutGateIsActive(),
    requireSignIn(reason = 'protected_action') {
      if (!LaunchState.enteredWorkspace || !signedOutGateIsActive()) return false;
      if (!monitorTourComplete() || monitorTourActive()) return false;
      showSoftAccountGate(reason);
      return true;
    },
    showAccount: showSoftAccountGate,
    closeAccount: closeSoftAccountGate
  };
}

function showLaunchProjectSelect(projects) {
  setLaunchSubtitle('Select project');
  launchShowOnly('launch-project-select');
  renderLaunchProjectCards(projects);
  launchSetHidden('launch-backstage-row', true);
  setLaunchVisible(true);
}

function hasLaunchActiveProject() {
  const name = String(LaunchState.activeProject || '').trim().toLowerCase();
  const serial = String(LaunchState.activeProjectSerial || '').trim();
  if (LaunchState.backstage && (serial === 'system' || serial === '00' || name === 'system')) return true;
  return Boolean(name && !['system', 'backstage', 'universal'].includes(name));
}

async function renderLaunchState() {
  if (LaunchState.enteredWorkspace) return;
  const auth = LaunchState.auth || {};
  const signedIn = isSignedInAuth(auth);
  const projects = LaunchState.projects.filter(isRealProject);

  if (!signedIn) {
    enterLocalLaunchMode('signed_out');
    return;
  }

  launchSignedOutMode(false);

  if (hasLaunchActiveProject()) {
    await enterActiveLaunchProject();
    return;
  }

  if (LaunchState.backstage) {
    await enterActiveLaunchProject();
    return;
  }

  if (!projects.length) {
    enterLocalLaunchMode('no_projects_available');
    return;
  }

  showLaunchProjectSelect(projects);
}

function OpenSignup() {
  return openStandaloneAccountWindow();
}
async function bootLaunchGate() {
  await runBootSplash('Loading workspace', async () => {
    LaunchState.settings = await SettingsStore.load();
    LaunchState.auth = await refreshAccountUI();
    LaunchState.backstage = isBackstageAuth(LaunchState.auth);
    await fetchLaunchStatus();
    LaunchState.projects = await fetchLaunchProjects();
    await fetchLaunchStatus();

    try {
      await enforceAgreementGate(LaunchState.settings || {}, LaunchState.auth || {});
    } catch (err) {
      appendLog?.(`⚪ agreement check skipped: ${err?.message || err}`, 'warn');
    }

    await renderLaunchState();
  });

}

function portalReturnPayloadReady(payload) {
  return Boolean(
    payload &&
    payload.type === 'nodarama.account.status' &&
    payload.accessToken &&
    payload.refreshToken &&
    (payload.email || payload.user?.email)
  );
}

function installPortalReturnListener() {
  if (window.__NV_PORTAL_RETURN_LISTENER__) return;
  window.__NV_PORTAL_RETURN_LISTENER__ = true;

  window.addEventListener('message', async event => {
    const origin = String(event.origin || '').trim();
    if (origin && origin !== 'https://nodarama.com') return;

    const payload = event.data || {};
    if (!payload || payload.type !== 'nodarama.account.status') return;

    if (!portalReturnPayloadReady(payload)) {
      LaunchState.auth = await refreshAccountUI();
      return;
    }

    try {
      const result = typeof api === 'function'
        ? await api('/auth/portal-return', 'POST', payload)
        : await fetch('/auth/portal-return', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify(payload)
          }).then(res => res.json());

      if (!result?.ok) throw new Error(result?.message || result?.error || 'portal_return_failed');

      LaunchState.auth = await refreshAccountUI() || result;
      LaunchState.backstage = isBackstageAuth(LaunchState.auth);
      launchSignedOutMode(false);
      setLaunchVisible(false);
      await fetchLaunchStatus();
      LaunchState.projects = await fetchLaunchProjects();
      appendLog?.('✓ account connected from Nodarama portal', 'pass');
      toast?.('Signed in to Verbatim');
    } catch (err) {
      appendLog?.(`✗ account return failed: ${err?.message || err}`, 'fail');
      toast?.('Account return failed');
    }
  });
}

function setLaunchAuthError(message = '') {
  const el = byId('launch-auth-error');
  if (el) el.textContent = message;
}

function setAccountAuthError(message = '') {
  const el = byId('account-auth-error');
  if (el) el.textContent = message;
}

async function completeManualSignIn(result) {
  LaunchState.auth = await refreshAccountUI() || result;
  LaunchState.backstage = isBackstageAuth(LaunchState.auth);
  launchSignedOutMode(false);
  setLaunchVisible(false);
  await fetchLaunchStatus();
  LaunchState.projects = await fetchLaunchProjects();
  appendLog?.('✓ signed in to Verbatim', 'pass');
  toast?.('Signed in to Verbatim');
}

async function submitManualSignIn(email, password, setError, button) {
  setError('');
  if (!email || !password) {
    setError('Enter email and password.');
    return;
  }

  if (button) button.disabled = true;
  try {
    const result = await window.AuthSession?.login?.(email, password);
    if (!result?.ok) throw new Error(result?.message || result?.error || 'Sign in failed');
    await completeManualSignIn(result);
  } catch (err) {
    setError(err?.message || 'Sign in failed.');
  } finally {
    if (button) button.disabled = false;
  }
}

async function submitLaunchSignIn() {
  const emailInput = byId('launch-auth-email');
  const passwordInput = byId('launch-auth-password');
  const button = byId('launch-auth-signin-btn');
  const email = String(emailInput?.value || '').trim();
  const password = String(passwordInput?.value || '').trim();
  await submitManualSignIn(email, password, setLaunchAuthError, button);
}

async function refreshAccountFromSettings() {
  setAccountAuthError('');
  try {
    LaunchState.auth = await refreshAccountUI();
    LaunchState.backstage = isBackstageAuth(LaunchState.auth);
    const signedIn = isSignedInAuth(LaunchState.auth || {});
    launchSignedOutMode(!signedIn);
    toast?.(signedIn ? 'Account status refreshed' : 'Still signed out');
  } catch (err) {
    setAccountAuthError(err?.message || 'Refresh failed.');
  }
}

async function saveSettingsThenSignIn() {
  setAccountAuthError('');
  const saveButton = byId('settings-save-btn');
  if (saveButton) {
    saveButton.click();
    await new Promise(resolve => setTimeout(resolve, 180));
  }
  await submitAccountSignIn();
}

async function submitAccountSignIn() {
  const emailInput = byId('account-auth-email');
  const passwordInput = byId('account-auth-password');
  const button = byId('account-auth-signin-btn');
  const email = String(emailInput?.value || '').trim();
  const password = String(passwordInput?.value || '').trim();
  await submitManualSignIn(email, password, setAccountAuthError, button);
}
function openStandaloneAccountWindow() {
  const url = 'https://nodarama.com/account/?source=verbatim';
  const features = 'popup=yes,width=980,height=760,resizable=yes,scrollbars=yes';
  const win = window.open(url, 'nodarama-account', features) || window.open(url, '_blank');
  if (win) win.focus?.();
  return Boolean(win);
}
function installLaunchEscapeBypass() {
  if (window.__NV_LAUNCH_ESCAPE_BYPASS__) return;
  window.__NV_LAUNCH_ESCAPE_BYPASS__ = true;

  document.addEventListener('keydown', event => {
    if (event.key !== 'Escape') return;

    const splash = byId('project-switch-splash');
    const gate = byId('launch-gate');
    const splashActive = Boolean(splash && (splash.classList.contains('active') || splash.offsetParent !== null));
    const gateActive = Boolean(gate && !gate.hidden);

    if (!splashActive && !gateActive) return;

    event.preventDefault();
    event.stopPropagation();

    if (splash) splash.remove();
    if (gateActive && LaunchState.enteredWorkspace) {
      closeSoftAccountGate('escape_bypass');
      return;
    }
    if (gateActive || !LaunchState.enteredWorkspace) enterLocalLaunchMode('escape_bypass');
  }, true);
}

function wireLaunchGateControls() {
  installLaunchEscapeBypass();
  installSignedOutSoftGate();
  installPortalReturnListener();
  on('launch-settings-btn', 'click', () => {
    setLaunchVisible(false);
    activateTab('settings');
  });

  on('launch-account-settings-btn', 'click', () => {
    openStandaloneAccountWindow();
    setTimeout(() => void refreshAccountUI(), 900);
  });

  on('launch-auth-signin-btn', 'click', () => {
    void submitLaunchSignIn();
  });

  on('launch-auth-email', 'keydown', event => {
    if (event.key === 'Enter') {
      event.preventDefault();
      byId('launch-auth-password')?.focus();
    }
  });

  on('launch-auth-password', 'keydown', event => {
    if (event.key === 'Enter') {
      event.preventDefault();
      void submitLaunchSignIn();
    }
  });

  on('account-auth-signin-btn', 'click', () => {
    void submitAccountSignIn();
  });

  on('account-save-signin-btn', 'click', () => {
    void saveSettingsThenSignIn();
  });

  on('account-refresh-btn', 'click', () => {
    void refreshAccountFromSettings();
  });

  on('account-auth-email', 'keydown', event => {
    if (event.key === 'Enter') {
      event.preventDefault();
      byId('account-auth-password')?.focus();
    }
  });

  on('account-auth-password', 'keydown', event => {
    if (event.key === 'Enter') {
      event.preventDefault();
      void submitAccountSignIn();
    }
  });

  on('account-open-window-btn', 'click', () => {
    openStandaloneAccountWindow();
    setTimeout(() => void refreshAccountUI(), 900);
  });

  on('agreement-open-account-btn', 'click', () => {
    openStandaloneAccountWindow();
    setTimeout(() => void refreshAccountUI(), 900);
  });


  on('launch-create-open-btn', 'click', () => {
    launchSetHidden('launch-create-inline', false);
    byId('launch-project-name-inline')?.focus();
  });

  on('launch-create-cancel-btn', 'click', () => {
    launchSetHidden('launch-create-inline', true);
  });

  on('launch-create-project-inline-btn', 'click', () => {
    void launchCreateProject('launch-project-name-inline', 'launch-create-inline-error');
  });

  on('launch-project-name-inline', 'keydown', event => {
    if (event.key === 'Enter') {
      event.preventDefault();
      void launchCreateProject('launch-project-name-inline', 'launch-create-inline-error');
    }
  });
}
