// public/assets/ui.js
/* English comments: shared DOM + UI helpers */

(function () {
  const THEME_COOKIE = 'scmedia_theme';
  let themeToggleReady = false;
  let queueState = { active: [], recent: [] };
  let sseOpening = false;

  function qs(selOrId) {
    if (typeof selOrId !== 'string') return null;
    const s = selOrId.trim();
    if (s === '') return null;
    if (s[0] === '#' || s[0] === '.' || s[0] === '[' || s.includes(' ') || s.includes('>')) {
      return document.querySelector(s);
    }
    return document.getElementById(s);
  }

  function qsa(selector) {
    return Array.from(document.querySelectorAll(selector));
  }

  function getCookie(name) {
    const parts = document.cookie.split(';').map((p) => p.trim());
    for (const part of parts) {
      if (!part) continue;
      const idx = part.indexOf('=');
      if (idx === -1) continue;
      const key = part.slice(0, idx);
      if (key === name) return decodeURIComponent(part.slice(idx + 1));
    }
    return '';
  }

  function setCookie(name, value, days = 365) {
    const expires = new Date(Date.now() + days * 86400000).toUTCString();
    document.cookie = `${name}=${encodeURIComponent(value)}; path=/; expires=${expires}; SameSite=Lax`;
  }

  function setTheme(theme) {
    const mode = theme === 'light' ? 'light' : 'dark';
    document.documentElement.setAttribute('data-theme', mode);
    setCookie(THEME_COOKIE, mode);
  }


  function initThemeToggle() {
    const btn = qs('themeToggle');
    const saved = getCookie(THEME_COOKIE) || 'dark';
    setTheme(saved);
    if (!btn || themeToggleReady) return;
    btn.addEventListener('click', () => {
      const current = document.documentElement.getAttribute('data-theme') || 'dark';
      setTheme(current === 'dark' ? 'light' : 'dark');
    });
    themeToggleReady = true;
  }

  function formatBytes(bytes) {
    const value = Number(bytes || 0);
    if (!Number.isFinite(value) || value <= 0) return '0 B';
    const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
    let idx = 0;
    let n = value;
    while (n >= 1024 && idx < units.length - 1) {
      n /= 1024;
      idx += 1;
    }
    return `${n.toFixed(n >= 10 || idx === 0 ? 0 : 1)} ${units[idx]}`;
  }

  window.UI = {
    qs,
    qsa,
    setTheme,
    initThemeToggle,
    formatBytes,
  };

  window.UI.bindThemePreference = function (onChange) {
    const btn = qs('themeToggle');
    if (!btn || btn.dataset.themePrefBind === '1') return;
    btn.dataset.themePrefBind = '1';
    btn.addEventListener('click', () => {
      const current = document.documentElement.getAttribute('data-theme') || 'dark';
      window.UserPrefs?.setUi?.('theme', current);
      if (typeof onChange === 'function') {
        onChange(current);
      }
    });
  };

  window.UI.updateSseIndicator = function (status) {
    const items = document.querySelectorAll('[data-sse-indicator]');
    items.forEach((el) => {
      el.classList.remove('sse-ok', 'sse-idle', 'sse-offline');
      if (status === 'ok') el.classList.add('sse-ok');
      else if (status === 'idle') el.classList.add('sse-idle');
      else if (status === 'offline') el.classList.add('sse-offline');
    });
  };

  window.UI.blinkSseIndicator = function () {
    const items = document.querySelectorAll('[data-sse-indicator]');
    items.forEach((el) => {
      el.classList.add('sse-blink');
      setTimeout(() => el.classList.remove('sse-blink'), 250);
    });
  };

  window.UI.startSseIndicatorPolling = function () {
    const updateFromStorage = () => {
      const last = Number(localStorage.getItem('scmedia_sse_last') || 0);
      const connectedRaw = localStorage.getItem('scmedia_sse_connected');
      const connected = connectedRaw === '1';
      if (!last && !connectedRaw) {
        const items = document.querySelectorAll('[data-sse-indicator]');
        items.forEach((el) => {
          el.classList.remove('sse-ok', 'sse-idle', 'sse-offline');
        });
        return;
      }
      const recent = last > 0 && (Date.now() - last) <= 15000;
      if (recent) {
        window.UI.updateSseIndicator('ok');
        return;
      }
      if (connected) {
        window.UI.updateSseIndicator('idle');
        return;
      }
      window.UI.updateSseIndicator('offline');
    };
    updateFromStorage();
    setInterval(updateFromStorage, 5000);
  };
  window.UI.startSseClient = function () {
    window.Sse?.start?.();
  };

  window.UI.stopSseClient = function () {
    window.Sse?.stop?.();
  };

  window.UI.getSseStats = function () {
    const connected = localStorage.getItem('scmedia_sse_connected') === '1';
    const last = Number(localStorage.getItem('scmedia_sse_last') || 0);
    const lastType = localStorage.getItem('scmedia_sse_last_type') || '—';
    const reconnects = Number(localStorage.getItem('scmedia_sse_reconnects') || 0);
    return { connected, last, lastType, reconnects };
  };

  window.UI.initQueuePanel = function () {
    const summary = qs('queueSummary');
    const menu = qs('queueMenu');
    if (!summary || !menu) return;
    if (summary.dataset.queueInit === '1') return;
    summary.dataset.queueInit = '1';

    const t = (key, fallback) => {
      const dict = window.I18N || {};
      const v = dict && Object.prototype.hasOwnProperty.call(dict, key) ? dict[key] : null;
      return (typeof v === 'string' && v.length) ? v : fallback;
    };

    const updateQueueSummary = (data) => {
      const activeEl = summary.querySelector('[data-queue-active]');
      const errorsEl = summary.querySelector('[data-queue-errors]');
      const dividerEl = summary.querySelector('[data-queue-divider]');
      if (activeEl || errorsEl) {
        const activeLabel = activeEl?.dataset.queueActiveLabel || t('queue.active', 'Active');
        const errorsLabel = errorsEl?.dataset.queueErrorsLabel || t('queue.errors', 'Errors');
        const activeCount = Number(data.running || 0);
        const errorsCount = Number(data.errors || 0);
        if (activeEl) activeEl.textContent = `${activeLabel}: ${activeCount}`;
        if (errorsEl) {
          errorsEl.textContent = `${errorsLabel}: ${errorsCount}`;
          errorsEl.classList.toggle('is-hidden', errorsCount <= 0);
        }
        if (dividerEl) dividerEl.classList.toggle('is-hidden', errorsCount <= 0);
      }
    };

    const updateJobIndicator = (job) => {
      const wrap = qs('job-indicator');
      const prog = qs('job-indicator-progress');
      if (!wrap || !prog) return;
      if (!job) {
        wrap.classList.add('hidden');
        return;
      }
      wrap.classList.remove('hidden');
      const total = Number(job.progress_total || 0);
      const cur = Number(job.progress || 0);
      const pct = total > 0 ? Math.floor((cur / total) * 100) : 0;
      prog.max = 100;
      prog.value = pct;
    };

    const isMenuOpen = () => !menu.classList.contains('is-hidden');

    const cancelJobById = async (id) => {
      if (!id) return;
      if (!confirm(t('job.cancel_confirm', 'Cancel job?'))) return;
      try {
        await apiJson('/api/jobs/cancel', {
          method: 'POST',
          body: JSON.stringify({ id }),
          headers: { 'Content-Type': 'application/json' },
        });
      } catch (e) {
        // ignore
      }
    };

    const renderQueueMenu = () => {
      const activeWrap = qs('queueMenuActive');
      const finishedWrap = qs('queueMenuFinished');
      if (!activeWrap || !finishedWrap) return;
      activeWrap.innerHTML = '';
      finishedWrap.innerHTML = '';

      if (queueState.active.length === 0) {
        const empty = document.createElement('div');
        empty.className = 'queue-item-status';
        empty.textContent = t('queue.none_active', 'No active tasks');
        activeWrap.appendChild(empty);
      } else {
        queueState.active.forEach(j => {
          const row = document.createElement('div');
          row.className = 'queue-item';
          const title = document.createElement('div');
          const pct = j.progress_total > 0 ? Math.floor((j.progress / j.progress_total) * 100) : 0;
          title.textContent = `${j.title || ''} (${pct}%)`;
          const actions = document.createElement('div');
          actions.className = 'queue-item-actions';
          const btn = document.createElement('button');
          btn.className = 'btn';
          btn.textContent = t('queue.cancel', 'Cancel');
          btn.addEventListener('click', () => cancelJobById(j.id));
          actions.appendChild(btn);
          row.appendChild(title);
          row.appendChild(actions);
          activeWrap.appendChild(row);
        });
      }

      if (queueState.recent.length === 0) {
        const empty = document.createElement('div');
        empty.className = 'queue-item-status';
        empty.textContent = t('queue.none_finished', 'No finished tasks');
        finishedWrap.appendChild(empty);
      } else {
        queueState.recent.forEach(j => {
          const row = document.createElement('div');
          row.className = 'queue-item';
          const title = document.createElement('div');
          title.textContent = j.title || '';
          const status = document.createElement('div');
          status.className = 'queue-item-status';
          status.textContent = j.status || '';
          row.appendChild(title);
          row.appendChild(status);
          finishedWrap.appendChild(row);
        });
      }
      updateSseStats();
    };

    const updateSseStats = () => {
      const wrap = qs('queueSseStats');
      const stats = qs('queueSseStats')?.querySelector('.queue-stats');
      if (!wrap || !stats) return;
      const enabled = window.DEBUG_TOOLS_ENABLED === true;
      wrap.classList.toggle('is-hidden', !enabled);
      if (!enabled) return;
      const sse = window.UI.getSseStats();
      const lastAt = sse.last > 0 ? new Date(sse.last).toLocaleTimeString() : '—';
      stats.textContent = `last: ${lastAt} | type: ${sse.lastType} | reconnects: ${sse.reconnects}`;
    };

    const apiJson = async (path, opts = {}) => {
      if (window.Api?.request) {
        const res = await window.Api.request(path, opts);
        return res?.data || res || null;
      }
      const token = window.Auth?.getAccessToken?.();
      const headers = { ...(opts.headers || {}) };
      if (token) headers.Authorization = `Bearer ${token}`;
      const res = await fetch(path, { ...opts, headers });
      const json = await res.json().catch(() => null);
      return json?.data || null;
    };

    const loadRecent = async () => {
      // disabled: SSE-only mode
    };

    summary.addEventListener('click', () => {
      menu.classList.toggle('is-hidden');
      if (!menu.classList.contains('is-hidden')) {
        renderQueueMenu();
      }
    });
    document.addEventListener('click', (e) => {
      if (summary.contains(e.target) || menu.contains(e.target)) return;
      menu.classList.add('is-hidden');
    });

    updateQueueSummary({ running: 0, errors: 0 });
    updateSseStats();

    if (window.Sse?.on) {
      window.Sse.on('jobs', (payload) => {
        if (!payload) return;
        updateQueueSummary(payload);
        updateJobIndicator(payload.active || null);
        queueState.active = Array.isArray(payload.active_list) ? payload.active_list : [];
        if (isMenuOpen()) renderQueueMenu();
      });
      window.Sse.on('tick', () => updateSseStats());
    }
  };

  window.UI.initHeader = function () {
    if (window.Auth?.initHeaderControls) {
      window.Auth.initHeaderControls();
    }
    if (window.Auth?.initSessionRefresh) {
      window.Auth.initSessionRefresh();
    }
    window.UI.initThemeToggle();
    window.UI.startSseIndicatorPolling();
    window.UI.initQueuePanel();
    window.UI.startSseClient();
    const menu = document.querySelector('.topbar-menu');
    if (menu && menu.dataset.outsideClose !== '1') {
      menu.dataset.outsideClose = '1';
      document.addEventListener('click', (e) => {
        if (!menu.hasAttribute('open')) return;
        const target = e.target;
        if (target && menu.contains(target)) return;
        menu.removeAttribute('open');
      });
      document.addEventListener('keydown', (e) => {
        if (e.key === 'Escape' && menu.hasAttribute('open')) {
          menu.removeAttribute('open');
        }
      });
    }
    if (window.Sse?.on && window.UI?.blinkSseIndicator) {
      const blink = () => window.UI.blinkSseIndicator();
      window.Sse.on('message', blink);
      window.Sse.on('jobs', blink);
      window.Sse.on('sources', blink);
      window.Sse.on('tick', blink);
    }
  };
})();
