async function api(url, options = {}) {
  const opts = {
    credentials: 'same-origin',
    headers: {
      'Accept': 'application/json',
      ...(options.body ? { 'Content-Type': 'application/json' } : {}),
      ...(options.headers || {})
    },
    ...options
  };

  const res = await fetch(url, opts);
  if (res.status === 401) {
    const here = location.pathname + location.search;
    if (!location.pathname.endsWith('/login.html')) {
      location.href = '/login.html?returnUrl=' + encodeURIComponent(here);
    }
    throw new Error((window.SpLocale && SpLocale.t('common.notSignedIn')) || 'Nicht angemeldet');
  }
  return res;
}

function escapeHtml(s) {
  return String(s ?? '')
    .replaceAll('&', '&amp;')
    .replaceAll('<', '&lt;')
    .replaceAll('>', '&gt;')
    .replaceAll('"', '&quot;');
}

/**
 * Theme-konforme Bestätigungsabfrage (ersetzt window.confirm).
 * @returns {Promise<boolean>}
 */
function confirmDialog(opts) {
  const options = typeof opts === 'string' ? { message: opts } : (opts || {});
  const title = options.title || (window.SpLocale ? SpLocale.t('common.confirmTitle', 'Bitte bestätigen') : 'Bitte bestätigen');
  const message = options.message || '';
  const confirmLabel = options.confirmLabel || (window.SpLocale ? SpLocale.t('common.confirm', 'Bestätigen') : 'Bestätigen');
  const cancelLabel = options.cancelLabel || (window.SpLocale ? SpLocale.t('common.cancel', 'Abbrechen') : 'Abbrechen');
  const danger = !!options.danger;

  return new Promise(resolve => {
    const existing = document.getElementById('spConfirmModal');
    if (existing) existing.remove();

    const overlay = document.createElement('div');
    overlay.id = 'spConfirmModal';
    overlay.className = 'modal-overlay';
    overlay.setAttribute('role', 'dialog');
    overlay.setAttribute('aria-modal', 'true');
    overlay.innerHTML =
      `<div class="modal-card">
        <h3 class="modal-title">${escapeHtml(title)}</h3>
        <p class="modal-message">${escapeHtml(message)}</p>
        <div class="modal-actions">
          <button type="button" class="modal-cancel">${escapeHtml(cancelLabel)}</button>
          <button type="button" class="modal-confirm ${danger ? 'btn-danger' : 'btn-primary'}">${escapeHtml(confirmLabel)}</button>
        </div>
      </div>`;

    const finish = (ok) => {
      document.removeEventListener('keydown', onKey);
      overlay.remove();
      resolve(ok);
    };
    const onKey = (e) => {
      if (e.key === 'Escape') finish(false);
      if (e.key === 'Enter') finish(true);
    };

    overlay.addEventListener('click', (e) => {
      if (e.target === overlay) finish(false);
    });
    overlay.querySelector('.modal-cancel').addEventListener('click', () => finish(false));
    overlay.querySelector('.modal-confirm').addEventListener('click', () => finish(true));
    document.addEventListener('keydown', onKey);
    document.body.appendChild(overlay);
    overlay.querySelector('.modal-confirm').focus();
  });
}

function fmt(v, unit) {
  return v == null || v === undefined ? '—' : Number(v).toFixed(1).replace(/\.0$/, '') + unit;
}

async function logout() {
  await api('/api/auth/logout', { method: 'POST' });
  location.href = '/login.html';
}

async function loadMe() {
  const res = await api('/api/auth/me');
  if (!res.ok) return null;
  return res.json();
}

/** Hides nav links the current role isn't allowed to manage and remembers the role globally. */
function applyRoleNav(role) {
  window.__spRole = role || 'Viewer';
  const hideMap = {
    Viewer: ['sqladmin', 'users', 'settings', 'license'],
    Operator: ['sqladmin', 'users', 'settings', 'license']
  };
  const hide = hideMap[window.__spRole] || [];
  hide.forEach(id => {
    document.querySelectorAll(`.nav [data-nav="${id}"]`).forEach(el => el.remove());
  });
}

function setActiveNav(page) {
  document.querySelectorAll('.nav [data-nav]').forEach(el => {
    el.classList.toggle('active', el.getAttribute('data-nav') === page);
  });
}

function navHtml(active) {
  const items = [
    ['fleet', '/', 'nav.fleet', 'Fleet'],
    ['setup', '/setup.html', 'nav.setup', 'Setup'],
    ['alerts', '/alerts.html', 'nav.alerts', 'Alerts'],
    ['tools', '/tools.html', 'nav.tools', 'Server-Tools'],
    ['sqladmin', '/sqladmin.html', 'nav.sqladmin', 'SQL-Admin'],
    ['reports', '/reports.html', 'nav.reports', 'Reports'],
    ['license', '/license.html', 'nav.license', 'Lizenz'],
    ['users', '/users.html', 'nav.users', 'Benutzer'],
    ['settings', '/settings.html', 'nav.settings', 'Einstellungen']
  ];
  return items.map(([id, href, key, fallback]) => {
    const label = window.SpLocale ? SpLocale.t(key, fallback) : fallback;
    return `<a href="${href}" data-nav="${id}" data-i18n="${key}"${id === active ? ' class="active"' : ''}>${label}</a>`;
  }).join('\n      ');
}

function languageSelectHtml() {
  const lang = window.SpLocale ? SpLocale.getLang() : 'de';
  const opts = (window.SpLocale ? SpLocale.SUPPORTED : ['de', 'en', 'fr', 'es', 'it', 'pl'])
    .map(code => `<option value="${code}"${code === lang ? ' selected' : ''}>${code.toUpperCase()}</option>`)
    .join('');
  const label = window.SpLocale ? SpLocale.t('nav.language', 'Sprache') : 'Sprache';
  return `<label class="nav-lang" title="${label}"><span class="sr-only" data-i18n="nav.language">${label}</span>` +
    `<select id="uiLangSelect" aria-label="${label}">${opts}</select></label>`;
}

function chromeNav(active) {
  const logout = window.SpLocale ? SpLocale.t('nav.logout', 'Abmelden') : 'Abmelden';
  return navHtml(active) + '\n      ' + languageSelectHtml() +
    `\n      <button id="btnLogout" type="button" data-i18n="nav.logout">${logout}</button>`;
}

function bindLanguageSelect() {
  const sel = document.getElementById('uiLangSelect');
  if (!sel || !window.SpLocale) return;
  sel.value = SpLocale.getLang();
  sel.addEventListener('change', async () => {
    await SpLocale.setLang(sel.value);
    location.reload();
  });
}

async function initLocale() {
  if (!window.SpLocale) return;
  await SpLocale.load();
  bindLanguageSelect();
}

function renderLicenseBanner(license) {
  let el = document.getElementById('licenseBanner');
  if (!el) {
    el = document.createElement('div');
    el.id = 'licenseBanner';
    el.className = 'license-banner';
    const main = document.querySelector('main.page');
    if (main) main.insertAdjacentElement('afterbegin', el);
    else return;
  }
  if (!license) {
    el.hidden = true;
    applyLicenseLock(null);
    return;
  }
  el.hidden = false;
  const ok = !!license.isLicensed;
  const trial = !!license.isTrial;
  let tone = 'crit';
  if (ok && trial) tone = license.trialDaysRemaining <= 3 ? 'warn' : 'ok';
  else if (ok) tone = license.canAcceptNewDevices ? 'ok' : 'warn';
  el.className = 'license-banner ' + tone;
  el.innerHTML = `<strong>${trial ? 'Testversion:' : 'Lizenz:'}</strong> ${escapeHtml(license.statusMessage || '')}` +
    (ok ? '' : ` · <a href="/license.html">Lizenzmanager öffnen</a>`);
  applyLicenseLock(license);
}

/** Pages stay visible; mutating controls are disabled when trial/license is inactive. */
function applyLicenseLock(license) {
  const onLicensePage = /\/license\.html$/i.test(location.pathname);
  const locked = !!(license && license.isLicensed === false && !onLicensePage);
  document.body.classList.toggle('license-locked', locked);
  document.body.classList.toggle('license-trial', !!(license && license.isTrial));

  document.querySelectorAll('[data-license-disabled="1"]').forEach(el => {
    el.disabled = false;
    el.removeAttribute('data-license-disabled');
  });

  if (!locked) return;

  document.querySelectorAll('main.page button, main.page input, main.page select, main.page textarea').forEach(el => {
    if (el.closest('[data-license-allow]')) return;
    if (el.id === 'btnLogout') return;
    el.disabled = true;
    el.setAttribute('data-license-disabled', '1');
  });
}
