const express = require('express');
const router = express.Router();
const { v4: uuidv4 } = require('uuid');
const { db } = require('../db/database');
const { PLATFORM_ROLES, ELEVATED_ROLES } = require('../middleware/auth');
// Phase 2.2e: workspace-aware access. Same pattern as content/widgets/folders.
const { accessContext } = require('../lib/tenancy');

// Escape HTML to prevent XSS
function escapeHtml(str) {
  if (typeof str !== 'string') return str;
  return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
}

// Validate CSS color values to prevent style injection
function safeColor(val, fallback) {
  if (!val) return fallback;
  if (/^#[0-9a-fA-F]{3,8}$/.test(val) || /^[a-zA-Z]+$/.test(val)) return val;
  return fallback;
}

// CSS VALUE escaping. These land inside a <style> block, where escapeHtml() is the WRONG
// tool: it escapes & < > " ' but not { } ;, and inside a raw-text <style> element the entities
// it does produce are never decoded. So escapeHtml neither prevents CSS injection nor renders
// correctly. `red} body{background:url(https://attacker/x)` closes the declaration AND the rule
// and appends arbitrary ones — no XSS (</style> can't be reached), but an attacker-chosen rule
// on every panel showing the page, which is an outbound beacon at minimum.
//
// The check is on STRUCTURE, not a value allowlist: `background` is a free-text field in the
// editor, so legitimate values include linear-gradient(...), rgb(...) and url(...). Those all
// stay; only characters that could end the declaration or open a new rule are refused.
function safeCssValue(val, fallback) {
  if (typeof val !== 'string') return fallback;
  const v = val.trim();
  if (!v) return fallback;
  if (/[{};]/.test(v)) return fallback;          // declaration / rule breakout
  if (/\/\*|\*\//.test(v)) return fallback;        // comments can swallow following declarations
  if (/[\u0000-\u001F]/.test(v)) return fallback;   // control chars, incl. newlines
  if (/<\s*\/?\s*style/i.test(v)) return fallback;  // belt-and-braces against the raw-text edge
  return v;
}

// font-family needs no parentheses, so it gets a tighter allowlist than the general value check:
// family names, the generic keywords, quotes and separators only.
function safeFontFamily(val, fallback) {
  if (typeof val !== 'string') return fallback;
  const v = val.trim();
  if (!v) return fallback;
  return /^[a-zA-Z0-9 ,'"._-]+$/.test(v) ? v : fallback;
}

// Validate CSS numeric values
function safeNumber(val, fallback) {
  const n = Number(val);
  return isFinite(n) ? n : fallback;
}

// List kiosk pages in the caller's current workspace plus any platform-template
// rows (workspace_id IS NULL) shared with all workspaces.
// Phase 2.2e: workspace-scoped. Cross-workspace visibility comes from
// switch-workspace, not a special list branch.
router.get('/', (req, res) => {
  if (!req.workspaceId) return res.json([]);
  const pages = db.prepare(
    'SELECT * FROM kiosk_pages WHERE (workspace_id = ? OR workspace_id IS NULL) ORDER BY created_at DESC'
  ).all(req.workspaceId);
  res.json(pages);
});

// Phase 2.2e: workspace-aware access. Mirrors widgets/content helpers.
// Platform-template kiosks (workspace_id IS NULL) are readable by anyone
// authenticated and writable only by platform_admin.
function checkKioskRead(req, res) {
  const page = db.prepare('SELECT * FROM kiosk_pages WHERE id = ?').get(req.params.id);
  if (!page) { res.status(404).json({ error: 'Page not found' }); return null; }
  if (!page.workspace_id) return page;
  const ws = db.prepare('SELECT * FROM workspaces WHERE id = ?').get(page.workspace_id);
  const ctx = ws && accessContext(req.user.id, req.user.role, ws);
  if (!ctx) { res.status(403).json({ error: 'Access denied' }); return null; }
  return page;
}

function checkKioskWrite(req, res) {
  const page = db.prepare('SELECT * FROM kiosk_pages WHERE id = ?').get(req.params.id);
  if (!page) { res.status(404).json({ error: 'Page not found' }); return null; }
  if (!page.workspace_id) {
    if (!PLATFORM_ROLES.includes(req.user.role)) {
      res.status(403).json({ error: 'Platform admin required to modify shared kiosk pages' }); return null;
    }
    return page;
  }
  const ws = db.prepare('SELECT * FROM workspaces WHERE id = ?').get(page.workspace_id);
  const ctx = ws && accessContext(req.user.id, req.user.role, ws);
  if (!ctx) { res.status(403).json({ error: 'Access denied' }); return null; }
  if (!ctx.actingAs && ctx.workspaceRole === 'workspace_viewer') {
    res.status(403).json({ error: 'Read-only access' }); return null;
  }
  return page;
}

// Get kiosk page
router.get('/:id', (req, res) => {
  const page = checkKioskRead(req, res);
  if (!page) return;
  res.json(page);
});

// Render kiosk page (public - accessed by devices)
router.get('/:id/render', (req, res) => {
  const page = db.prepare('SELECT * FROM kiosk_pages WHERE id = ?').get(req.params.id);
  if (!page) return res.status(404).send('Page not found');

  const config = JSON.parse(page.config || '{}');
  const buttons = config.buttons || [];
  const style = config.style || {};

  const html = `<!DOCTYPE html>
<html><head>
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<style>
  * { margin:0; padding:0; box-sizing:border-box; -webkit-tap-highlight-color:transparent; }
  body { width:100vw; height:100vh; overflow:hidden; font-family:${safeFontFamily(style.fontFamily, '-apple-system,sans-serif')};
    background:${safeCssValue(style.background, '#111827')}; color:${safeColor(style.textColor, '#f1f5f9')}; display:flex; flex-direction:column; }
  .header { padding:40px 60px 20px; text-align:${/^(left|center|right)$/.test(style.headerAlign) ? style.headerAlign : 'center'}; }
  .header h1 { font-size:${safeNumber(style.titleSize, 48)}px; font-weight:700; }
  .header p { font-size:${safeNumber(style.subtitleSize, 20)}px; opacity:0.7; margin-top:8px; }
  .header img { max-height:80px; margin-bottom:16px; }
  .content { flex:1; display:flex; align-items:center; justify-content:center; padding:20px 60px; }
  .button-grid { display:grid; grid-template-columns:repeat(${safeNumber(style.columns, 3)}, 1fr); gap:${safeNumber(style.gap, 24)}px; width:100%; max-width:1200px; }
  .kiosk-btn {
    background:${safeColor(style.buttonBg, '#1e293b')}; border:2px solid ${safeColor(style.buttonBorder, '#334155')};
    border-radius:${safeNumber(style.buttonRadius, 16)}px; padding:${safeNumber(style.buttonPadding, 32)}px;
    text-align:center; cursor:pointer; transition:all 0.2s ease; touch-action:manipulation;
    display:flex; flex-direction:column; align-items:center; justify-content:center; gap:12px;
  }
  .kiosk-btn:hover, .kiosk-btn:active { background:${safeColor(style.buttonHover, '#3b82f6')}; border-color:${safeColor(style.buttonHover, '#3b82f6')}; transform:scale(1.02); }
  .kiosk-btn .icon { font-size:${safeNumber(style.iconSize, 48)}px; }
  .kiosk-btn .label { font-size:${safeNumber(style.labelSize, 20)}px; font-weight:600; }
  .kiosk-btn .sublabel { font-size:${safeNumber(style.sublabelSize, 14)}px; opacity:0.6; }
  .footer { padding:20px 60px; text-align:center; font-size:14px; opacity:0.4; }
  .idle-overlay { position:fixed; inset:0; background:rgba(0,0,0,0.95); display:none; flex-direction:column;
    align-items:center; justify-content:center; z-index:100; cursor:pointer; }
  .idle-overlay h2 { font-size:48px; margin-bottom:16px; }
  .idle-overlay p { font-size:20px; opacity:0.6; }
</style>
</head>
<body>
  <div class="header">
    ${config.logoUrl ? `<img src="${escapeHtml(config.logoUrl)}" alt="Logo">` : ''}
    <h1>${escapeHtml(config.title) || 'Welcome'}</h1>
    ${config.subtitle ? `<p>${escapeHtml(config.subtitle)}</p>` : ''}
  </div>
  <div class="content">
    <div class="button-grid">
      ${buttons.map(btn => `
        <div class="kiosk-btn" data-action="${escapeHtml(btn.action) || ''}" data-url="${escapeHtml(btn.url) || ''}" data-page="${escapeHtml(btn.page) || ''}">
          ${btn.icon ? `<div class="icon">${escapeHtml(btn.icon)}</div>` : ''}
          <div class="label">${escapeHtml(btn.label) || 'Button'}</div>
          ${btn.sublabel ? `<div class="sublabel">${escapeHtml(btn.sublabel)}</div>` : ''}
        </div>
      `).join('')}
    </div>
  </div>
  <div class="footer">${escapeHtml(config.footer) || ''}</div>

  <!-- Idle screen (shows after inactivity) -->
  <div class="idle-overlay" id="idleOverlay">
    <h2>${escapeHtml(config.idleTitle) || 'Touch to Begin'}</h2>
    <p>${escapeHtml(config.idleSubtitle) || ''}</p>
  </div>

  <script>
    // Button actions
    document.querySelectorAll('.kiosk-btn').forEach(btn => {
      btn.addEventListener('click', () => {
        resetIdleTimer();
        const action = btn.dataset.action;
        const url = btn.dataset.url;
        const page = btn.dataset.page;
        if (action === 'url' && url) window.open(url, '_blank');
        else if (action === 'page' && page) window.location.href = page;
        else if (action === 'back') window.history.back();
        // Visual feedback
        btn.style.transform = 'scale(0.95)';
        setTimeout(() => btn.style.transform = '', 200);

        // Report touch to server
        if (window.parent !== window) {
          window.parent.postMessage({ type: 'kiosk-tap', label: btn.querySelector('.label')?.textContent }, '*');
        }
      });
    });

    // Idle screen after ${safeNumber(config.idleTimeout, 60)} seconds of no interaction
    let idleTimer;
    function resetIdleTimer() {
      document.getElementById('idleOverlay').style.display = 'none';
      clearTimeout(idleTimer);
      idleTimer = setTimeout(() => {
        document.getElementById('idleOverlay').style.display = 'flex';
      }, ${safeNumber(config.idleTimeout, 60) * 1000});
    }
    document.getElementById('idleOverlay').addEventListener('click', resetIdleTimer);
    ['touchstart', 'click', 'mousemove'].forEach(e => document.addEventListener(e, resetIdleTimer));
    resetIdleTimer();

    // Clock update if element exists
    const clockEl = document.getElementById('clock');
    if (clockEl) setInterval(() => { clockEl.textContent = new Date().toLocaleTimeString(); }, 1000);
  </script>
</body></html>`;

  // Embedded by the player in a sandboxed (null-origin) iframe; the global
  // X-Frame-Options: SAMEORIGIN would refuse that and leave it blank.
  res.removeHeader('X-Frame-Options');
  res.setHeader('Cache-Control', 'no-store');
  res.setHeader('Content-Type', 'text/html');
  res.send(html);
});

// Create kiosk page in the caller's current workspace.
router.post('/', (req, res) => {
  if (!req.workspaceId) return res.status(403).json({ error: 'No workspace context. Switch to a workspace before creating kiosk pages.' });
  const { name, config: pageConfig } = req.body;
  if (!name) return res.status(400).json({ error: 'name required' });

  const id = uuidv4();
  db.prepare('INSERT INTO kiosk_pages (id, user_id, workspace_id, name, config) VALUES (?, ?, ?, ?, ?)')
    .run(id, req.user.id, req.workspaceId, name, JSON.stringify(pageConfig || getDefaultKioskConfig()));

  res.status(201).json(db.prepare('SELECT * FROM kiosk_pages WHERE id = ?').get(id));
});

// Update kiosk page
router.put('/:id', (req, res) => {
  const page = checkKioskWrite(req, res);
  if (!page) return;

  const { name, config: pageConfig } = req.body;
  if (name) db.prepare('UPDATE kiosk_pages SET name = ? WHERE id = ?').run(name, req.params.id);
  if (pageConfig) db.prepare('UPDATE kiosk_pages SET config = ?, updated_at = strftime(\'%s\',\'now\') WHERE id = ?')
    .run(JSON.stringify(pageConfig), req.params.id);

  res.json(db.prepare('SELECT * FROM kiosk_pages WHERE id = ?').get(req.params.id));
});

// Delete kiosk page
router.delete('/:id', (req, res) => {
  const page = checkKioskWrite(req, res);
  if (!page) return;
  db.prepare('DELETE FROM kiosk_pages WHERE id = ?').run(req.params.id);
  res.json({ success: true });
});

function getDefaultKioskConfig() {
  return {
    title: 'Welcome',
    subtitle: 'How can we help you today?',
    footer: '',
    logoUrl: '',
    idleTitle: 'Touch to Begin',
    idleSubtitle: '',
    idleTimeout: 60,
    buttons: [
      { label: 'Directory', sublabel: 'Find a location', icon: '&#128205;', action: 'page', page: '' },
      { label: 'Events', sublabel: 'See what\'s happening', icon: '&#128197;', action: 'page', page: '' },
      { label: 'Map', sublabel: 'Building map', icon: '&#128506;', action: 'page', page: '' },
      { label: 'Contact', sublabel: 'Get in touch', icon: '&#128222;', action: 'page', page: '' },
      { label: 'WiFi', sublabel: 'Connect to WiFi', icon: '&#128246;', action: 'page', page: '' },
      { label: 'Help', sublabel: 'Need assistance?', icon: '&#10068;', action: 'page', page: '' },
    ],
    style: {
      background: 'linear-gradient(135deg, #0c0c0c 0%, #1a1a2e 50%, #16213e 100%)',
      textColor: '#f1f5f9',
      columns: 3,
      buttonBg: '#1e293b',
      buttonBorder: '#334155',
      buttonHover: '#3b82f6',
      buttonRadius: 16,
      buttonPadding: 32,
      gap: 24,
      titleSize: 48,
      iconSize: 48,
      labelSize: 20,
    }
  };
}

module.exports = router;
