// app.js — entry point: initialises all modules, wires scan flow and mode switching.
import CONFIG from './config.js';
import { getAsset, searchAssets, updateAsset } from './api/syncro.js';
import { initScanner, resetIdleTimer, focusScanInput, cancelIdleTimer, setTimerDuration, getTimerDuration, setKeyInterceptor, pause as pauseScanner, resume as resumeScanner } from './modules/scanner.js';
import { init as initCameraScanner, start as startCamera, stop as stopCamera, isActive as isCameraActive } from './modules/cameraScanner.js';
import { renderAssetCard } from './modules/assetCard.js';
import { initActions } from './modules/actions.js';
import { initTicketHistory } from './modules/ticketHistory.js';
import { showToast } from './modules/toast.js';
import { initAssetBrowser, setActiveAsset, setFiltersAndRender } from './modules/assetBrowser.js';
import { initSearchAutocomplete, handleAutocompleteKey } from './modules/searchAutocomplete.js';
import { initLabelCenter, closeLabelCenter, refreshBadge } from './modules/labelCenter.js';
import { renderClientDashboard } from './modules/clientDashboard.js';

// ── View management ───────────────────────────────────────────────────────────

const VIEWS = ['neutral', 'idle', 'loading', 'asset', 'search-results', 'quick-view', 'error'];

// ── Timer cycle ───────────────────────────────────────────────────────────────
const TIMER_STEPS  = [30_000, 60_000, 300_000, 900_000, null];
const TIMER_LABELS = ['Timer: 30s', 'Timer: 1m', 'Timer: 5m', 'Timer: 15m', 'Timer: OFF'];

function _updateTimerButton(ms) {
  const idx = TIMER_STEPS.indexOf(ms);
  document.getElementById('timer-toggle-label').textContent = TIMER_LABELS[idx] ?? 'Timer: OFF';
  document.getElementById('btn-timer-toggle')?.classList.toggle('active', ms !== null);
}

// Views worth returning to when closing an asset card
const _BACK_VIEWS = new Set(['neutral', 'idle', 'search-results', 'quick-view']);
let _returnView = 'neutral';

export function showView(name) {
  // Capture where we came from so closeAssetView() can go back there
  if (name === 'asset') {
    const current = VIEWS.find(v => document.getElementById(`view-${v}`)?.classList.contains('active'));
    if (current && _BACK_VIEWS.has(current)) _returnView = current;
  }
  VIEWS.forEach(v => {
    const el = document.getElementById(`view-${v}`);
    if (el) el.classList.toggle('active', v === name);
  });
  if (name === 'quick-view') {
    document.getElementById('btn-quick-view')?.classList.add('active');
  } else {
    document.getElementById('btn-quick-view')?.classList.remove('active');
  }
}

export function closeAssetView() {
  setActiveAsset(null);
  const card = document.querySelector('.asset-card');
  if (card) {
    card.classList.add('closing');
    setTimeout(() => showView(_returnView), 180);
  } else {
    showView(_returnView);
  }
}

// ── Scan mode state ───────────────────────────────────────────────────────────

let scanModeActive = false;

function setScanMode(active) {
  scanModeActive = active;
  setActiveMode(active ? 'scan' : null);
  localStorage.setItem('appMode', active ? 'scan' : 'label');
}

// ── Scan flow ─────────────────────────────────────────────────────────────────

async function handleScan(rawValue) {
  const value = rawValue.trim();
  if (!value) return;

  showView('loading');

  try {
    if (/^\d+$/.test(value)) {
      await resolveById(parseInt(value, 10));
    } else {
      await resolveBySearch(value);
    }
  } catch (err) {
    showView('error');
    document.getElementById('error-container').innerHTML = errorCardHTML(
      'Asset Not Found',
      err.message,
      value
    );
  }
}

async function resolveById(id) {
  let asset;
  try {
    asset = await getAsset(id);
  } catch (err) {
    if (err.message.includes('404') || err.message.toLowerCase().includes('not found')) {
      await resolveBySearch(String(id));
      return;
    }
    throw err;
  }
  await showAsset(asset);
}

async function resolveBySearch(query) {
  const assets = await searchAssets(query);
  if (!assets.length) {
    throw new Error(`No asset found matching "${query}"`);
  }
  if (assets.length === 1) {
    await showAsset(assets[0]);
    return;
  }
  showSearchResults(assets, query);
}

async function showAsset(asset) {
  stampScan(asset);
  renderAssetCard(asset);
  showView('asset');
  initActions(asset);
  initTicketHistory(asset);
  setActiveAsset(asset.id);
  resetIdleTimer();
}

function stampScan(asset) {
  if (window._currentUser?.role === 'client') return;
  updateAsset(asset.id, {
    properties: {
      'Last Scan Date': new Date().toISOString().split('T')[0],
      'Last Action': asset.properties?.['Last Action'] ?? 'Scanned',
    },
  }).catch(() => {});
}

// ── Search results picker ─────────────────────────────────────────────────────

function showSearchResults(assets, query) {
  const container = document.getElementById('search-results-container');
  container.innerHTML = `
<div class="search-results-wrap">
  <h3>Multiple assets match "${esc(query)}" — select one:</h3>
  <div class="search-result-list">
    ${assets.map(a => `
      <div class="search-result-item" data-asset-id="${a.id}">
        <div>
          <div class="search-result-name">${esc(a.name)}</div>
          <div class="search-result-meta">
            ${esc(a.asset_type ?? '')}
            ${a.serial ? ` · SN: ${esc(a.serial)}` : ''}
            ${a.customer?.name ? ` · ${esc(a.customer.name)}` : ''}
          </div>
        </div>
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--gray-400)" stroke-width="2"><polyline points="9 18 15 12 9 6"/></svg>
      </div>
    `).join('')}
  </div>
</div>`;

  container.querySelectorAll('.search-result-item').forEach(el => {
    el.addEventListener('click', async () => {
      showView('loading');
      try {
        const asset = await getAsset(parseInt(el.dataset.assetId, 10));
        await showAsset(asset);
      } catch (err) {
        showToast('Failed to load asset: ' + err.message, 'error');
        showView('search-results');
      }
    });
  });

  showView('search-results');
}

// ── Error card HTML ───────────────────────────────────────────────────────────

function errorCardHTML(title, message) {
  return `
<div class="error-card">
  <div class="error-icon">⚠</div>
  <h3>${esc(title)}</h3>
  <p>${esc(message)}</p>
  <button class="btn btn-ghost" id="err-retry-search">Try Manual Search</button>
</div>`;
}

// ── Idle ──────────────────────────────────────────────────────────────────────

function handleIdle() {
  if (!scanModeActive) return;  // don't hijack the view if scan mode is off
  // Close label center overlay if it happens to be open
  const lcOverlay = document.getElementById('label-center-overlay');
  if (lcOverlay && !lcOverlay.hidden) closeLabelCenter();
  setActiveMode('scan');
  showView('idle');
  focusScanInput();
}

// ── Mode switching ────────────────────────────────────────────────────────────

function setActiveMode(mode) {
  document.querySelectorAll('.mode-btn').forEach(btn => {
    btn.classList.toggle('active', btn.dataset.mode === mode);
  });
}

// ── User menu ─────────────────────────────────────────────────────────────────

async function initUserMenu() {
  try {
    const res = await fetch('/auth/me', { credentials: 'same-origin' });
    if (!res.ok) {
      window.location.href = '/login.html';
      return;
    }
    const { user } = await res.json();

    const nameEl = document.getElementById('user-name');
    const roleEl = document.getElementById('user-role');
    if (nameEl) nameEl.textContent = user.name;
    if (roleEl) {
      roleEl.textContent = user.role;
      roleEl.dataset.role = user.role;
    }

    // Show admin portal link for admin and above
    if (['admin', 'superduperadmin'].includes(user.role)) {
      document.getElementById('menu-admin-link')?.removeAttribute('hidden');
    }

    // Store on window for use by other modules if needed
    window._currentUser = user;

    if (user.role === 'client') {
      document.body.classList.add('role-client');
      const scanInput = document.getElementById('scan-input');
      if (scanInput) {
        scanInput.placeholder = 'Search by name, serial, or assigned user…';
        scanInput.removeAttribute('inputmode');
      }
      // Queue the dashboard render — showView('quick-view') happens after
      // DOMContentLoaded finishes its localStorage restores (which call showView)
      document.getElementById('btn-quick-view')?.classList.add('active');
      const container = document.getElementById('quick-view-container');
      if (container) renderClientDashboard(container, user, {
        onFilterSelect: ({ lifecycle, possession }) => {
          setFiltersAndRender({ lifecycle, possession });
        },
      });
    }
  } catch {
    window.location.href = '/login.html';
  }
}

// ── App menu toggle ────────────────────────────────────────────────────────────

function initAppMenu() {
  const toggle  = document.getElementById('btn-menu-toggle');
  const menu    = document.getElementById('app-menu');
  if (!toggle || !menu) return;

  // Open / close
  toggle.addEventListener('click', e => {
    e.stopPropagation();
    const opening = menu.hidden;
    menu.hidden = !opening;
    toggle.setAttribute('aria-expanded', String(opening));
  });

  // Close on outside click
  document.addEventListener('click', e => {
    if (!menu.hidden && !menu.contains(e.target) && e.target !== toggle && !toggle.contains(e.target)) {
      menu.hidden = true;
      toggle.setAttribute('aria-expanded', 'false');
    }
  });

  // Close on Escape
  document.addEventListener('keydown', e => {
    if (e.key === 'Escape' && !menu.hidden) {
      menu.hidden = true;
      toggle.setAttribute('aria-expanded', 'false');
    }
  });

  // Close menu when any item is clicked, except toggles (leave open so state is visible)
  menu.addEventListener('click', e => {
    const item = e.target.closest('.app-menu-item');
    if (item && item.id !== 'btn-timer-toggle' && item.id !== 'btn-scan-mode-toggle') {
      menu.hidden = true;
      toggle.setAttribute('aria-expanded', 'false');
    }
  });
}

// ── Init ──────────────────────────────────────────────────────────────────────

// ── Sidebar resize ───────────────────────────────────────────────────────────
(function initSidebarResize() {
  const sidebar = document.getElementById('asset-sidebar');
  const handle  = document.getElementById('sidebar-resize-handle');
  if (!sidebar || !handle) return;

  const MIN_W = 160;
  const MAX_W = 600;

  const saved = parseInt(localStorage.getItem('sidebar_width'), 10);
  if (saved >= MIN_W && saved <= MAX_W) sidebar.style.width = saved + 'px';

  handle.addEventListener('mousedown', e => {
    e.preventDefault();
    handle.classList.add('dragging');
    document.body.classList.add('sidebar-resizing');

    const appBody = document.getElementById('app-body');

    const onMove = e2 => {
      const rect = appBody.getBoundingClientRect();
      const newW = Math.min(MAX_W, Math.max(MIN_W, e2.clientX - rect.left));
      sidebar.style.width = newW + 'px';
    };
    const onUp = () => {
      handle.classList.remove('dragging');
      document.body.classList.remove('sidebar-resizing');
      document.removeEventListener('mousemove', onMove);
      document.removeEventListener('mouseup', onUp);
      localStorage.setItem('sidebar_width', Math.round(sidebar.getBoundingClientRect().width));
    };
    document.addEventListener('mousemove', onMove);
    document.addEventListener('mouseup', onUp);
  });
})();

document.addEventListener('DOMContentLoaded', async () => {
  // Verify session and populate user menu before rendering app
  await initUserMenu();
  initAppMenu();

  // Camera scanner — pass handleScan as the barcode callback.
  // onCameraStop resets the toggle UI whenever the overlay closes (via X or after a scan).
  initCameraScanner(handleScan, () => {
    resumeScanner();
    document.getElementById('btn-scan-mode-toggle')?.classList.remove('active');
    localStorage.setItem('scanMode', 'usb');
  });

  // Logout
  document.getElementById('btn-logout')?.addEventListener('click', async () => {
    await fetch('/auth/logout', { method: 'POST', credentials: 'same-origin' });
    window.location.href = '/login.html';
  });

  // ── Restore persisted state ──────────────────────────────────────────────

  // Scan mode (clients always get quick-view; scan mode is staff-only)
  if (window._currentUser?.role === 'client') {
    showView('quick-view');
  } else if (localStorage.getItem('appMode') === 'scan') {
    scanModeActive = true;
    setActiveMode('scan');
    showView('idle');
    focusScanInput();
  } else {
    showView('neutral');
  }

  // Timer
  const savedTimer = localStorage.getItem('timerDuration');
  const timerMs = savedTimer && savedTimer !== 'off' ? Number(savedTimer) : null;
  setTimerDuration(timerMs);
  _updateTimerButton(timerMs);

  // Camera scan mode — restore button UI only (cannot auto-start camera without a user gesture)
  if (localStorage.getItem('scanMode') === 'camera') {
    document.getElementById('btn-scan-mode-toggle')?.classList.add('active');
  }

  // ── Mode nav ─────────────────────────────────────────────────────────────

  document.getElementById('btn-scan-mode')?.addEventListener('click', () => {
    if (scanModeActive) {
      setScanMode(false);
      showView('neutral');
      cancelIdleTimer();
    } else {
      setScanMode(true);
      showView('idle');
      cancelIdleTimer();
      focusScanInput();
    }
  });

  document.getElementById('btn-label-center')?.addEventListener('click', () => {
    // handled by labelCenter.js initLabelCenter() — just close the menu
    const menu   = document.getElementById('app-menu');
    const toggle = document.getElementById('btn-menu-toggle');
    if (menu) { menu.hidden = true; toggle?.setAttribute('aria-expanded', 'false'); }
  });

  // ── Timer toggle ─────────────────────────────────────────────────────────

  document.getElementById('btn-timer-toggle')?.addEventListener('click', () => {
    const cur = getTimerDuration();
    const idx = TIMER_STEPS.indexOf(cur);
    const next = TIMER_STEPS[(idx + 1) % TIMER_STEPS.length];
    setTimerDuration(next);
    _updateTimerButton(next);
    localStorage.setItem('timerDuration', next ?? 'off');
  });

  // ── Camera scan mode toggle ───────────────────────────────────────────────

  document.getElementById('btn-scan-mode-toggle')?.addEventListener('click', async () => {
    const menu   = document.getElementById('app-menu');
    const toggle = document.getElementById('btn-menu-toggle');
    if (isCameraActive()) {
      // Switch back to USB
      await stopCamera(); // triggers onCameraStop which resets UI
    } else {
      // Switch to camera — close menu, pause USB wedge, open camera overlay
      menu.hidden = true;
      toggle.setAttribute('aria-expanded', 'false');
      document.getElementById('btn-scan-mode-toggle')?.classList.add('active');
      localStorage.setItem('scanMode', 'camera');
      pauseScanner();
      await startCamera();
    }
  });

  // Release camera tracks if the page is hidden/unloaded while overlay is open
  window.addEventListener('pagehide', () => {
    if (isCameraActive()) stopCamera();
  });

  // ── Scan input focus — show idle hint; blur — back to neutral if off ──────

  const scanInput = document.getElementById('scan-input');
  let _blurTimer;

  scanInput?.addEventListener('focus', () => {
    clearTimeout(_blurTimer);
    if (window._currentUser?.role !== 'client' &&
        document.getElementById('view-neutral')?.classList.contains('active')) {
      showView('idle');
    }
  });

  scanInput?.addEventListener('blur', () => {
    if (!scanModeActive) {
      _blurTimer = setTimeout(() => {
        if (document.getElementById('view-idle')?.classList.contains('active')) {
          showView('neutral');
        }
      }, 150);
    }
  });

  // ── Error retry + asset card close ───────────────────────────────────────

  document.addEventListener('click', e => {
    if (e.target.id === 'err-retry-search') {
      showView('idle');
      if (scanModeActive) focusScanInput();
    }
    if (e.target.closest('#btn-close-asset')) {
      closeAssetView();
    }
  });

  // ── Quick View button (client role only) ──────────────────────────────────

  document.getElementById('btn-quick-view')?.addEventListener('click', () => {
    const btn = document.getElementById('btn-quick-view');
    const isOpen = btn?.classList.contains('active');
    if (isOpen) {
      btn?.classList.remove('active');
      showView('neutral');
    } else {
      btn?.classList.add('active');
      const container = document.getElementById('quick-view-container');
      if (container) renderClientDashboard(container, window._currentUser, {
        onFilterSelect: ({ lifecycle, possession }) => {
          setFiltersAndRender({ lifecycle, possession });
        },
      });
      showView('quick-view');
    }
  });

  // ── Init modules ──────────────────────────────────────────────────────────

  initScanner({ onScan: handleScan, onIdle: handleIdle, canFocus: () => scanModeActive });

  initSearchAutocomplete({ onLocalSelect: showAsset, onRemoteSearch: handleScan });
  setKeyInterceptor(handleAutocompleteKey);

  initAssetBrowser({
    onAssetSelect:  (asset) => { showAsset(asset); },
    onAssetClose:   ()      => { closeAssetView(); },
  });

  // ── Home button — returns to the role-appropriate landing view ────────────
  document.getElementById('btn-home')?.addEventListener('click', () => {
    const home = window._currentUser?.role === 'client' ? 'quick-view' : 'neutral';
    showView(home);
  });

  initLabelCenter();
  refreshBadge();

  // ── Server-restart detection ──────────────────────────────────────────────
  // Poll /api/ping every 30s. If the bootId changes (or the server was down
  // and came back), reload so clients pick up any new static assets.
  let _bootId = null;
  let _serverWasDown = false;

  async function _pollServer() {
    try {
      const res = await fetch('/api/ping', { credentials: 'same-origin' });
      if (!res.ok) { _serverWasDown = true; return; }
      const { bootId } = await res.json();
      if (_bootId === null) {
        _bootId = bootId; // baseline on first successful poll
      } else if (bootId !== _bootId || _serverWasDown) {
        _showRestartCountdown();
      }
      _serverWasDown = false;
    } catch {
      _serverWasDown = true;
    }
  }

  _pollServer();
  setInterval(_pollServer, 30_000);
});

function _showRestartCountdown() {
  // Only show once
  if (document.getElementById('restart-countdown-backdrop')) return;

  const backdrop = document.createElement('div');
  backdrop.id = 'restart-countdown-backdrop';
  backdrop.style.cssText = [
    'position:fixed', 'inset:0', 'z-index:9999',
    'background:rgba(0,0,0,.55)',
    'display:flex', 'align-items:center', 'justify-content:center',
    'animation:fadeIn .2s ease',
  ].join(';');

  const card = document.createElement('div');
  card.style.cssText = [
    'background:#fff', 'border-radius:12px',
    'max-width:380px', 'width:calc(100vw - 40px)',
    'overflow:hidden', 'box-shadow:0 8px 32px rgba(0,0,0,.25)',
  ].join(';');

  let seconds = 5;
  card.innerHTML = `
    <div style="background:#1a3565;color:#fff;padding:16px 20px;display:flex;align-items:center;gap:12px;border-bottom:3px solid #C4622A;">
      <img src="/assets/logo-swirl.png" style="width:36px;height:36px;border-radius:50%;background:#fff;padding:2px;flex-shrink:0;" alt="">
      <div>
        <div style="font-size:.95rem;font-weight:700;line-height:1.2;">Asset Browser</div>
        <div style="font-size:.65rem;color:rgba(255,255,255,.55);text-transform:uppercase;letter-spacing:.05em;margin-top:2px;">deRenzy Business Technologies</div>
      </div>
    </div>
    <div style="padding:24px 28px;text-align:center;">
      <div style="margin-bottom:14px;">
        <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="#1a3565" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
          <polyline points="23 4 23 10 17 10"/><polyline points="1 20 1 14 7 14"/>
          <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>
        </svg>
      </div>
      <div style="font-size:1rem;font-weight:700;color:#1a3565;margin-bottom:6px;">Server Restarted</div>
      <div style="font-size:.88rem;color:#6b7280;margin-bottom:20px;">Reloading in <strong id="rc-seconds">5</strong> second(s)…</div>
      <button id="rc-reload-now" style="background:#C4622A;color:#fff;border:none;border-radius:6px;padding:8px 20px;font-size:.88rem;font-weight:600;cursor:pointer;font-family:inherit;">Reload now</button>
    </div>`;

  backdrop.appendChild(card);
  document.body.appendChild(backdrop);

  const interval = setInterval(() => {
    seconds--;
    const el = document.getElementById('rc-seconds');
    if (el) el.textContent = seconds;
    if (seconds <= 0) { clearInterval(interval); window.location.reload(); }
  }, 1000);

  document.getElementById('rc-reload-now')?.addEventListener('click', () => {
    clearInterval(interval);
    window.location.reload();
  });
}

function esc(s) {
  return String(s ?? '').replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
}
