// routes/adminPanel.js — password-protected admin panel for free-access shop management
const express = require('express');
const crypto  = require('crypto');
const { isShopAllowed, addShop, removeShop, listShops } = require('../freeAccessStore');
const { listTokens } = require('../tokenStore');
const { addMessage, readChat, markRead, listChats } = require('../chatStore');

const router = express.Router();

const ADMIN_USER = 'd4a-admin';
const ADMIN_PASS = 'Data4autos@2026.';
const COOKIE_NAME = 'd4a_admin_tok';
const COOKIE_MAX_AGE = 8 * 60 * 60 * 1000; // 8 hours

// In-memory valid tokens (cleared on server restart)
const validTokens = new Set();

// ── auth middleware ─────────────────────────────────────────────────────────
function requireAuth(req, res, next) {
  const tok = req.cookies?.[COOKIE_NAME] || req.headers['x-admin-token'];
  if (tok && validTokens.has(tok)) return next();
  if (req.path.startsWith('/api/')) return res.status(401).json({ error: 'Unauthorised' });
  res.redirect('/d4a-admin');
}

// ── cookie parser (lightweight, no dependency) ──────────────────────────────
router.use((req, _res, next) => {
  const raw = req.headers.cookie || '';
  req.cookies = Object.fromEntries(
    raw.split(';').map(c => c.trim().split('=').map(decodeURIComponent))
      .filter(([k]) => k).map(([k, ...v]) => [k, v.join('=')])
  );
  next();
});

router.use(express.urlencoded({ extended: false }));
router.use(express.json());

// ── login ────────────────────────────────────────────────────────────────────
router.post('/login', (req, res) => {
  const { username, password } = req.body;
  if (username === ADMIN_USER && password === ADMIN_PASS) {
    const token = crypto.randomBytes(32).toString('hex');
    validTokens.add(token);
    setTimeout(() => validTokens.delete(token), COOKIE_MAX_AGE);
    res.setHeader('Set-Cookie', `${COOKIE_NAME}=${encodeURIComponent(token)}; HttpOnly; Path=/; Max-Age=${COOKIE_MAX_AGE / 1000}; SameSite=Lax`);
    return res.json({ ok: true });
  }
  res.status(401).json({ error: 'Invalid credentials' });
});

// ── logout ───────────────────────────────────────────────────────────────────
router.post('/logout', (req, res) => {
  const tok = req.cookies?.[COOKIE_NAME];
  if (tok) validTokens.delete(tok);
  res.setHeader('Set-Cookie', `${COOKIE_NAME}=; HttpOnly; Path=/; Max-Age=0; SameSite=Lax`);
  res.json({ ok: true });
});

// ── check-auth ───────────────────────────────────────────────────────────────
router.get('/api/check-auth', (req, res) => {
  const tok = req.cookies?.[COOKIE_NAME];
  if (tok && validTokens.has(tok)) return res.json({ ok: true });
  res.status(401).json({ ok: false });
});

// ── shops API (protected) ────────────────────────────────────────────────────
router.get('/api/shops', requireAuth, (_req, res) => {
  res.json({ shops: listShops() });
});

router.post('/api/shops', requireAuth, (req, res) => {
  const { shop, expiresAt, note } = req.body;
  if (!shop) return res.status(400).json({ error: 'shop is required' });
  const entry = addShop(shop.trim(), expiresAt || null, note || '');
  res.json({ ok: true, shop: shop.trim(), entry });
});

router.delete('/api/shops/:shop', requireAuth, (req, res) => {
  removeShop(decodeURIComponent(req.params.shop));
  res.json({ ok: true });
});

// ── all installed users (from tokens.json) merged with free-access status ────
router.get('/api/users', requireAuth, (_req, res) => {
  const tokens = listTokens();
  const freeList = listShops();
  const freeMap = Object.fromEntries(freeList.map(s => [s.shop, s]));
  const users = Object.entries(tokens).map(([shop, t]) => {
    const fa = freeMap[shop] || null;
    return {
      shop,
      savedAt: t.savedAt || null,
      hasToken: !!t.accessToken,
      freeAccess: !!fa && !fa.expired,
      freeEntry: fa || null,
    };
  });
  users.sort((a, b) => (b.savedAt || '').localeCompare(a.savedAt || ''));
  res.json({ users });
});

// ── chat API (admin-protected) ───────────────────────────────────────────────
router.get('/api/chats', requireAuth, (_req, res) => {
  res.json({ chats: listChats() });
});

router.get('/api/chats/:shop', requireAuth, (req, res) => {
  const shop = decodeURIComponent(req.params.shop);
  markRead(shop);
  res.json(readChat(shop));
});

router.post('/api/chats/:shop/reply', requireAuth, (req, res) => {
  const shop = decodeURIComponent(req.params.shop);
  const { text } = req.body;
  if (!text) return res.status(400).json({ error: 'text required' });
  const msg = addMessage(shop, 'admin', text);
  res.json({ ok: true, message: msg });
});

// ── serve admin HTML (always — login gate is client-side) ────────────────────
router.get('/', (_req, res) => {
  res.setHeader('Content-Type', 'text/html; charset=utf-8');
  res.send(adminHtml());
});

// ── HTML ─────────────────────────────────────────────────────────────────────
function adminHtml() {
  return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width,initial-scale=1"/>
<title>Data4Autos — Admin Portal</title>
<style>
  @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap');
  *{box-sizing:border-box;margin:0;padding:0}
  body{font-family:'Inter',system-ui,sans-serif;background:#f1f5f9;min-height:100vh;color:#0f172a;overflow-x:hidden}

  /* ═══════════════════════════ LOGIN ═══════════════════════════ */
  #login-screen{display:flex;align-items:stretch;min-height:100vh;}

  /* Left — vibrant blue panel */
  .login-left{
    flex:1;display:flex;flex-direction:column;justify-content:center;
    padding:64px 56px;
    background:linear-gradient(145deg,#1e40af 0%,#2563eb 45%,#4f46e5 100%);
    position:relative;overflow:hidden;
  }
  @media(max-width:860px){.login-left{display:none}}
  .login-left::before{
    content:'';position:absolute;width:500px;height:500px;border-radius:50%;
    background:rgba(255,255,255,0.06);top:-160px;right:-120px;
  }
  .login-left::after{
    content:'';position:absolute;width:320px;height:320px;border-radius:50%;
    background:rgba(255,255,255,0.05);bottom:-80px;left:-60px;
  }
  .ll-logo{
    display:flex;align-items:center;gap:14px;margin-bottom:52px;position:relative;z-index:1;
  }
  .ll-icon{
    width:52px;height:52px;background:rgba(255,255,255,0.15);border:1px solid rgba(255,255,255,0.25);
    border-radius:14px;display:flex;align-items:center;justify-content:center;font-size:24px;
  }
  .ll-brand{font-size:20px;font-weight:800;color:#fff;letter-spacing:-0.3px;}
  .ll-brand span{display:block;font-size:12px;font-weight:500;color:rgba(255,255,255,0.6);letter-spacing:0;margin-top:1px;}
  .ll-heading{font-size:34px;font-weight:900;color:#fff;line-height:1.2;letter-spacing:-1px;margin-bottom:16px;position:relative;z-index:1;}
  .ll-heading em{font-style:normal;color:#bfdbfe;}
  .ll-desc{font-size:15px;color:rgba(255,255,255,0.72);line-height:1.7;max-width:340px;margin-bottom:48px;position:relative;z-index:1;}
  .ll-features{display:flex;flex-direction:column;gap:12px;position:relative;z-index:1;}
  .ll-feat{
    display:flex;align-items:center;gap:12px;
    background:rgba(255,255,255,0.08);border:1px solid rgba(255,255,255,0.12);
    border-radius:10px;padding:12px 16px;
  }
  .ll-feat-check{
    width:22px;height:22px;border-radius:6px;background:rgba(255,255,255,0.15);
    display:flex;align-items:center;justify-content:center;
    font-size:12px;color:#fff;flex-shrink:0;font-weight:700;
  }
  .ll-feat span{font-size:13px;color:rgba(255,255,255,0.85);font-weight:500;}

  /* Right — white form panel */
  .login-right{
    width:500px;flex-shrink:0;background:#fff;
    display:flex;align-items:center;justify-content:center;
    padding:48px 40px;
  }
  @media(max-width:860px){.login-right{width:100%;}}
  .login-card{width:100%;max-width:380px;}
  @keyframes cardIn{from{opacity:0;transform:translateY(16px);}to{opacity:1;transform:none;}}
  .login-card{animation:cardIn 0.4s ease both;}

  .lc-top{margin-bottom:36px;}
  .lc-eyebrow{
    display:inline-flex;align-items:center;gap:6px;
    background:#eff6ff;border:1px solid #bfdbfe;border-radius:20px;
    padding:4px 12px;font-size:11px;font-weight:700;color:#1d4ed8;
    letter-spacing:0.06em;text-transform:uppercase;margin-bottom:18px;
  }
  .lc-eyebrow .status-dot{width:6px;height:6px;border-radius:50%;background:#16a34a;}
  .lc-title{font-size:26px;font-weight:900;color:#0f172a;letter-spacing:-0.8px;margin-bottom:6px;}
  .lc-sub{font-size:14px;color:#64748b;line-height:1.5;}

  /* fields */
  .lc-field{margin-bottom:20px;}
  .lc-field label{
    display:block;font-size:12px;font-weight:600;color:#374151;margin-bottom:7px;
  }
  .lc-inp-wrap{position:relative;}
  .lc-inp-icon{
    position:absolute;left:13px;top:50%;transform:translateY(-50%);
    width:18px;height:18px;display:flex;align-items:center;justify-content:center;
    color:#9ca3af;font-size:14px;pointer-events:none;
  }
  .lc-field input{
    width:100%;background:#f8fafc;border:1.5px solid #e2e8f0;border-radius:10px;
    padding:12px 40px 12px 40px;color:#0f172a;font-size:14px;font-family:inherit;
    outline:none;transition:border-color 0.15s,box-shadow 0.15s,background 0.15s;
  }
  .lc-field input::placeholder{color:#b0b8c4;}
  .lc-field input:focus{
    border-color:#2563eb;background:#fff;
    box-shadow:0 0 0 3px rgba(37,99,235,0.1);
  }
  .lc-eye{
    position:absolute;right:12px;top:50%;transform:translateY(-50%);
    background:none;border:none;cursor:pointer;color:#9ca3af;font-size:14px;
    padding:4px;transition:color 0.15s;line-height:1;
  }
  .lc-eye:hover{color:#374151;}

  /* divider */
  .lc-divider{height:1px;background:#f1f5f9;margin:4px 0 20px;}

  /* sign in button */
  .btn-login{
    width:100%;padding:13px 20px;border:none;border-radius:10px;
    background:#2563eb;color:#fff;font-size:15px;font-weight:700;font-family:inherit;
    cursor:pointer;position:relative;overflow:hidden;
    transition:background 0.15s,transform 0.1s,box-shadow 0.15s;
    box-shadow:0 1px 3px rgba(37,99,235,0.3),0 4px 12px rgba(37,99,235,0.2);
  }
  .btn-login:hover{background:#1d4ed8;transform:translateY(-1px);box-shadow:0 4px 16px rgba(37,99,235,0.35);}
  .btn-login:active{transform:none;background:#1e40af;}
  .btn-login:disabled{background:#93c5fd;cursor:not-allowed;transform:none;box-shadow:none;}

  /* error */
  .err-msg{
    background:#fef2f2;border:1px solid #fecaca;border-radius:8px;
    padding:10px 14px;font-size:13px;color:#dc2626;margin-top:14px;display:none;
  }
  @keyframes shake{0%,100%{transform:none;}20%,60%{transform:translateX(-5px);}40%,80%{transform:translateX(5px);}}
  .err-msg.shake{animation:shake 0.3s ease;}

  /* footer */
  .lc-footer{
    display:flex;align-items:center;justify-content:center;gap:6px;
    margin-top:24px;font-size:11px;color:#94a3b8;
  }
  .lc-footer svg{opacity:0.5;}

  /* spinner */
  .spinner{display:inline-block;width:15px;height:15px;border:2px solid rgba(255,255,255,0.35);border-top-color:#fff;border-radius:50%;animation:spin 0.65s linear infinite;vertical-align:middle;margin-right:6px;}
  @keyframes spin{to{transform:rotate(360deg)}}

  /* ═══════════════════════════ DASHBOARD ═══════════════════════════ */
  #dashboard{display:none}

  /* topbar */
  .topbar{
    background:#fff;border-bottom:1px solid #e2e8f0;
    padding:0 32px;height:60px;
    display:flex;align-items:center;justify-content:space-between;
    position:sticky;top:0;z-index:100;
    box-shadow:0 1px 3px rgba(0,0,0,0.06);
  }
  .topbar-left{display:flex;align-items:center;gap:12px;}
  .topbar-logo{
    width:36px;height:36px;background:linear-gradient(135deg,#2563eb,#4f46e5);
    border-radius:10px;display:flex;align-items:center;justify-content:center;
    font-size:18px;
  }
  .topbar-title{font-size:16px;font-weight:800;color:#0f172a;letter-spacing:-0.3px;}
  .topbar-sub{font-size:12px;color:#94a3b8;margin-top:1px;}
  .topbar-right{display:flex;align-items:center;gap:12px;}
  .topbar-badge{
    background:#eff6ff;border:1px solid #bfdbfe;border-radius:20px;
    padding:3px 10px;font-size:11px;font-weight:700;color:#2563eb;
  }
  .logout-btn{
    background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;
    color:#374151;padding:7px 14px;font-size:13px;font-weight:600;
    cursor:pointer;font-family:inherit;transition:background 0.12s,border-color 0.12s;
  }
  .logout-btn:hover{background:#f1f5f9;border-color:#cbd5e1;}

  /* content */
  .content{max-width:1000px;margin:0 auto;padding:32px 24px;}

  /* page header inside dashboard */
  .page-header{margin-bottom:24px;}
  .page-header h2{font-size:20px;font-weight:800;color:#0f172a;letter-spacing:-0.4px;}
  .page-header p{font-size:13px;color:#64748b;margin-top:4px;}

  /* add card */
  .add-card{
    background:#fff;border:1px solid #e2e8f0;border-radius:14px;
    padding:24px 28px;margin-bottom:24px;
    box-shadow:0 1px 3px rgba(0,0,0,0.05);
  }
  .add-card-header{display:flex;align-items:center;gap:10px;margin-bottom:20px;}
  .add-card-icon{
    width:36px;height:36px;background:#eff6ff;border-radius:9px;
    display:flex;align-items:center;justify-content:center;font-size:17px;flex-shrink:0;
  }
  .add-card h3{font-size:15px;font-weight:700;color:#0f172a;}
  .add-card .sub{font-size:12px;color:#94a3b8;margin-top:1px;}

  .form-row{display:grid;grid-template-columns:1fr 1fr 1fr auto;gap:14px;align-items:end;}
  @media(max-width:720px){.form-row{grid-template-columns:1fr}}
  .field{margin-bottom:0;}
  .field label{display:block;font-size:12px;font-weight:600;color:#374151;margin-bottom:6px;}
  .field input{
    width:100%;background:#f8fafc;border:1.5px solid #e2e8f0;border-radius:9px;
    padding:10px 13px;color:#0f172a;font-size:13px;font-family:inherit;
    outline:none;transition:border-color 0.15s,box-shadow 0.15s,background 0.15s;
  }
  .field input:focus{border-color:#2563eb;background:#fff;box-shadow:0 0 0 3px rgba(37,99,235,0.1);}
  .field input::placeholder{color:#b0b8c4;}
  .btn-add{
    background:#2563eb;border:none;border-radius:9px;color:#fff;
    padding:10px 20px;font-size:13px;font-weight:700;cursor:pointer;
    white-space:nowrap;font-family:inherit;
    box-shadow:0 1px 3px rgba(37,99,235,0.25);transition:background 0.12s,transform 0.1s;
  }
  .btn-add:hover{background:#1d4ed8;transform:translateY(-1px);}
  .btn-add:active{transform:none;}

  .success-msg{
    background:#f0fdf4;border:1px solid #bbf7d0;border-radius:8px;
    padding:10px 14px;font-size:13px;color:#15803d;font-weight:600;
    margin-top:14px;display:none;
  }
  .err-msg-dash{
    background:#fef2f2;border:1px solid #fecaca;border-radius:8px;
    padding:10px 14px;font-size:13px;color:#dc2626;
    margin-top:14px;display:none;
  }

  /* shops card */
  .shops-card{
    background:#fff;border:1px solid #e2e8f0;border-radius:14px;overflow:hidden;
    box-shadow:0 1px 3px rgba(0,0,0,0.05);
  }
  .shops-card-header{
    padding:16px 24px;border-bottom:1px solid #f1f5f9;
    display:flex;align-items:center;justify-content:space-between;
    background:#fafafa;
  }
  .shops-card-header h3{font-size:14px;font-weight:700;color:#0f172a;}
  .count-badge{
    background:#eff6ff;border:1px solid #bfdbfe;border-radius:20px;
    padding:3px 10px;font-size:11px;font-weight:700;color:#2563eb;
  }

  table{width:100%;border-collapse:collapse;}
  th{
    background:#fafafa;padding:10px 20px;
    font-size:11px;font-weight:700;color:#6b7280;
    text-transform:uppercase;letter-spacing:0.06em;text-align:left;
    border-bottom:1px solid #f1f5f9;
  }
  td{padding:14px 20px;font-size:13px;border-top:1px solid #f8fafc;vertical-align:middle;color:#374151;}
  tr:hover td{background:#fafcff;}
  .shop-name{font-weight:700;color:#0f172a;font-size:14px;}
  .shop-domain{font-size:11px;color:#94a3b8;margin-top:2px;font-family:monospace;}
  .note-text{color:#94a3b8;font-size:12px;font-style:italic;}
  .tag{display:inline-flex;align-items:center;gap:5px;border-radius:20px;padding:3px 10px;font-size:11px;font-weight:700;}
  .tag-dot{width:6px;height:6px;border-radius:50%;flex-shrink:0;}
  .tag-ok{background:#f0fdf4;color:#15803d;border:1px solid #bbf7d0;}
  .tag-ok .tag-dot{background:#16a34a;}
  .tag-exp{background:#fef2f2;color:#dc2626;border:1px solid #fecaca;}
  .tag-exp .tag-dot{background:#dc2626;}
  .tag-perm{background:#eff6ff;color:#2563eb;border:1px solid #bfdbfe;}
  .tag-perm .tag-dot{background:#2563eb;}
  .date-cell{font-size:12px;color:#6b7280;}
  .btn-del{
    background:#fef2f2;border:1px solid #fecaca;border-radius:6px;
    color:#dc2626;padding:5px 12px;font-size:12px;font-weight:600;
    cursor:pointer;font-family:inherit;transition:background 0.12s;
  }
  .btn-del:hover{background:#fee2e2;}
  .btn-grant{
    background:#eff6ff;border:1px solid #bfdbfe;border-radius:6px;
    color:#2563eb;padding:5px 12px;font-size:12px;font-weight:600;
    cursor:pointer;font-family:inherit;transition:background 0.12s;
  }
  .btn-grant:hover{background:#dbeafe;}
  .note-cell{max-width:180px;}
  .empty-state{padding:56px 24px;text-align:center;}
  .empty-state .icon{font-size:38px;margin-bottom:12px;}
  .empty-state p{font-size:14px;color:#94a3b8;font-weight:500;}
  .empty-state small{font-size:12px;color:#b0b8c4;display:block;margin-top:4px;}
  .loading-row{padding:32px;text-align:center;}
  .spinner-dark{display:inline-block;width:20px;height:20px;border:2px solid #e2e8f0;border-top-color:#2563eb;border-radius:50%;animation:spin 0.7s linear infinite;}

  /* ═══ NAV TABS ═══ */
  .topbar-nav{display:flex;gap:3px;background:#f1f5f9;border-radius:10px;padding:4px;}
  .nav-tab{background:none;border:none;border-radius:7px;padding:7px 18px;font-size:13px;font-weight:600;color:#64748b;cursor:pointer;font-family:inherit;transition:background 0.12s,color 0.12s;display:flex;align-items:center;gap:6px;}
  .nav-tab.active{background:#fff;color:#0f172a;box-shadow:0 1px 3px rgba(0,0,0,0.08);}
  .nav-tab:hover:not(.active){background:rgba(255,255,255,0.6);}
  .nav-badge{display:inline-flex;align-items:center;justify-content:center;min-width:16px;height:16px;background:#ef4444;border-radius:8px;font-size:10px;font-weight:700;color:#fff;padding:0 3px;}

  /* ═══ CHAT LAYOUT ═══ */
  #section-chat{height:calc(100vh - 61px);overflow:hidden;display:none;}
  .chat-wrap{display:flex;height:100%;}
  .chat-sidebar{width:300px;flex-shrink:0;background:#fff;border-right:1px solid #e2e8f0;display:flex;flex-direction:column;overflow:hidden;}
  .chat-sidebar-head{padding:16px 18px;border-bottom:1px solid #f1f5f9;background:#fafafa;}
  .chat-sidebar-head h3{font-size:15px;font-weight:800;color:#0f172a;margin-bottom:10px;}
  .chat-search{width:100%;background:#f1f5f9;border:none;border-radius:8px;padding:8px 12px;font-size:13px;font-family:inherit;outline:none;color:#0f172a;}
  .chat-list{flex:1;overflow-y:auto;}
  .chat-item{padding:13px 18px;cursor:pointer;display:flex;align-items:center;gap:12px;border-bottom:1px solid #f8fafc;transition:background 0.1s;}
  .chat-item:hover{background:#f8fafc;}
  .chat-item.active{background:#eff6ff;}
  .chat-avatar{width:42px;height:42px;background:linear-gradient(135deg,#2563eb,#4f46e5);border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:14px;font-weight:800;color:#fff;flex-shrink:0;}
  .chat-item-meta{flex:1;min-width:0;}
  .chat-item-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:3px;}
  .chat-item-shop{font-size:13px;font-weight:700;color:#0f172a;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:155px;}
  .chat-item-time{font-size:11px;color:#94a3b8;flex-shrink:0;margin-left:6px;}
  .chat-item-bot{display:flex;justify-content:space-between;align-items:center;}
  .chat-item-preview{font-size:12px;color:#64748b;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:185px;}
  .chat-unread{min-width:18px;height:18px;background:#2563eb;border-radius:9px;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;color:#fff;padding:0 4px;flex-shrink:0;margin-left:6px;}

  .chat-panel{flex:1;display:flex;flex-direction:column;overflow:hidden;}
  .chat-panel-empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#94a3b8;}
  .chat-panel-empty .icon{font-size:52px;margin-bottom:16px;}
  .chat-panel-empty p{font-size:15px;font-weight:600;color:#374151;margin-bottom:6px;}
  .chat-panel-empty small{font-size:13px;}
  .chat-active{flex:1;display:none;flex-direction:column;overflow:hidden;}
  .chat-active.open{display:flex;}
  .chat-hdr{padding:14px 24px;background:#fff;border-bottom:1px solid #e2e8f0;display:flex;align-items:center;gap:12px;flex-shrink:0;}
  .chat-hdr-avatar{width:40px;height:40px;background:linear-gradient(135deg,#2563eb,#4f46e5);border-radius:12px;display:flex;align-items:center;justify-content:center;font-size:15px;font-weight:800;color:#fff;flex-shrink:0;}
  .chat-hdr-shop{font-size:14px;font-weight:700;color:#0f172a;}
  .chat-hdr-sub{font-size:12px;color:#94a3b8;margin-top:1px;}
  .chat-msgs{flex:1;overflow-y:auto;padding:20px 24px;display:flex;flex-direction:column;gap:12px;background:#f8fafc;}
  .chat-bubble-wrap{display:flex;flex-direction:column;}
  .chat-bubble-wrap.admin{align-items:flex-end;}
  .chat-bubble-wrap.customer{align-items:flex-start;}
  .chat-bubble{max-width:70%;padding:10px 14px;font-size:14px;line-height:1.55;box-shadow:0 1px 3px rgba(0,0,0,0.07);}
  .chat-bubble.admin{background:#2563eb;color:#fff;border-radius:16px 16px 4px 16px;}
  .chat-bubble.customer{background:#fff;color:#0f172a;border-radius:16px 16px 16px 4px;border:1px solid #f1f5f9;}
  .chat-bubble-time{font-size:11px;color:#94a3b8;margin-top:4px;}
  .chat-input-row{padding:14px 20px;background:#fff;border-top:1px solid #e2e8f0;display:flex;gap:10px;align-items:flex-end;flex-shrink:0;}
  .chat-textarea{flex:1;background:#f8fafc;border:1.5px solid #e2e8f0;border-radius:10px;padding:10px 14px;font-size:14px;font-family:inherit;outline:none;color:#0f172a;resize:none;line-height:1.5;max-height:120px;}
  .chat-textarea:focus{border-color:#2563eb;background:#fff;box-shadow:0 0 0 3px rgba(37,99,235,0.08);}
  .chat-send{background:#2563eb;border:none;border-radius:10px;color:#fff;padding:10px 22px;font-size:14px;font-weight:700;cursor:pointer;font-family:inherit;white-space:nowrap;flex-shrink:0;transition:background 0.12s;}
  .chat-send:hover{background:#1d4ed8;}
  .chat-send:disabled{background:#93c5fd;cursor:not-allowed;}
</style>
</head>
<body>

<!-- ═══════════════════════════ LOGIN ═══════════════════════════ -->
<div id="login-screen">

  <!-- Left branding panel -->
  <div class="login-left">
    <div class="ll-logo">
      <div class="ll-icon">🛡️</div>
      <div class="ll-brand">Data4Autos <span>Admin Portal</span></div>
    </div>
    <div class="ll-heading">Manage <em>free access</em><br>with confidence</div>
    <div class="ll-desc">Grant, revoke, and schedule free-access windows for any Shopify store — no code changes, no redeployment needed.</div>
    <div class="ll-features">
      <div class="ll-feat"><div class="ll-feat-check">✓</div><span>Grant free access to any Shopify store</span></div>
      <div class="ll-feat"><div class="ll-feat-check">✓</div><span>Set custom expiry dates per shop</span></div>
      <div class="ll-feat"><div class="ll-feat-check">✓</div><span>Changes take effect instantly</span></div>
      <div class="ll-feat"><div class="ll-feat-check">✓</div><span>Persisted to disk — survives restarts</span></div>
    </div>
  </div>

  <!-- Right login panel -->
  <div class="login-right">
    <div class="login-card">
      <div class="lc-top">
        <div class="lc-eyebrow"><div class="status-dot"></div>Secure Portal</div>
        <div class="lc-title">Welcome back</div>
        <div class="lc-sub">Sign in to manage shop access permissions.</div>
      </div>

      <div class="lc-divider"></div>

      <div class="lc-field">
        <label for="inp-user">Username</label>
        <div class="lc-inp-wrap">
          <span class="lc-inp-icon">👤</span>
          <input type="text" id="inp-user" placeholder="d4a-admin" autocomplete="username"/>
        </div>
      </div>

      <div class="lc-field">
        <label for="inp-pass">Password</label>
        <div class="lc-inp-wrap">
          <span class="lc-inp-icon">🔒</span>
          <input type="password" id="inp-pass" placeholder="••••••••••••" autocomplete="current-password"/>
          <button class="lc-eye" id="eye-btn" onclick="togglePass()" type="button" tabindex="-1">👁</button>
        </div>
      </div>

      <button class="btn-login" id="login-btn" onclick="doLogin()">
        Sign In to Admin Portal
      </button>

      <div class="err-msg" id="login-err"></div>

      <div class="lc-footer">
        <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>
        Session secured · Expires in 8 hours
      </div>
    </div>
  </div>
</div>

<!-- ═══════════════════════════ DASHBOARD ═══════════════════════════ -->
<div id="dashboard">

  <div class="topbar">
    <div class="topbar-left">
      <div class="topbar-logo">🛡️</div>
      <div>
        <div class="topbar-title">Data4Autos Admin</div>
        <div class="topbar-sub">Free Access Manager</div>
      </div>
    </div>
    <div class="topbar-nav">
      <button class="nav-tab active" id="tab-users" onclick="showTab('users')">👥 Users</button>
      <button class="nav-tab" id="tab-chat" onclick="showTab('chat')">
        💬 Chat <span class="nav-badge" id="chat-unread-badge" style="display:none">0</span>
      </button>
    </div>
    <div class="topbar-right">
      <span class="topbar-badge" id="shops-count">0 users</span>
      <button class="logout-btn" onclick="doLogout()">Sign Out</button>
    </div>
  </div>

  <div id="section-users">
  <div class="content">
    <div class="page-header">
      <h2>App Users</h2>
      <p>All shops that have installed Data4Autos. Toggle free access directly from this list.</p>
    </div>

    <!-- Grant expiry modal -->
    <div id="expiry-modal" style="display:none;position:fixed;inset:0;background:rgba(15,23,42,0.4);z-index:999;align-items:center;justify-content:center;">
      <div style="background:#fff;border-radius:16px;padding:32px 28px;width:100%;max-width:400px;box-shadow:0 20px 60px rgba(0,0,0,0.15);margin:0 16px;">
        <div style="font-size:16px;font-weight:800;color:#0f172a;margin-bottom:6px;">Grant Free Access</div>
        <div id="modal-shop-name" style="font-size:13px;color:#64748b;margin-bottom:20px;font-family:monospace;"></div>
        <div class="field" style="margin-bottom:14px;">
          <label>Expiry Date <span style="color:#b0b8c4;font-weight:400">(blank = permanent)</span></label>
          <input type="date" id="modal-expires" style="width:100%;background:#f8fafc;border:1.5px solid #e2e8f0;border-radius:9px;padding:10px 13px;font-size:13px;font-family:inherit;outline:none;color:#0f172a;"/>
        </div>
        <div class="field" style="margin-bottom:20px;">
          <label>Note <span style="color:#b0b8c4;font-weight:400">(optional)</span></label>
          <input type="text" id="modal-note" placeholder="e.g. Partner shop" style="width:100%;background:#f8fafc;border:1.5px solid #e2e8f0;border-radius:9px;padding:10px 13px;font-size:13px;font-family:inherit;outline:none;color:#0f172a;"/>
        </div>
        <div style="display:flex;gap:10px;">
          <button onclick="confirmGrant()" style="flex:1;background:#2563eb;border:none;border-radius:9px;color:#fff;padding:11px;font-size:14px;font-weight:700;cursor:pointer;font-family:inherit;">Grant Access</button>
          <button onclick="closeModal()" style="flex:1;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:9px;color:#374151;padding:11px;font-size:14px;font-weight:600;cursor:pointer;font-family:inherit;">Cancel</button>
        </div>
      </div>
    </div>

    <!-- Users table -->
    <div class="shops-card">
      <div class="shops-card-header">
        <h3>Installed Shops</h3>
        <div style="display:flex;align-items:center;gap:10px;">
          <input id="search-inp" placeholder="Search shops…" oninput="filterUsers()" style="background:#f8fafc;border:1.5px solid #e2e8f0;border-radius:8px;padding:6px 12px;font-size:13px;font-family:inherit;outline:none;color:#0f172a;width:200px;"/>
          <span class="count-badge" id="shops-count-table">0 shops</span>
        </div>
      </div>
      <div id="shops-table-wrap">
        <div class="loading-row"><div class="spinner-dark"></div></div>
      </div>
    </div>

  </div>
  </div><!-- /section-users -->

  <!-- ═══ CHAT SECTION ═══ -->
  <div id="section-chat">
    <div class="chat-wrap">

      <!-- Left sidebar -->
      <div class="chat-sidebar">
        <div class="chat-sidebar-head">
          <h3>Messages</h3>
          <input class="chat-search" id="chat-search" placeholder="Search shops…" oninput="filterChats()"/>
        </div>
        <div class="chat-list" id="chat-list">
          <div class="loading-row"><div class="spinner-dark"></div></div>
        </div>
      </div>

      <!-- Right panel -->
      <div class="chat-panel">
        <div class="chat-panel-empty" id="chat-empty">
          <div class="icon">💬</div>
          <p>Select a conversation</p>
          <small>Choose a shop from the left to view messages</small>
        </div>
        <div class="chat-active" id="chat-active">
          <div class="chat-hdr">
            <div class="chat-hdr-avatar" id="chat-hdr-avatar"></div>
            <div>
              <div class="chat-hdr-shop" id="chat-hdr-shop"></div>
              <div class="chat-hdr-sub">Customer Support</div>
            </div>
          </div>
          <div class="chat-msgs" id="chat-msgs"></div>
          <div class="chat-input-row">
            <textarea class="chat-textarea" id="chat-input" rows="2" placeholder="Type a reply… (Enter to send, Shift+Enter for new line)"
              onkeydown="if(event.key==='Enter'&&!event.shiftKey){event.preventDefault();sendReply();}"></textarea>
            <button class="chat-send" id="chat-send-btn" onclick="sendReply()">Send</button>
          </div>
        </div>
      </div>

    </div>
  </div><!-- /section-chat -->

</div>

<script>
const BASE = '/d4a-admin';

async function api(method, path, body) {
  const opts = { method, headers: { 'Content-Type': 'application/json' }, credentials: 'include' };
  if (body) opts.body = JSON.stringify(body);
  const r = await fetch(BASE + path, opts);
  return { ok: r.ok, status: r.status, data: await r.json().catch(() => ({})) };
}

// ── AUTH CHECK ──────────────────────────────────────────────────────────────
async function checkAuth() {
  const r = await api('GET', '/api/check-auth');
  if (r.ok) showDashboard();
}
checkAuth();

// ── PASSWORD TOGGLE ──────────────────────────────────────────────────────────
function togglePass() {
  const inp = document.getElementById('inp-pass');
  const btn = document.getElementById('eye-btn');
  if (inp.type === 'password') { inp.type = 'text'; btn.textContent = '🙈'; }
  else { inp.type = 'password'; btn.textContent = '👁'; }
}

// ── LOGIN ───────────────────────────────────────────────────────────────────
async function doLogin() {
  const btn = document.getElementById('login-btn');
  const err = document.getElementById('login-err');
  const user = document.getElementById('inp-user').value.trim();
  const pass = document.getElementById('inp-pass').value;
  btn.disabled = true;
  btn.innerHTML = '<span class="spinner"></span> Signing in…';
  err.style.display = 'none';

  const r = await api('POST', '/login', { username: user, password: pass });
  btn.disabled = false;
  btn.textContent = 'Sign In to Admin Portal';
  if (r.ok) {
    showDashboard();
  } else {
    err.textContent = '⚠️ ' + (r.data.error || 'Invalid credentials');
    err.style.display = 'block';
  }
}
document.addEventListener('keydown', e => { if (e.key === 'Enter') doLogin(); });

// ── LOGOUT ──────────────────────────────────────────────────────────────────
async function doLogout() {
  await api('POST', '/logout');
  document.getElementById('dashboard').style.display = 'none';
  document.getElementById('login-screen').style.display = 'flex';
  document.getElementById('inp-user').value = '';
  document.getElementById('inp-pass').value = '';
}

// ── SHOW DASHBOARD ──────────────────────────────────────────────────────────
function showDashboard() {
  document.getElementById('login-screen').style.display = 'none';
  document.getElementById('dashboard').style.display = 'block';
  showTab('users');
}

// ── TAB SWITCHING ────────────────────────────────────────────────────────────
let chatPollInterval = null;

function showTab(tab) {
  document.getElementById('section-users').style.display = tab === 'users' ? 'block' : 'none';
  document.getElementById('section-chat').style.display  = tab === 'chat'  ? 'block' : 'none';
  document.getElementById('tab-users').classList.toggle('active', tab === 'users');
  document.getElementById('tab-chat').classList.toggle('active',  tab === 'chat');
  if (tab === 'users') {
    loadUsers();
    if (chatPollInterval) { clearInterval(chatPollInterval); chatPollInterval = null; }
  } else {
    loadChatList();
    if (!chatPollInterval) chatPollInterval = setInterval(() => {
      loadChatListSilent();
      if (selectedChatShop) loadMessages(selectedChatShop, false);
    }, 3000);
  }
}

// ── ALL USERS DATA ───────────────────────────────────────────────────────────
let allUsers = [];

async function loadUsers() {
  const wrap = document.getElementById('shops-table-wrap');
  wrap.innerHTML = '<div class="loading-row"><div class="spinner-dark"></div></div>';
  const r = await api('GET', '/api/users');
  if (!r.ok) { wrap.innerHTML = '<div class="empty-state"><p>Failed to load users.</p></div>'; return; }
  allUsers = r.data.users || [];
  document.getElementById('shops-count').textContent = allUsers.length + ' user' + (allUsers.length !== 1 ? 's' : '');
  renderUsers(allUsers);
}

function filterUsers() {
  const q = document.getElementById('search-inp').value.toLowerCase();
  renderUsers(q ? allUsers.filter(u => u.shop.toLowerCase().includes(q)) : allUsers);
}

function renderUsers(users) {
  const wrap = document.getElementById('shops-table-wrap');
  document.getElementById('shops-count-table').textContent = users.length + ' shop' + (users.length !== 1 ? 's' : '');

  if (users.length === 0) {
    wrap.innerHTML = '<div class="empty-state"><div class="icon">🏪</div><p>No shops found.</p></div>';
    return;
  }

  const rows = users.map(u => {
    const lastSeen = u.savedAt
      ? new Date(u.savedAt).toLocaleDateString(undefined,{year:'numeric',month:'short',day:'numeric'})
      : '—';

    let statusTag, actionBtn;
    if (u.freeAccess) {
      const fa = u.freeEntry;
      const expLabel = fa?.expiresAt
        ? 'Until ' + new Date(fa.expiresAt).toLocaleDateString(undefined,{month:'short',day:'numeric',year:'numeric'})
        : 'Permanent';
      statusTag = \`<span class="tag tag-ok"><span class="tag-dot"></span>Free Access · \${expLabel}</span>\`;
      actionBtn = \`<button class="btn-del" onclick="doRevoke('\${escHtml(u.shop)}')">Revoke</button>\`;
    } else {
      statusTag = '<span class="tag" style="background:#f8fafc;color:#94a3b8;border:1px solid #e2e8f0;"><span class="tag-dot" style="background:#cbd5e1;"></span>Subscribed</span>';
      actionBtn = \`<button class="btn-grant" onclick="openModal('\${escHtml(u.shop)}')">Grant Free</button>\`;
    }

    return \`<tr data-shop="\${escHtml(u.shop)}">
      <td>
        <div class="shop-name">\${escHtml(u.shop)}</div>
        <div class="shop-domain">Last auth: \${lastSeen}</div>
      </td>
      <td>\${statusTag}</td>
      <td class="note-cell"><span class="note-text">\${escHtml(u.freeEntry?.note || '—')}</span></td>
      <td style="text-align:right">\${actionBtn}</td>
    </tr>\`;
  }).join('');

  wrap.innerHTML = \`<table>
    <thead><tr>
      <th>Shop Domain</th>
      <th>Access Status</th>
      <th>Note</th>
      <th></th>
    </tr></thead>
    <tbody>\${rows}</tbody>
  </table>\`;
}

// ── MODAL ────────────────────────────────────────────────────────────────────
let _modalShop = null;

function openModal(shop) {
  _modalShop = shop;
  document.getElementById('modal-shop-name').textContent = shop;
  document.getElementById('modal-expires').value = '';
  document.getElementById('modal-note').value = '';
  const m = document.getElementById('expiry-modal');
  m.style.display = 'flex';
}

function closeModal() {
  document.getElementById('expiry-modal').style.display = 'none';
  _modalShop = null;
}

async function confirmGrant() {
  if (!_modalShop) return;
  const expires = document.getElementById('modal-expires').value || null;
  const note    = document.getElementById('modal-note').value.trim();
  const expiresAt = expires ? new Date(expires + 'T23:59:59.000Z').toISOString() : null;
  const r = await api('POST', '/api/shops', { shop: _modalShop, expiresAt, note });
  if (r.ok) { closeModal(); loadUsers(); }
  else alert('Failed to grant access: ' + (r.data.error || 'Unknown error'));
}

// ── REVOKE ───────────────────────────────────────────────────────────────────
async function doRevoke(shop) {
  if (!confirm('Revoke free access for ' + shop + '? They will need an active subscription.')) return;
  const r = await api('DELETE', '/api/shops/' + encodeURIComponent(shop));
  if (r.ok) loadUsers();
  else alert('Failed to revoke access');
}

// ── CHAT ─────────────────────────────────────────────────────────────────────
let allChats = [];
let selectedChatShop = null;

async function loadChatList() {
  const el = document.getElementById('chat-list');
  el.innerHTML = '<div class="loading-row"><div class="spinner-dark"></div></div>';
  const r = await api('GET', '/api/chats');
  if (!r.ok) { el.innerHTML = '<div style="padding:20px;text-align:center;color:#94a3b8;font-size:13px;">Failed to load</div>'; return; }
  allChats = r.data.chats || [];
  updateChatBadge();
  renderChatList(allChats);
}

async function loadChatListSilent() {
  const r = await api('GET', '/api/chats');
  if (!r.ok) return;
  allChats = r.data.chats || [];
  updateChatBadge();
  renderChatList(allChats);
}

function updateChatBadge() {
  const total = allChats.reduce((s, c) => s + (c.unread || 0), 0);
  const badge = document.getElementById('chat-unread-badge');
  if (total > 0) { badge.textContent = total > 99 ? '99+' : total; badge.style.display = 'inline-flex'; }
  else badge.style.display = 'none';
}

function filterChats() {
  const q = document.getElementById('chat-search').value.toLowerCase();
  renderChatList(q ? allChats.filter(c => c.shop.toLowerCase().includes(q)) : allChats);
}

function renderChatList(chats) {
  const el = document.getElementById('chat-list');
  if (chats.length === 0) {
    el.innerHTML = '<div style="padding:32px 16px;text-align:center;color:#94a3b8;font-size:13px;">No conversations yet</div>';
    return;
  }
  el.innerHTML = chats.map(c => {
    const isActive = c.shop === selectedChatShop;
    const preview = c.lastMessage ? escHtml(c.lastMessage.text.slice(0,42) + (c.lastMessage.text.length > 42 ? '…' : '')) : '<em>No messages yet</em>';
    const t = c.lastMessage ? fmtTime(c.lastMessage.timestamp) : '';
    const initials = c.shop.slice(0,2).toUpperCase();
    const unreadBadge = c.unread > 0 ? \`<div class="chat-unread">\${c.unread > 99 ? '99+' : c.unread}</div>\` : '';
    return \`<div class="chat-item\${isActive ? ' active' : ''}" onclick="selectChat('\${escHtml(c.shop)}')">
      <div class="chat-avatar">\${initials}</div>
      <div class="chat-item-meta">
        <div class="chat-item-top">
          <div class="chat-item-shop">\${escHtml(c.shop)}</div>
          <div class="chat-item-time">\${t}</div>
        </div>
        <div class="chat-item-bot">
          <div class="chat-item-preview">\${preview}</div>
          \${unreadBadge}
        </div>
      </div>
    </div>\`;
  }).join('');
}

async function selectChat(shop) {
  selectedChatShop = shop;
  document.getElementById('chat-empty').style.display = 'none';
  const active = document.getElementById('chat-active');
  active.classList.add('open');
  document.getElementById('chat-hdr-shop').textContent = shop;
  document.getElementById('chat-hdr-avatar').textContent = shop.slice(0,2).toUpperCase();
  renderChatList(allChats);
  await loadMessages(shop, true);
}

async function loadMessages(shop, scrollToBottom) {
  const r = await api('GET', '/api/chats/' + encodeURIComponent(shop));
  if (!r.ok) return;
  // clear unread in local data
  const idx = allChats.findIndex(c => c.shop === shop);
  if (idx !== -1) { allChats[idx].unread = 0; updateChatBadge(); }
  const msgs = r.data.messages || [];
  const el = document.getElementById('chat-msgs');
  const wasAtBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 60;
  if (msgs.length === 0) {
    el.innerHTML = '<div style="text-align:center;color:#94a3b8;font-size:13px;margin-top:40px;">No messages yet.<br>Customer messages from the widget will appear here.</div>';
    return;
  }
  el.innerHTML = msgs.map(m => {
    const isAdmin = m.from === 'admin';
    const time = new Date(m.timestamp).toLocaleTimeString(undefined,{hour:'2-digit',minute:'2-digit'});
    return \`<div class="chat-bubble-wrap \${isAdmin ? 'admin' : 'customer'}">
      <div class="chat-bubble \${isAdmin ? 'admin' : 'customer'}">\${escHtml(m.text)}</div>
      <div class="chat-bubble-time">\${isAdmin ? 'You · ' : ''}\${time}</div>
    </div>\`;
  }).join('');
  if (scrollToBottom || wasAtBottom) el.scrollTop = el.scrollHeight;
}

async function sendReply() {
  if (!selectedChatShop) return;
  const inp = document.getElementById('chat-input');
  const btn = document.getElementById('chat-send-btn');
  const text = inp.value.trim();
  if (!text) return;
  btn.disabled = true;
  const r = await api('POST', '/api/chats/' + encodeURIComponent(selectedChatShop) + '/reply', { text });
  btn.disabled = false;
  if (r.ok) { inp.value = ''; await loadMessages(selectedChatShop, true); loadChatListSilent(); }
  else alert('Failed to send reply');
}

function fmtTime(ts) {
  if (!ts) return '';
  const d = new Date(ts), now = new Date(), diff = now - d;
  if (diff < 60000) return 'now';
  if (diff < 3600000) return Math.floor(diff/60000) + 'm';
  if (diff < 86400000) return d.toLocaleTimeString(undefined,{hour:'2-digit',minute:'2-digit'});
  return d.toLocaleDateString(undefined,{month:'short',day:'numeric'});
}

// ── UTIL ──────────────────────────────────────────────────────────────────────
function escHtml(s) {
  return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
}
</script>
</body>
</html>`;
}

module.exports = router;
