// script.js — Airport NavCom E-Inspection System (vanilla SPA)
'use strict';

const state = { role: null, userId: null, userName: null, today: '2026-06-03' };
const THEME_STORAGE_KEY = 'navcom-theme';
const AVAILABLE_THEMES = ['default', 'light', 'dark'];

// ---------- tiny helpers ----------
const $ = (sel) => document.querySelector(sel);
const h = (html) => { const t = document.createElement('template'); t.innerHTML = html.trim(); return t.content.firstElementChild; };
const esc = (s) => String(s ?? '').replace(/[&<>"']/g, c => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]));

async function api(path, opts = {}) {
  const res = await fetch('/api' + path, {
    headers: { 'Content-Type': 'application/json' },
    ...opts,
    body: opts.body ? JSON.stringify(opts.body) : undefined
  });
  const data = res.status === 204 ? null : await res.json().catch(() => null);
  if (!res.ok) throw new Error((data && data.error) || ('Request failed (' + res.status + ')'));
  return data;
}

function toast(msg, type = '') {
  const t = $('#toast');
  t.textContent = msg; t.className = 'toast ' + type;
  setTimeout(() => t.classList.add('hidden'), 2600);
}

function applyTheme(theme) {
  const t = AVAILABLE_THEMES.includes(theme) ? theme : 'default';
  document.body.classList.remove(...AVAILABLE_THEMES.map(v => `theme-${v}`));
  document.body.classList.add(`theme-${t}`);
  ['theme-select', 'login-theme-select'].forEach(id => {
    const sel = document.getElementById(id);
    if (sel) sel.value = t;
  });
  localStorage.setItem(THEME_STORAGE_KEY, t);
}

function initTheme() {
  const saved = localStorage.getItem(THEME_STORAGE_KEY);
  applyTheme(saved || 'default');
}

function bindThemeSelectors() {
  ['theme-select', 'login-theme-select'].forEach(id => {
    const select = document.getElementById(id);
    if (select) select.onchange = (e) => applyTheme(e.target.value);
  });
}

function loading(node) { node.innerHTML = '<div class="state"><div class="spinner"></div>Loading…</div>'; }
function emptyState(msg) { return `<div class="state"><div class="big">📭</div>${esc(msg)}</div>`; }
function errorState(msg) { return `<div class="state error-state"><div class="big">⚠️</div>${esc(msg)}</div>`; }

// status -> badge class
function badge(status) {
  const map = {
    'Scheduled': 'b-grey', 'Assigned': 'b-blue', 'In Progress': 'b-amber',
    'Awaiting Validation': 'b-purple', 'Needs Revision': 'b-red', 'Completed': 'b-green',
    'Overdue': 'b-red', 'Cancelled': 'b-grey', 'Rescheduled': 'b-grey',
    'Created': 'b-amber', 'Awaiting Review': 'b-amber', 'Accepted': 'b-blue',
    'Assigned for Follow-Up': 'b-blue', 'In Follow-Up': 'b-blue', 'Awaiting Verification': 'b-purple',
    'Resolved': 'b-green', 'Closed': 'b-green', 'Escalated': 'b-red'
  };
  return `<span class="badge ${map[status] || 'b-grey'}">${esc(status)}</span>`;
}
function urgencyBadge(u) {
  const map = { low: 'b-grey', medium: 'b-amber', high: 'b-red', critical: 'b-red' };
  return `<span class="badge ${map[u] || 'b-grey'}">${esc(u)}</span>`;
}

// ---------- modal ----------
function openModal(title, bodyNode) {
  $('#modal-title').textContent = title;
  const body = $('#modal-body'); body.innerHTML = ''; body.appendChild(bodyNode);
  $('#modal').classList.remove('hidden');
}
function closeModal() { $('#modal').classList.add('hidden'); }
$('#modal-close').onclick = closeModal;
$('#modal').onclick = (e) => { if (e.target.id === 'modal') closeModal(); };

// Generic form modal. fields: [{name,label,type,options,value,required,placeholder}]
function formModal(title, fields, submitLabel, onSubmit) {
  const form = h('<form></form>');
  fields.forEach(f => {
    const wrap = h('<div class="field"></div>');
    wrap.appendChild(h(`<label>${esc(f.label)}${f.required ? ' *' : ''}</label>`));
    let input;
    if (f.type === 'textarea') input = h(`<textarea name="${f.name}" placeholder="${esc(f.placeholder || '')}"></textarea>`);
    else if (f.type === 'select') {
      input = h(`<select name="${f.name}"></select>`);
      (f.options || []).forEach(o => {
        const opt = h(`<option value="${esc(o.value)}">${esc(o.label)}</option>`);
        if (String(o.value) === String(f.value)) opt.selected = true;
        input.appendChild(opt);
      });
    } else input = h(`<input type="${f.type || 'text'}" name="${f.name}" placeholder="${esc(f.placeholder || '')}" />`);
    if (f.value != null && f.type !== 'select') input.value = f.value;
    wrap.appendChild(input);
    form.appendChild(wrap);
  });
  const actions = h('<div class="modal-actions"></div>');
  const cancel = h('<button type="button" class="btn-sm">Cancel</button>'); cancel.onclick = closeModal;
  const submit = h(`<button type="submit" class="btn-primary">${esc(submitLabel)}</button>`);
  actions.append(cancel, submit); form.appendChild(actions);
  form.onsubmit = async (e) => {
    e.preventDefault();
    const values = {};
    fields.forEach(f => { values[f.name] = form.elements[f.name].value; });
    for (const f of fields) if (f.required && !values[f.name]) { toast(f.label + ' is required', 'err'); return; }
    submit.disabled = true;
    try { await onSubmit(values); } catch (err) { toast(err.message, 'err'); submit.disabled = false; }
  };
  openModal(title, form);
}

// ---------- login ----------
async function showLogin() {
  state.role = null; state.userId = null; state.userName = null;
  localStorage.removeItem('navcom');
  $('#app').classList.add('hidden');
  $('#login-screen').classList.remove('hidden');
  $('#tech-picker').classList.add('hidden');
}

document.querySelectorAll('.role-btn').forEach(btn => {
  btn.onclick = async () => {
    const role = btn.dataset.role;
    if (role === 'technician') {
      const techs = await api('/users?role=technician');
      const active = techs.filter(t => t.active);
      const sel = $('#tech-select');
      sel.innerHTML = active.map(t => `<option value="${t.id}">${esc(t.name)}</option>`).join('');
      $('#tech-picker').classList.remove('hidden');
      $('#tech-enter').onclick = () => {
        const id = sel.value;
        const t = active.find(x => String(x.id) === String(id));
        enterApp('technician', t.id, t.name);
      };
    } else {
      const users = await api('/users?role=' + role);
      const u = users.find(x => x.active) || users[0];
      enterApp(role, u ? u.id : null, u ? u.name : role);
    }
  };
});

function enterApp(role, userId, userName) {
  state.role = role; state.userId = userId; state.userName = userName;
  localStorage.setItem('navcom', JSON.stringify({ role, userId, userName }));
  $('#login-screen').classList.add('hidden');
  $('#app').classList.remove('hidden');
  buildNav();
}
$('#switch-role').onclick = showLogin;

// ---------- navigation ----------
const NAV = {
  technician: [
    ['Dashboard', renderTechDashboard],
    ['My Tasks', renderTechTasks],
    ['Follow-ups', renderTechFollowups],
    ['History', renderTechHistory]
  ],
  supervisor: [
    ['Dashboard', renderSupDashboard],
    ['Inspections', renderSupInspections],
    ['Findings', renderFindings],
    ['Reports', renderReports]
  ],
  management: [
    ['Dashboard', renderMgmtDashboard],
    ['Findings', renderFindings],
    ['Reports', renderReports]
  ],
  administrator: [
    ['Dashboard', renderAdminDashboard],
    ['Users', renderUsers],
    ['Equipment', renderEquipment],
    ['Checklists', renderChecklists]
  ]
};
const ROLE_LABEL = { technician: 'Technician', supervisor: 'Supervisor', management: 'Management', administrator: 'Administrator' };

function buildNav() {
  $('#current-user').textContent = `${state.userName} · ${ROLE_LABEL[state.role]}`;
  const nav = $('#nav'); nav.innerHTML = '';
  NAV[state.role].forEach(([label, fn], i) => {
    const b = h(`<button>${esc(label)}</button>`);
    b.onclick = () => { document.querySelectorAll('#nav button').forEach(x => x.classList.remove('active')); b.classList.add('active'); fn(); };
    if (i === 0) b.classList.add('active');
    nav.appendChild(b);
  });
  NAV[state.role][0][1](); // render first view
}

// ---------- card helper ----------
function card(num, label, cls = '') { return `<div class="card ${cls}"><div class="num">${num}</div><div class="lbl">${esc(label)}</div></div>`; }
function bars(obj, max) {
  const m = max || Math.max(1, ...Object.values(obj));
  return Object.entries(obj).map(([k, v]) =>
    `<div class="bar-row"><div class="bar-label">${esc(k)}</div><div class="bar-track"><div class="bar-fill" style="width:${(v / m) * 100}%"></div></div><div class="bar-val">${v}</div></div>`
  ).join('') || emptyState('No data');
}

// =====================================================================
//  TECHNICIAN
// =====================================================================
async function renderTechDashboard() {
  const v = $('#view'); loading(v);
  try {
    const d = await api(`/dashboard?role=technician&user=${state.userId}`);
    const c = d.cards;
    v.innerHTML = `
      <h2 class="page-title">My Dashboard</h2>
      <p class="page-sub">Today is ${esc(state.today)} · ${esc(state.userName)}</p>
      <div class="cards section">
        ${card(c.today, "Today's tasks", 'info')}
        ${card(c.upcoming, 'Upcoming')}
        ${card(c.inProgress, 'In progress', 'warn')}
        ${card(c.overdue, 'Overdue', 'alert')}
        ${card(c.needsRevision, 'Needs revision', 'alert')}
        ${card(c.followUps, 'My follow-ups', 'warn')}
      </div>`;
    v.appendChild(taskPanel("Today's priority tasks", d.today.concat(d.overdue), 'No tasks for today.'));
    if (d.needsRevision.length) v.appendChild(taskPanel('Returned for revision', d.needsRevision, ''));
    v.appendChild(taskPanel('Upcoming tasks', d.upcoming, 'No upcoming tasks.'));
  } catch (e) { v.innerHTML = errorState(e.message); }
}

function taskPanel(title, list, emptyMsg) {
  const panel = h('<div class="section panel"></div>');
  panel.appendChild(h(`<div class="panel-head"><h3>${esc(title)}</h3></div>`));
  if (!list.length) { panel.appendChild(h(emptyState(emptyMsg || 'Nothing here.'))); return panel; }
  const table = h(`<table><thead><tr><th>Inspection</th><th>Type</th><th>Scheduled</th><th>Status</th></tr></thead><tbody></tbody></table>`);
  const tb = table.querySelector('tbody');
  list.forEach(i => {
    const tr = h(`<tr class="clickable"><td>${esc(i.title)}<br><small style="color:#64748b">${esc(i.equipment_area || '')}</small></td><td>${esc(i.inspection_type)}</td><td>${esc(i.scheduled_date)}</td><td>${badge(i.status)}</td></tr>`);
    tr.onclick = () => openInspection(i.id);
    tb.appendChild(tr);
  });
  panel.appendChild(table);
  return panel;
}

async function renderTechTasks() {
  const v = $('#view'); loading(v);
  try {
    let type = '';
    const all = await api(`/inspections?assigned_to=${state.userId}`);
    v.innerHTML = `<h2 class="page-title">My Tasks</h2><p class="page-sub">All inspections assigned to you.</p><div class="tabs" id="ttabs"></div><div id="tlist"></div>`;
    const tabs = ['all', 'daily', 'weekly', 'monthly'];
    const draw = () => {
      const list = type ? all.filter(i => i.inspection_type === type) : all;
      $('#tlist').innerHTML = '';
      $('#tlist').appendChild(list.length ? inspectionTable(list, openInspection) : h(emptyState('No tasks in this category.')));
    };
    const tt = $('#ttabs');
    tabs.forEach(t => {
      const b = h(`<button>${t === 'all' ? 'All' : t[0].toUpperCase() + t.slice(1)}</button>`);
      if ((t === 'all' && !type) || t === type) b.classList.add('active');
      b.onclick = () => { type = t === 'all' ? '' : t; document.querySelectorAll('#ttabs button').forEach(x => x.classList.remove('active')); b.classList.add('active'); draw(); };
      tt.appendChild(b);
    });
    draw();
  } catch (e) { v.innerHTML = errorState(e.message); }
}

async function renderTechHistory() {
  const v = $('#view'); loading(v);
  try {
    const list = (await api(`/inspections?assigned_to=${state.userId}`)).filter(i => ['Completed', 'Awaiting Validation', 'Cancelled'].includes(i.status));
    v.innerHTML = `<h2 class="page-title">Inspection History</h2><p class="page-sub">Submitted, completed, and cancelled inspections.</p>`;
    v.appendChild(list.length ? inspectionTable(list, openInspection) : h(emptyState('No history yet.')));
  } catch (e) { v.innerHTML = errorState(e.message); }
}

async function renderTechFollowups() {
  const v = $('#view'); loading(v);
  try {
    const all = await api('/findings?open=1');
    const mine = all.filter(f => String(f.assigned_to) === String(state.userId));
    v.innerHTML = `<h2 class="page-title">My Follow-up Actions</h2><p class="page-sub">Findings assigned to you for action.</p>`;
    if (!mine.length) { v.appendChild(h(emptyState('No follow-up actions assigned to you.'))); return; }
    v.appendChild(findingTable(mine, true));
  } catch (e) { v.innerHTML = errorState(e.message); }
}

// =====================================================================
//  SUPERVISOR
// =====================================================================
async function renderSupDashboard() {
  const v = $('#view'); loading(v);
  try {
    const d = await api('/dashboard?role=supervisor');
    const c = d.cards;
    v.innerHTML = `
      <h2 class="page-title">Supervision Dashboard</h2>
      <p class="page-sub">Telecom &amp; Navigation Division · ${esc(state.today)}</p>
      <div class="cards section">
        ${card(c.scheduled, 'Scheduled / Assigned', 'info')}
        ${card(c.inProgress, 'In progress', 'warn')}
        ${card(c.completed, 'Completed', 'ok')}
        ${card(c.overdue, 'Overdue', 'alert')}
        ${card(c.awaitingValidation, 'Awaiting validation', 'info')}
        ${card(c.needsRevision, 'Needs revision', 'warn')}
        ${card(c.openFindings, 'Open findings', 'warn')}
        ${card(c.criticalFindings, 'Critical findings', 'alert')}
      </div>`;
    // validation queue
    const vq = h('<div class="section panel"></div>');
    vq.appendChild(h('<div class="panel-head"><h3>Validation queue</h3></div>'));
    vq.appendChild(d.validationQueue.length ? inspectionTable(d.validationQueue, openInspection) : h(emptyState('Nothing awaiting validation.')));
    v.appendChild(vq);
    // status distribution
    const sd = h('<div class="section panel"></div>');
    sd.appendChild(h('<div class="panel-head"><h3>Inspection status distribution</h3></div>'));
    const wrap = h('<div style="padding:16px"></div>'); wrap.innerHTML = bars(d.statusCounts); sd.appendChild(wrap); v.appendChild(sd);
    // performance by technician
    const pt = h('<div class="section panel"></div>');
    pt.appendChild(h('<div class="panel-head"><h3>Performance by technician</h3></div>'));
    const tbl = h('<table><thead><tr><th>Technician</th><th>Total</th><th>Completed</th><th>Overdue</th></tr></thead><tbody></tbody></table>');
    d.byTech.forEach(t => tbl.querySelector('tbody').appendChild(h(`<tr><td>${esc(t.name)}</td><td>${t.total}</td><td>${t.completed}</td><td>${t.overdue}</td></tr>`)));
    pt.appendChild(tbl); v.appendChild(pt);
  } catch (e) { v.innerHTML = errorState(e.message); }
}

async function renderSupInspections() {
  const v = $('#view'); loading(v);
  try {
    const all = await api('/inspections');
    v.innerHTML = `<h2 class="page-title">Inspections</h2><p class="page-sub">Schedule, assign, and track all inspections.</p>
      <div class="toolbar">
        <button class="btn-primary" id="new-insp">+ New inspection</button>
        <input type="search" id="search" placeholder="Search title or equipment…" style="max-width:280px" />
        <select id="fstatus" style="max-width:200px"></select>
      </div><div id="ilist"></div>`;
    const statuses = ['All statuses', ...[...new Set(all.map(i => i.status))]];
    $('#fstatus').innerHTML = statuses.map(s => `<option>${esc(s)}</option>`).join('');
    const draw = () => {
      const q = $('#search').value.toLowerCase();
      const st = $('#fstatus').value;
      let list = all.filter(i => (i.title + ' ' + (i.equipment_name || '')).toLowerCase().includes(q));
      if (st && st !== 'All statuses') list = list.filter(i => i.status === st);
      $('#ilist').innerHTML = '';
      $('#ilist').appendChild(list.length ? inspectionTable(list, openInspection) : h(emptyState('No inspections match.')));
    };
    $('#search').oninput = draw; $('#fstatus').onchange = draw;
    $('#new-insp').onclick = newInspectionForm;
    draw();
  } catch (e) { v.innerHTML = errorState(e.message); }
}

async function newInspectionForm() {
  const [equip, techs, templates] = await Promise.all([api('/equipment'), api('/users?role=technician'), api('/checklists')]);
  formModal('New inspection', [
    { name: 'title', label: 'Title', required: true, placeholder: 'e.g. Daily check — VHF Radio' },
    { name: 'inspection_type', label: 'Type', type: 'select', options: [{ value: 'daily', label: 'Daily' }, { value: 'weekly', label: 'Weekly' }, { value: 'monthly', label: 'Monthly' }] },
    { name: 'equipment_id', label: 'Equipment / facility', type: 'select', options: equip.map(e => ({ value: e.id, label: `${e.name} (${e.area})` })) },
    { name: 'checklist_template_id', label: 'Checklist template', type: 'select', options: templates.map(t => ({ value: t.id, label: `${t.name} [${t.inspection_type}]` })) },
    { name: 'assigned_to', label: 'Assign technician', type: 'select', options: [{ value: '', label: '— Unassigned —' }, ...techs.filter(t => t.active).map(t => ({ value: t.id, label: t.name }))] },
    { name: 'scheduled_date', label: 'Scheduled date', type: 'date', required: true, value: state.today },
    { name: 'priority', label: 'Priority', type: 'select', options: [{ value: 'normal', label: 'Normal' }, { value: 'high', label: 'High' }, { value: 'low', label: 'Low' }] }
  ], 'Create', async (vals) => {
    vals.created_by = state.userId;
    await api('/inspections', { method: 'POST', body: vals });
    closeModal(); toast('Inspection created', 'ok'); renderSupInspections();
  });
}

// =====================================================================
//  MANAGEMENT
// =====================================================================
async function renderMgmtDashboard() {
  const v = $('#view'); loading(v);
  try {
    const d = await api('/dashboard?role=management');
    const c = d.cards;
    v.innerHTML = `
      <h2 class="page-title">Management Dashboard</h2>
      <p class="page-sub">Operational overview · read-only · ${esc(state.today)}</p>
      <div class="cards section">
        ${card(c.compliance + '%', 'Compliance', 'ok')}
        ${card(c.totalInspections, 'Total inspections', 'info')}
        ${card(c.completed, 'Completed', 'ok')}
        ${card(c.overdue, 'Overdue', 'alert')}
        ${card(c.openFindings, 'Open findings', 'warn')}
        ${card(c.criticalFindings, 'Critical findings', 'alert')}
        ${card(c.escalated, 'Escalated', 'alert')}
        ${card(c.resolvedFollowUps, 'Resolved follow-ups', 'ok')}
      </div>`;
    const mk = (title, obj) => { const p = h('<div class="section panel"></div>'); p.appendChild(h(`<div class="panel-head"><h3>${esc(title)}</h3></div>`)); const w = h('<div style="padding:16px"></div>'); w.innerHTML = bars(obj); p.appendChild(w); return p; };
    v.appendChild(mk('Inspections by type', d.byType));
    v.appendChild(mk('Findings by area', d.areaCounts));
    v.appendChild(mk('Follow-up status distribution', d.followCounts));
    const cp = h('<div class="section panel"></div>');
    cp.appendChild(h('<div class="panel-head"><h3>Critical &amp; escalated findings</h3></div>'));
    cp.appendChild(d.criticalFindings.length ? findingTable(d.criticalFindings, false) : h(emptyState('No critical findings.')));
    v.appendChild(cp);
  } catch (e) { v.innerHTML = errorState(e.message); }
}

// =====================================================================
//  FINDINGS (supervisor manage / management view)
// =====================================================================
async function renderFindings() {
  const v = $('#view'); loading(v);
  try {
    const all = await api('/findings');
    v.innerHTML = `<h2 class="page-title">Findings &amp; Follow-ups</h2>
      <p class="page-sub">${state.role === 'supervisor' ? 'Review, assign follow-ups, and close findings.' : 'Field findings overview (read-only).'}</p>
      <div class="toolbar"><select id="ffilter" style="max-width:220px">
        <option value="">All findings</option><option value="open">Open only</option>
        <option value="critical">Critical urgency</option></select></div><div id="flist"></div>`;
    const draw = () => {
      const f = $('#ffilter').value;
      let list = all;
      if (f === 'open') list = all.filter(x => !['Resolved', 'Closed'].includes(x.status));
      if (f === 'critical') list = all.filter(x => x.urgency === 'critical');
      $('#flist').innerHTML = '';
      $('#flist').appendChild(list.length ? findingTable(list, state.role === 'technician') : h(emptyState('No findings match.')));
    };
    $('#ffilter').onchange = draw; draw();
  } catch (e) { v.innerHTML = errorState(e.message); }
}

function findingTable(list, techView) {
  const wrap = h('<div class="panel"></div>');
  const table = h(`<table><thead><tr><th>Finding</th><th>Equipment / Area</th><th>Urgency</th><th>Status</th><th>Assigned</th><th></th></tr></thead><tbody></tbody></table>`);
  const tb = table.querySelector('tbody');
  list.forEach(f => {
    const tr = h(`<tr>
      <td>${esc(f.description)}</td>
      <td>${esc(f.equipment_name || '—')}<br><small style="color:#64748b">${esc(f.equipment_area || '')}</small></td>
      <td>${urgencyBadge(f.urgency)}</td>
      <td>${badge(f.status)}</td>
      <td>${esc(f.assigned_name || '—')}</td>
      <td class="row-actions"></td></tr>`);
    const actions = tr.querySelector('.row-actions');
    const view = h('<button class="btn-sm">View</button>'); view.onclick = () => openFinding(f); actions.appendChild(view);
    tb.appendChild(tr);
  });
  wrap.appendChild(table);
  return wrap;
}

function openFinding(f) {
  const body = h('<div></div>');
  body.innerHTML = `
    <div class="detail-grid">
      <div><div class="k">Equipment</div><div class="v">${esc(f.equipment_name || '—')}</div></div>
      <div><div class="k">Location / Area</div><div class="v">${esc(f.location || f.equipment_area || '—')}</div></div>
      <div><div class="k">Urgency</div><div class="v">${urgencyBadge(f.urgency)}</div></div>
      <div><div class="k">Status</div><div class="v">${badge(f.status)}</div></div>
      <div><div class="k">Reported by</div><div class="v">${esc(f.creator_name || '—')}</div></div>
      <div><div class="k">Assigned to</div><div class="v">${esc(f.assigned_name || '—')}</div></div>
    </div>
    <div class="field"><div class="k">Description</div><div>${esc(f.description)}</div></div>
    ${f.evidence_note ? `<div class="note-box"><strong>Evidence:</strong> ${esc(f.evidence_note)}</div>` : ''}
    ${f.recommendation ? `<div class="field"><div class="k">Recommendation</div><div>${esc(f.recommendation)}</div></div>` : ''}
    ${f.follow_up_notes ? `<div class="field"><div class="k">Follow-up notes</div><div>${esc(f.follow_up_notes)}</div></div>` : ''}
    ${f.completion_evidence ? `<div class="note-box"><strong>Completion evidence:</strong> ${esc(f.completion_evidence)}</div>` : ''}`;
  const act = h('<div class="modal-actions"></div>');

  const trans = async (action, extra = {}) => {
    try { await api(`/findings/${f.id}/transition`, { method: 'POST', body: { action, role: state.role, ...extra } }); closeModal(); toast('Finding updated', 'ok'); reloadCurrent(); }
    catch (e) { toast(e.message, 'err'); }
  };

  if (state.role === 'supervisor') {
    const add = (label, action) => { const b = h(`<button class="btn-sm">${label}</button>`); b.onclick = () => trans(action); act.appendChild(b); };
    if (['Created', 'Awaiting Review'].includes(f.status)) { add('✓ Accept as valid', 'accept'); }
    if (['Accepted', 'Created', 'Awaiting Review', 'Assigned for Follow-Up', 'In Follow-Up'].includes(f.status)) {
      const b = h('<button class="btn-sm blue">Assign follow-up</button>');
      b.onclick = async () => {
        const techs = (await api('/users?role=technician')).filter(t => t.active);
        formModal('Assign follow-up', [
          { name: 'assigned_to', label: 'Technician', type: 'select', required: true, options: techs.map(t => ({ value: t.id, label: t.name })), value: f.assigned_to },
          { name: 'follow_up_notes', label: 'Instruction', type: 'textarea' }
        ], 'Assign', async (vals) => trans('assign-followup', vals));
      };
      act.appendChild(b);
    }
    if (f.status === 'Awaiting Verification') {
      const b = h('<button class="btn-sm green">✓ Verify & resolve</button>'); b.onclick = () => trans('resolve'); act.appendChild(b);
      const r = h('<button class="btn-sm red">Return for rework</button>'); r.onclick = () => trans('return'); act.appendChild(r);
    }
    if (f.status === 'Resolved') { const b = h('<button class="btn-sm green">Close finding</button>'); b.onclick = () => trans('close'); act.appendChild(b); }
    if (!['Closed', 'Escalated', 'Resolved'].includes(f.status)) { const b = h('<button class="btn-sm red">Escalate</button>'); b.onclick = () => trans('escalate'); act.appendChild(b); }
  }
  if (state.role === 'technician' && String(f.assigned_to) === String(state.userId) && ['Assigned for Follow-Up', 'In Follow-Up'].includes(f.status)) {
    const b = h('<button class="btn-primary">Submit follow-up result</button>');
    b.onclick = () => formModal('Submit follow-up result', [
      { name: 'completion_evidence', label: 'Completion evidence / notes', type: 'textarea', required: true, placeholder: 'Describe the action taken and result' }
    ], 'Submit', async (vals) => trans('submit-followup', vals));
    act.appendChild(b);
  }
  if (act.children.length) body.appendChild(act);
  openModal('Finding detail', body);
}

// Read an image file and return a downscaled JPEG data URL (browser-safe, keeps base64 small).
function processImage(file) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onerror = () => reject(new Error('Could not read the file.'));
    reader.onload = () => {
      const img = new Image();
      img.onerror = () => reject(new Error('That file is not a valid image.'));
      img.onload = () => {
        const MAX = 1024;
        let { width, height } = img;
        if (width > MAX || height > MAX) {
          const scale = Math.min(MAX / width, MAX / height);
          width = Math.round(width * scale); height = Math.round(height * scale);
        }
        const canvas = document.createElement('canvas');
        canvas.width = width; canvas.height = height;
        canvas.getContext('2d').drawImage(img, 0, 0, width, height);
        resolve(canvas.toDataURL('image/jpeg', 0.7));
      };
      img.src = reader.result;
    };
    reader.readAsDataURL(file);
  });
}

// Required-evidence rule: every Abnormal item needs a note AND a photo.
// Returns a list of human-readable issues (empty = ok to submit).
function validateAbnormal(checklist) {
  const issues = [];
  checklist.forEach(it => {
    if (it.condition !== 'abnormal') return;
    const missing = [];
    if (!it.note || !it.note.trim()) missing.push('a note');
    if (!it.photo) missing.push('a photo');
    if (missing.length) issues.push(`“${it.item}” needs ${missing.join(' and ')}`);
  });
  return issues;
}

// Full-size photo preview. A standalone overlay layered ABOVE #modal, so the inspection
// validation modal underneath keeps its scroll position and state when this closes.
function openPhotoLightbox({ src, item, note, equipment }) {
  if (!src) return; // no photo → nothing to open (guards against broken/empty preview)
  const lb = h(`<div class="lightbox" role="dialog" aria-modal="true">
    <div class="lightbox-inner">
      <div class="lightbox-head">
        <div class="lightbox-title"></div>
        <button type="button" class="lightbox-close" aria-label="Close">&times;</button>
      </div>
      <img class="lightbox-img" alt="abnormal condition evidence" />
      <div class="lightbox-cap"></div>
    </div>
  </div>`);
  lb.querySelector('.lightbox-title').textContent = item || 'Abnormal condition photo';
  lb.querySelector('.lightbox-img').src = src; // property assignment keeps base64 intact
  const parts = [];
  if (note && note.trim()) parts.push(note.trim());
  if (equipment) parts.push(equipment);
  const cap = lb.querySelector('.lightbox-cap');
  if (parts.length) cap.textContent = parts.join(' · '); else cap.remove();

  const close = () => { lb.remove(); document.removeEventListener('keydown', onKey); };
  const onKey = (e) => { if (e.key === 'Escape') close(); };
  lb.querySelector('.lightbox-close').onclick = close;
  lb.addEventListener('click', (e) => { if (e.target === lb) close(); }); // click outside the image
  document.addEventListener('keydown', onKey);
  document.body.appendChild(lb);
}

// =====================================================================
//  INSPECTION DETAIL (shared)
// =====================================================================
async function openInspection(id) {
  let i;
  try { i = await api('/inspections/' + id); } catch (e) { toast(e.message, 'err'); return; }
  const body = h('<div></div>');
  body.innerHTML = `
    <div class="detail-grid">
      <div><div class="k">Equipment</div><div class="v">${esc(i.equipment_name || '—')}</div></div>
      <div><div class="k">Area / Location</div><div class="v">${esc(i.equipment_area || '')} ${i.equipment_location ? '· ' + esc(i.equipment_location) : ''}</div></div>
      <div><div class="k">Type</div><div class="v">${esc(i.inspection_type)}</div></div>
      <div><div class="k">Status</div><div class="v">${badge(i.status)}</div></div>
      <div><div class="k">Scheduled</div><div class="v">${esc(i.scheduled_date)}</div></div>
      <div><div class="k">Assigned to</div><div class="v">${esc(i.assigned_name || '—')}</div></div>
    </div>
    ${i.revision_notes && i.status === 'Needs Revision' ? `<div class="note-box"><strong>Supervisor asked for revision:</strong> ${esc(i.revision_notes)}</div>` : ''}`;

  const editable = state.role === 'technician' && String(i.assigned_to) === String(state.userId) && ['In Progress', 'Needs Revision'].includes(i.status);
  const startable = state.role === 'technician' && String(i.assigned_to) === String(state.userId) && ['Assigned', 'Scheduled', 'Rescheduled', 'Overdue'].includes(i.status);

  // checklist
  let template = null;
  if (i.checklist_template_id) { try { template = (await api('/checklists')).find(t => t.id === i.checklist_template_id); } catch (_) {} }
  const items = (i.checklist_results && i.checklist_results.length)
    ? i.checklist_results
    : (template ? template.items.map(it => ({ item: it, condition: 'normal', note: '' })) : []);

  if (items.length) {
    const clSection = h('<div class="section"></div>');
    clSection.appendChild(h('<h3>Checklist</h3>'));
    items.forEach((it, idx) => {
      const ci = h(`<div class="check-item" data-idx="${idx}">
        <div class="ci-head"><div class="ci-name">${esc(it.item)}</div>
        <div class="ci-toggle">
          <button type="button" data-cond="normal" class="${it.condition === 'normal' ? 'sel-normal' : ''}">Normal</button>
          <button type="button" data-cond="abnormal" class="${it.condition === 'abnormal' ? 'sel-abnormal' : ''}">Abnormal</button>
        </div></div>
        <div class="ci-note"><input type="text" placeholder="Note / reading" value="${esc(it.note || '')}" ${editable ? '' : 'disabled'} /></div>
        <div class="ci-evidence hidden">
          ${editable
            ? `<label class="ci-ev-label">Upload abnormal condition photo</label>
               <p class="ci-ev-help">Required when condition is marked Abnormal.</p>
               <input type="file" accept="image/*" class="ci-file" />`
            : `<div class="ci-ev-label">Abnormal condition photo</div>`}
          <div class="ci-preview hidden"><img alt="abnormal condition evidence" class="${editable ? '' : 'clickable'}" title="${editable ? '' : 'Click to view'}" />${editable ? '<button type="button" class="btn-sm red ci-remove">Remove photo</button>' : '<button type="button" class="btn-sm blue ci-view">🔍 View photo</button>'}</div>
        </div>
      </div>`);

      // Photo (data URL) is held on the element and round-trips through checklist_results JSON.
      ci._photo = it.photo || null;
      const evidence = ci.querySelector('.ci-evidence');
      const preview = ci.querySelector('.ci-preview');
      const previewImg = ci.querySelector('.ci-preview img');
      const fileInput = ci.querySelector('.ci-file');

      const showPreview = (dataUrl) => {
        previewImg.src = dataUrl;              // property assignment keeps base64 intact / injection-safe
        preview.classList.remove('hidden');
        if (fileInput) fileInput.classList.add('hidden');
      };
      const clearPhoto = () => {
        ci._photo = null;
        preview.classList.add('hidden');
        previewImg.removeAttribute('src');
        if (fileInput) { fileInput.value = ''; fileInput.classList.remove('hidden'); }
      };
      const syncEvidence = (cond) => {
        const show = cond === 'abnormal' && (editable || !!ci._photo);
        evidence.classList.toggle('hidden', !show);
        if (cond === 'abnormal') { if (ci._photo) showPreview(ci._photo); }
        else if (editable) clearPhoto(); // back to Normal: drop photo + its requirement
      };
      syncEvidence(it.condition);

      if (editable) {
        ci.querySelectorAll('.ci-toggle button').forEach(btn => {
          btn.onclick = () => {
            ci.querySelectorAll('.ci-toggle button').forEach(b => b.className = '');
            btn.className = btn.dataset.cond === 'normal' ? 'sel-normal' : 'sel-abnormal';
            syncEvidence(btn.dataset.cond);
          };
        });
        if (fileInput) fileInput.onchange = async () => {
          const file = fileInput.files[0];
          if (!file) return;
          if (!file.type.startsWith('image/')) { toast('Please choose an image file.', 'err'); fileInput.value = ''; return; }
          try { const dataUrl = await processImage(file); ci._photo = dataUrl; showPreview(dataUrl); }
          catch (e) { toast(e.message || 'Could not load image.', 'err'); fileInput.value = ''; }
        };
        const removeBtn = ci.querySelector('.ci-remove');
        if (removeBtn) removeBtn.onclick = clearPhoto;
      } else {
        ci.querySelectorAll('.ci-toggle button').forEach(b => b.disabled = true);
        // Review mode: click the thumbnail (or "View photo") to open a full-size lightbox.
        const openLb = () => { if (ci._photo) openPhotoLightbox({ src: ci._photo, item: it.item, note: it.note, equipment: i.equipment_name }); };
        previewImg.addEventListener('click', openLb);
        const viewBtn = ci.querySelector('.ci-view');
        if (viewBtn) viewBtn.onclick = openLb;
      }
      clSection.appendChild(ci);
    });
    body.appendChild(clSection);
  }

  if (i.result_notes) body.appendChild(h(`<div class="field"><div class="k">Result notes</div><div>${esc(i.result_notes)}</div></div>`));

  const collectChecklist = () => Array.from(body.querySelectorAll('.check-item')).map(ci => ({
    item: ci.querySelector('.ci-name').textContent,
    condition: ci.querySelector('.ci-toggle button.sel-abnormal') ? 'abnormal' : 'normal',
    note: ci.querySelector('.ci-note input').value,
    photo: ci._photo || ''
  }));

  const act = h('<div class="modal-actions"></div>');
  const reload = () => { closeModal(); reloadCurrent(); };

  if (startable) {
    const b = h('<button class="btn-primary">▶ Start inspection</button>');
    b.onclick = async () => { try { await api(`/inspections/${id}/transition`, { method: 'POST', body: { action: 'start', role: state.role } }); toast('Inspection started', 'ok'); closeModal(); openInspection(id); } catch (e) { toast(e.message, 'err'); } };
    act.appendChild(b);
  }
  if (editable) {
    // result notes editor
    const noteWrap = h('<div class="field" style="width:100%"><label>Result notes</label><textarea id="rnotes"></textarea></div>');
    noteWrap.querySelector('textarea').value = i.result_notes || '';
    body.appendChild(noteWrap);
    const finding = h('<button class="btn-sm">⚠ Raise finding</button>');
    finding.onclick = () => raiseFinding(i);
    const submit = h('<button class="btn-primary">Submit for validation</button>');
    submit.onclick = async () => {
      const cl = collectChecklist();
      const issues = validateAbnormal(cl);
      if (issues.length) { toast('Cannot submit — ' + issues.join('; ') + '.', 'err'); return; }
      try {
        await api(`/inspections/${id}/transition`, { method: 'POST', body: { action: 'submit', role: state.role, checklist_results: cl, result_notes: body.querySelector('#rnotes').value } });
        toast('Submitted for validation', 'ok'); reload();
      } catch (e) { toast(e.message, 'err'); }
    };
    const save = h('<button class="btn-sm">Save progress</button>');
    save.onclick = async () => { try { await api(`/inspections/${id}`, { method: 'PUT', body: { checklist_results: collectChecklist(), result_notes: body.querySelector('#rnotes').value } }); toast('Saved', 'ok'); } catch (e) { toast(e.message, 'err'); } };
    act.append(finding, save, submit);
  }

  if (state.role === 'supervisor') {
    if (i.status === 'Awaiting Validation') {
      const ok = h('<button class="btn-primary">✓ Validate (Complete)</button>');
      ok.onclick = async () => { try { await api(`/inspections/${id}/transition`, { method: 'POST', body: { action: 'validate', role: 'supervisor', validated_by: state.userId } }); toast('Inspection completed', 'ok'); reload(); } catch (e) { toast(e.message, 'err'); } };
      const ret = h('<button class="btn-sm red">↩ Return for revision</button>');
      ret.onclick = () => formModal('Return for revision', [{ name: 'revision_notes', label: 'Correction notes', type: 'textarea', required: true }], 'Return', async (vals) => { await api(`/inspections/${id}/transition`, { method: 'POST', body: { action: 'return', role: 'supervisor', ...vals } }); closeModal(); toast('Returned to technician', 'ok'); reloadCurrent(); });
      act.append(ok, ret);
    }
    if (['Scheduled', 'Assigned', 'Overdue', 'Rescheduled'].includes(i.status)) {
      const as = h('<button class="btn-sm blue">Assign technician</button>');
      as.onclick = async () => { const techs = (await api('/users?role=technician')).filter(t => t.active); formModal('Assign technician', [{ name: 'assigned_to', label: 'Technician', type: 'select', required: true, value: i.assigned_to, options: techs.map(t => ({ value: t.id, label: t.name })) }], 'Assign', async (vals) => { await api(`/inspections/${id}/transition`, { method: 'POST', body: { action: 'assign', role: 'supervisor', ...vals } }); closeModal(); toast('Assigned', 'ok'); reloadCurrent(); }); };
      const rs = h('<button class="btn-sm">Reschedule</button>');
      rs.onclick = () => formModal('Reschedule inspection', [{ name: 'scheduled_date', label: 'New date', type: 'date', required: true, value: i.scheduled_date }], 'Reschedule', async (vals) => { await api(`/inspections/${id}/transition`, { method: 'POST', body: { action: 'reschedule', role: 'supervisor', ...vals } }); closeModal(); toast('Rescheduled', 'ok'); reloadCurrent(); });
      const cancel = h('<button class="btn-sm red">Cancel</button>');
      cancel.onclick = async () => { if (!confirm('Cancel this inspection?')) return; await api(`/inspections/${id}/transition`, { method: 'POST', body: { action: 'cancel', role: 'supervisor' } }); closeModal(); toast('Cancelled', 'ok'); reloadCurrent(); };
      act.append(as, rs, cancel);
    }
  }

  if (act.children.length) body.appendChild(act);
  openModal(i.title, body);
}

function raiseFinding(inspection) {
  formModal('Raise finding', [
    { name: 'description', label: 'Issue description', type: 'textarea', required: true },
    { name: 'location', label: 'Location', value: inspection.equipment_location || inspection.equipment_area || '' },
    { name: 'urgency', label: 'Urgency', type: 'select', options: [{ value: 'low', label: 'Low' }, { value: 'medium', label: 'Medium' }, { value: 'high', label: 'High' }, { value: 'critical', label: 'Critical' }], value: 'medium' },
    { name: 'evidence_note', label: 'Evidence note', type: 'textarea' },
    { name: 'recommendation', label: 'Initial recommendation', type: 'textarea' }
  ], 'Create finding', async (vals) => {
    await api('/findings', { method: 'POST', body: { ...vals, inspection_id: inspection.id, equipment_id: inspection.equipment_id, created_by: state.userId } });
    closeModal(); toast('Finding recorded', 'ok');
  });
}

// =====================================================================
//  REPORTS (supervisor + management)
// =====================================================================
async function renderReports() {
  const v = $('#view'); loading(v);
  let type = 'daily';
  const draw = async () => {
    try {
      const r = await api('/reports?type=' + type);
      const body = $('#rbody'); body.innerHTML = `
        <div class="cards section">
          ${card(r.total, 'Total inspections', 'info')}
          ${card(r.completed, 'Completed', 'ok')}
          ${card(r.overdue, 'Overdue', 'alert')}
          ${card(r.findings.length, 'Findings logged', 'warn')}
        </div>`;
      const sp = h('<div class="section panel"></div>'); sp.appendChild(h('<div class="panel-head"><h3>Status breakdown</h3></div>'));
      const w = h('<div style="padding:16px"></div>'); w.innerHTML = bars(r.statusCounts); sp.appendChild(w); body.appendChild(sp);
      const ip = h('<div class="section panel"></div>'); ip.appendChild(h(`<div class="panel-head"><h3>${type[0].toUpperCase() + type.slice(1)} inspections</h3></div>`));
      ip.appendChild(r.inspections.length ? inspectionTable(r.inspections, openInspection) : h(emptyState('No inspections.'))); body.appendChild(ip);
    } catch (e) { $('#rbody').innerHTML = errorState(e.message); }
  };
  v.innerHTML = `<h2 class="page-title">Periodic Reports</h2><p class="page-sub">Daily, weekly, and monthly inspection recaps.</p>
    <div class="tabs" id="rtabs"></div><div id="rbody"></div>`;
  ['daily', 'weekly', 'monthly'].forEach(t => {
    const b = h(`<button>${t[0].toUpperCase() + t.slice(1)}</button>`); if (t === type) b.classList.add('active');
    b.onclick = () => { type = t; document.querySelectorAll('#rtabs button').forEach(x => x.classList.remove('active')); b.classList.add('active'); draw(); };
    $('#rtabs').appendChild(b);
  });
  draw();
}

// shared inspection table
function inspectionTable(list, onClick) {
  const wrap = h('<div class="panel"></div>');
  const table = h(`<table><thead><tr><th>Inspection</th><th>Type</th><th>Scheduled</th><th>Assigned</th><th>Status</th></tr></thead><tbody></tbody></table>`);
  const tb = table.querySelector('tbody');
  list.forEach(i => {
    const tr = h(`<tr class="clickable">
      <td>${esc(i.title)}<br><small style="color:#64748b">${esc(i.equipment_name || '')}</small></td>
      <td>${esc(i.inspection_type)}</td><td>${esc(i.scheduled_date)}</td>
      <td>${esc(i.assigned_name || '—')}</td><td>${badge(i.status)}</td></tr>`);
    tr.onclick = () => onClick(i.id);
    tb.appendChild(tr);
  });
  wrap.appendChild(table);
  return wrap;
}

// =====================================================================
//  ADMINISTRATOR — master data CRUD
// =====================================================================
async function renderAdminDashboard() {
  const v = $('#view'); loading(v);
  try {
    const d = await api('/dashboard?role=administrator');
    const c = d.cards;
    v.innerHTML = `<h2 class="page-title">Administrator Dashboard</h2><p class="page-sub">Reference / master data overview.</p>
      <div class="cards section">
        ${card(c.activeUsers, 'Active users', 'ok')}
        ${card(c.inactiveUsers, 'Inactive users')}
        ${card(c.equipment, 'Active equipment', 'info')}
        ${card(c.inactiveEquipment, 'Deactivated equipment')}
        ${card(c.checklists, 'Active checklists', 'info')}
        ${card(c.areas, 'Inspection areas')}
      </div>`;
    const p = h('<div class="section panel"></div>'); p.appendChild(h('<div class="panel-head"><h3>Equipment by type</h3></div>'));
    const w = h('<div style="padding:16px"></div>'); const obj = {}; d.equipmentByType.forEach(r => obj[r.type] = r.n); w.innerHTML = bars(obj); p.appendChild(w); v.appendChild(p);
  } catch (e) { v.innerHTML = errorState(e.message); }
}

async function renderUsers() {
  const v = $('#view'); loading(v);
  try {
    const users = await api('/users');
    v.innerHTML = `<h2 class="page-title">User &amp; Role Management</h2><p class="page-sub">Add, edit, or deactivate users.</p>
      <div class="toolbar"><button class="btn-primary" id="add">+ New user</button></div>`;
    const wrap = h('<div class="panel"></div>');
    const table = h(`<table><thead><tr><th>Name</th><th>Role</th><th>Department</th><th>Status</th><th></th></tr></thead><tbody></tbody></table>`);
    const tb = table.querySelector('tbody');
    users.forEach(u => {
      const tr = h(`<tr><td>${esc(u.name)}</td><td>${esc(ROLE_LABEL[u.role] || u.role)}</td><td>${esc(u.department)}</td>
        <td>${u.active ? '<span class="badge b-green">Active</span>' : '<span class="badge b-grey">Inactive</span>'}</td>
        <td class="row-actions"></td></tr>`);
      const a = tr.querySelector('.row-actions');
      const edit = h('<button class="btn-sm">Edit</button>'); edit.onclick = () => userForm(u);
      const tog = h(`<button class="btn-sm ${u.active ? 'red' : 'green'}">${u.active ? 'Deactivate' : 'Activate'}</button>`);
      tog.onclick = async () => { await api('/users/' + u.id, { method: 'PUT', body: { active: u.active ? 0 : 1 } }); toast('Updated', 'ok'); renderUsers(); };
      a.append(edit, tog); tb.appendChild(tr);
    });
    wrap.appendChild(table); v.appendChild(wrap);
    $('#add').onclick = () => userForm(null);
  } catch (e) { v.innerHTML = errorState(e.message); }
}

function userForm(u) {
  formModal(u ? 'Edit user' : 'New user', [
    { name: 'name', label: 'Name', required: true, value: u ? u.name : '' },
    { name: 'role', label: 'Role', type: 'select', value: u ? u.role : 'technician', options: Object.entries(ROLE_LABEL).map(([v2, l]) => ({ value: v2, label: l })) },
    { name: 'department', label: 'Department', value: u ? u.department : 'Telecom & Navigation' }
  ], u ? 'Save' : 'Create', async (vals) => {
    if (u) await api('/users/' + u.id, { method: 'PUT', body: vals });
    else await api('/users', { method: 'POST', body: vals });
    closeModal(); toast('Saved', 'ok'); renderUsers();
  });
}

async function renderEquipment() {
  const v = $('#view'); loading(v);
  try {
    const list = await api('/equipment?all=1');
    v.innerHTML = `<h2 class="page-title">Equipment, Facilities &amp; Areas</h2><p class="page-sub">Inspection master data. Items with history are deactivated, not deleted.</p>
      <div class="toolbar"><button class="btn-primary" id="add">+ New equipment</button></div>`;
    const wrap = h('<div class="panel"></div>');
    const table = h(`<table><thead><tr><th>Name</th><th>Type</th><th>Location</th><th>Area</th><th>Status</th><th></th></tr></thead><tbody></tbody></table>`);
    const tb = table.querySelector('tbody');
    list.forEach(e => {
      const tr = h(`<tr><td>${esc(e.name)}</td><td>${esc(e.type)}</td><td>${esc(e.location)}</td><td>${esc(e.area)}</td>
        <td>${e.active ? '<span class="badge b-green">Active</span>' : '<span class="badge b-grey">Inactive</span>'}</td>
        <td class="row-actions"></td></tr>`);
      const a = tr.querySelector('.row-actions');
      const edit = h('<button class="btn-sm">Edit</button>'); edit.onclick = () => equipForm(e);
      const del = h(`<button class="btn-sm ${e.active ? 'red' : 'green'}">${e.active ? 'Deactivate' : 'Activate'}</button>`);
      del.onclick = async () => {
        if (e.active) { const r = await api('/equipment/' + e.id, { method: 'DELETE' }); toast(r.message || 'Removed', 'ok'); }
        else { await api('/equipment/' + e.id, { method: 'PUT', body: { active: 1 } }); toast('Activated', 'ok'); }
        renderEquipment();
      };
      a.append(edit, del); tb.appendChild(tr);
    });
    wrap.appendChild(table); v.appendChild(wrap);
    $('#add').onclick = () => equipForm(null);
  } catch (e) { v.innerHTML = errorState(e.message); }
}

function equipForm(e) {
  formModal(e ? 'Edit equipment' : 'New equipment', [
    { name: 'name', label: 'Name', required: true, value: e ? e.name : '' },
    { name: 'type', label: 'Type', type: 'select', value: e ? e.type : 'Navigation', options: ['Navigation', 'Communication', 'Surveillance', 'Power', 'Facility'].map(x => ({ value: x, label: x })) },
    { name: 'location', label: 'Location', value: e ? e.location : '' },
    { name: 'area', label: 'Area', required: true, value: e ? e.area : '' }
  ], e ? 'Save' : 'Create', async (vals) => {
    if (e) await api('/equipment/' + e.id, { method: 'PUT', body: vals });
    else await api('/equipment', { method: 'POST', body: vals });
    closeModal(); toast('Saved', 'ok'); renderEquipment();
  });
}

async function renderChecklists() {
  const v = $('#view'); loading(v);
  try {
    const list = await api('/checklists');
    v.innerHTML = `<h2 class="page-title">Checklist Templates</h2><p class="page-sub">Standard checklists used during inspections.</p>
      <div class="toolbar"><button class="btn-primary" id="add">+ New template</button></div>`;
    list.forEach(t => {
      const p = h('<div class="section panel"></div>');
      const head = h(`<div class="panel-head"><h3>${esc(t.name)} <span class="badge b-blue">${esc(t.inspection_type)}</span></h3><div class="row-actions"></div></div>`);
      const edit = h('<button class="btn-sm">Edit</button>'); edit.onclick = () => checklistForm(t);
      const del = h('<button class="btn-sm red">Delete</button>'); del.onclick = async () => { const r = await api('/checklists/' + t.id, { method: 'DELETE' }); toast(r.message || 'Removed', 'ok'); renderChecklists(); };
      head.querySelector('.row-actions').append(edit, del);
      p.appendChild(head);
      const ul = h('<ul style="padding:14px 14px 14px 32px"></ul>');
      t.items.forEach(it => ul.appendChild(h(`<li>${esc(it)}</li>`)));
      p.appendChild(ul); v.appendChild(p);
    });
    if (!list.length) v.appendChild(h(emptyState('No checklist templates.')));
    $('#add').onclick = () => checklistForm(null);
  } catch (e) { v.innerHTML = errorState(e.message); }
}

function checklistForm(t) {
  formModal(t ? 'Edit checklist template' : 'New checklist template', [
    { name: 'name', label: 'Template name', required: true, value: t ? t.name : '' },
    { name: 'inspection_type', label: 'Type', type: 'select', value: t ? t.inspection_type : 'daily', options: [{ value: 'daily', label: 'Daily' }, { value: 'weekly', label: 'Weekly' }, { value: 'monthly', label: 'Monthly' }] },
    { name: 'items', label: 'Checklist items (one per line)', type: 'textarea', required: true, value: t ? t.items.join('\n') : '' }
  ], t ? 'Save' : 'Create', async (vals) => {
    const items = vals.items.split('\n').map(s => s.trim()).filter(Boolean);
    if (!items.length) throw new Error('At least one checklist item is required');
    const body = { name: vals.name, inspection_type: vals.inspection_type, items };
    if (t) await api('/checklists/' + t.id, { method: 'PUT', body });
    else await api('/checklists', { method: 'POST', body });
    closeModal(); toast('Saved', 'ok'); renderChecklists();
  });
}

// re-render whichever nav item is active (used after mutations)
function reloadCurrent() {
  const active = document.querySelector('#nav button.active');
  if (!active) return;
  const item = NAV[state.role].find(([label]) => label === active.textContent);
  if (item) item[1]();
}

// ---------- boot ----------
(async function boot() {
  initTheme();
  bindThemeSelectors();
  try { const meta = await api('/meta'); state.today = meta.today; } catch (_) {}
  const saved = localStorage.getItem('navcom');
  if (saved) { try { const s = JSON.parse(saved); enterApp(s.role, s.userId, s.userName); return; } catch (_) {} }
  showLogin();
})();
