/* Источник данных портала ЛАН-ПРОЕКТ — реальный API бэкенда (Fastify).
   Заменяет демо-данные: тянет продукты/версии/лицензии/журнал из /api/*,
   сохраняя интерфейс, который ожидают экраны (D.products, D.licenseFor, ...).
   Поля читаются через геттеры, поэтому после перезагрузки данных
   компоненты видят актуальные массивы без пересборки объекта D. */
(function () {
  // ---------- HTTP ----------
  async function api(path, opts = {}) {
    const hasBody = opts.body !== undefined;
    const res = await fetch(path, {
      credentials: 'same-origin',
      headers: hasBody ? { 'Content-Type': 'application/json' } : undefined,
      method: opts.method || 'GET',
      body: hasBody ? JSON.stringify(opts.body) : undefined,
    });
    let data = null;
    try { data = await res.json(); } catch (_) { /* пустое тело */ }
    if (!res.ok) {
      const err = new Error((data && data.error) || res.statusText || 'request_failed');
      err.status = res.status;
      err.code = data && data.error;
      throw err;
    }
    return data;
  }

  // ---------- Хранилище (мутабельное; экраны читают через геттеры D) ----------
  const store = {
    TODAY: new Date().toISOString().slice(0, 10),
    currentUser: null,
    products: [],
    versions: [],
    licenses: [],
    downloadLog: [],
    adminUsers: [],
    adminLicenses: [],
    adminLog: [],
  };

  // ---------- Маппинг версии (changelog text -> массив, is_critical -> critical) ----------
  function mapVersion(v) {
    const changelog = typeof v.changelog === 'string'
      ? v.changelog.split('\n').map((s) => s.trim()).filter(Boolean)
      : Array.isArray(v.changelog) ? v.changelog : [];
    return {
      id: v.id,
      product_id: v.product_id,
      product_name: v.product_name,
      product_slug: v.product_slug,
      version: v.version,
      release_date: v.release_date,
      size: v.size || '—',
      critical: !!v.is_critical,
      changelog,
      yadisk_url: v.yadisk_url,
      updates_until: v.updates_until,
      available: v.available != null ? !!v.available : undefined,
    };
  }

  // ---------- Загрузка данных клиента ----------
  async function loadClient() {
    const [meR, prodR, verR, dlR] = await Promise.all([
      api('/api/auth/me'),
      api('/api/me/products'),
      api('/api/me/versions'),
      api('/api/me/downloads'),
    ]);
    store.currentUser = meR.user;

    const seen = new Map();
    store.licenses = [];
    for (const r of prodR.products) {
      if (!seen.has(r.id)) {
        seen.set(r.id, {
          id: r.id, name: r.name, slug: r.slug,
          tagline: r.tagline || '', description: r.description || '',
          icon: r.icon || 'fas fa-cube', platform: r.platform || '—', tags: [],
        });
      }
      if (r.license_id) {
        store.licenses.push({
          id: r.license_id, product_id: r.id, license_key: r.license_key,
          valid_until: r.valid_until, updates_until: r.updates_until, seats: r.seats,
        });
      }
    }
    store.products = [...seen.values()];
    store.versions = verR.versions.map(mapVersion);
    store.downloadLog = dlR.downloads.map((d) => ({
      id: d.id, product: d.product_name, version: d.version,
      created_at: d.created_at, ip: d.ip,
    }));
  }

  // ---------- Загрузка данных админки ----------
  async function loadAdmin() {
    const [meR, prodR, verR, licR, usrR, logR] = await Promise.all([
      api('/api/auth/me'),
      api('/api/admin/products'),
      api('/api/admin/versions'),
      api('/api/admin/licenses'),
      api('/api/admin/users'),
      api('/api/admin/log'),
    ]);
    store.currentUser = meR.user;
    store.products = prodR.products.map((p) => ({
      ...p,
      icon: p.icon || 'fas fa-cube',
      tagline: p.tagline || p.description || '',
    }));
    store.versions = verR.versions.map(mapVersion);
    store.adminLicenses = licR.licenses.map((l) => ({
      id: l.id, key: l.license_key, product: l.product_name,
      user: l.user_name || l.user_email, org: l.user_org || '—',
      valid_until: l.valid_until, updates_until: l.updates_until, seats: l.seats,
    }));
    store.adminUsers = usrR.users.map((u) => ({
      id: u.id, email: u.email, display_name: u.display_name || u.email,
      org: u.org || '—', role: u.role, licenses: u.licenses_count, created_at: u.created_at,
    }));
    store.adminLog = logR.log.map((l) => ({
      id: l.id, user: l.user_name || '—', org: l.user_org || '—',
      product: l.product_name, version: l.version, ip: l.ip, created_at: l.created_at,
    }));
  }

  // ---------- Аутентификация / мутации ----------
  async function login(email, password) {
    const r = await api('/api/auth/login', { method: 'POST', body: { email, password } });
    store.currentUser = r.user;
    return r.user;
  }
  async function me() {
    const r = await api('/api/auth/me');
    store.currentUser = r.user;
    return r.user;
  }
  async function logout() {
    try { await api('/api/auth/logout', { method: 'POST' }); } catch (_) { /* всё равно сбрасываем */ }
    store.currentUser = null;
  }
  async function getDownloadLink(versionId) {
    const r = await api(`/api/me/versions/${versionId}/link`);
    return r.url;
  }
  async function updateProfile(patch) {
    const r = await api('/api/me', { method: 'PATCH', body: patch });
    if (r && r.user) store.currentUser = r.user;
    return r && r.user;
  }

  const admin = {
    createProduct: (b) => api('/api/admin/products', { method: 'POST', body: b }),
    deleteProduct: (id) => api(`/api/admin/products/${id}`, { method: 'DELETE' }),
    createVersion: (b) => api('/api/admin/versions', { method: 'POST', body: b }),
    deleteVersion: (id) => api(`/api/admin/versions/${id}`, { method: 'DELETE' }),
    createLicense: (b) => api('/api/admin/licenses', { method: 'POST', body: b }),
    deleteLicense: (id) => api(`/api/admin/licenses/${id}`, { method: 'DELETE' }),
    createUser: (b) => api('/api/admin/users', { method: 'POST', body: b }),
  };

  // ---------- Утилиты дат ----------
  function parseDate(s) { return s ? new Date(s.slice(0, 10) + 'T00:00:00') : null; }
  function daysBetween(a, b) { return Math.round((parseDate(b) - parseDate(a)) / 86400000); }
  function formatDate(iso) {
    if (!iso) return '—';
    const d = iso.slice(0, 10).split('-');
    return `${d[2]}.${d[1]}.${d[0]}`;
  }

  // Статус права на обновления по лицензии (относительно сегодняшней даты).
  function updatesStatus(updates_until) {
    if (!updates_until) return { code: 'unlimited', label: 'Обновления без ограничения', tone: 'online' };
    const left = daysBetween(store.TODAY, updates_until);
    if (left < 0) return { code: 'expired', label: 'Право на обновления истекло', tone: 'danger', date: updates_until };
    if (left <= 60) return { code: 'soon', label: `Обновления до ${formatDate(updates_until)} · ${left} дн.`, tone: 'warning', date: updates_until, left };
    return { code: 'active', label: `Обновления до ${formatDate(updates_until)}`, tone: 'online', date: updates_until, left };
  }

  // Доступна ли версия. Предпочитаем серверный флаг available; иначе считаем по правилу.
  function versionAvailable(license, version) {
    if (version && version.available != null) return !!version.available;
    if (!license) return false;
    if (!license.updates_until) return true;
    return parseDate(version.release_date) <= parseDate(license.updates_until);
  }

  // ---------- Выборки ----------
  function versionsFor(productId) {
    return store.versions
      .filter((v) => v.product_id === productId)
      .sort((a, b) => parseDate(b.release_date) - parseDate(a.release_date));
  }
  function licenseFor(productId) {
    return store.licenses.find((l) => l.product_id === productId) || null;
  }
  function productById(id) { return store.products.find((p) => p.id === id); }
  function productBySlug(slug) { return store.products.find((p) => p.slug === slug); }
  function versionById(id) { return store.versions.find((v) => v.id === Number(id)); }

  const D = {
    get TODAY() { return store.TODAY; },
    get currentUser() { return store.currentUser; },
    get products() { return store.products; },
    get versions() { return store.versions; },
    get licenses() { return store.licenses; },
    get downloadLog() { return store.downloadLog; },
    get adminUsers() { return store.adminUsers; },
    get adminLicenses() { return store.adminLicenses; },
    get adminLog() { return store.adminLog; },
    parseDate, daysBetween, formatDate, updatesStatus, versionAvailable,
    versionsFor, licenseFor, productById, productBySlug, versionById,
    api, login, me, logout, getDownloadLink, updateProfile, loadClient, loadAdmin, admin,
  };

  window.PortalData = D;
})();
