// Лабораторный режим карты связей (network-view/lab).
//
// Назначение: на мок-данных (без бэкенда) щупать физику force-графа, панорамирование,
// центрирование и навигацию между пользователями. Используется связанный мульти-граф
// networkGraphUsers: у каждого пользователя свой набор связей, тап по узлу переключает
// карту на сеть этого человека (как реальный путь, но локально).
//
// + Прототип «Мегамасштаб»: переключатель «Вселенная» процедурно достраивает связи
//   2-го и 3-го уровней НА ФРОНТЕНДЕ (API отдаёт только прямые связи — его не трогаем).
//   Это чисто визуальный лабораторный эксперимент на мок-данных.

import { renderHeader } from '../../components/header.js';
import { networkGraphUsers } from '../../mock-data.js';
import { createForceGraph, buildModelFromTz } from './force-graph.js';
import { openNodeMenu } from './node-menu.js';

const START_LOGIN = 'ivan';

// Фильтры слоёв — те же, что в реальном пути network-view (предикат по периферийным узлам;
// фокус виден всегда). Позволяют пощупать в лаборатории в т.ч. слой «Сияющие».
const FILTERS = {
  all: { label: 'Все', pred: () => true },
  family: { label: 'Семья', pred: (n) => n.relationType === 'family' },
  friends: { label: 'Друзья', pred: (n) => n.relationType === 'friend' },
  shining: { label: 'Сияющие', pred: (n) => Boolean(n.shining) },
};
const FILTER_ORDER = ['all', 'family', 'friends', 'shining'];

// Пул имён для процедурных «дальних» узлов 2-го уровня (3-й уровень — без подписей, точки).
const DEEP_NAMES = ['Лео', 'Майя', 'Тео', 'Ева', 'Ник', 'Зоя', 'Ян', 'Ада', 'Рик', 'Уна',
  'Гор', 'Лия', 'Сэм', 'Иня', 'Ким', 'Эль', 'Юта', 'Бьорн', 'Мила', 'Орт'];

// Детерминированный сид 0..1 по строке (без Math.random: одинаковый узел всегда одинаков).
function seed01(str) {
  let h = 2166136261;
  const s = String(str || '');
  for (let i = 0; i < s.length; i += 1) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619); }
  return ((h >>> 0) % 100000) / 100000;
}

function helpText() {
  return [
    'Лаборатория карты связей (мок-данные, без сервера).',
    '• Тащите по экрану — карта свободно перемещается (pan).',
    '• Тап по узлу — он стягивается в центр и карта перестраивается под его сеть.',
    '• Тап по центральному узлу — здесь открылся бы профиль.',
    '• Долгое нажатие — контекстное меню (в реальном пути «Связи»).',
    '• Чипы под шапкой — фильтры слоёв: Все / Семья / Друзья / Сияющие.',
    '• Чип «Вселенная» — режим «Интерактивная паутина» (глубина 2-3 уровней, фейковые связи).',
    '  Наведи мышь/палец на узел — его связи временно выплывают (превью). КЛИК по узлу — «умный',
    '  наезд»: камера летит и центрирует его, он вырастает, друзья раскрываются крупно вокруг,',
    '  путь назад к Ивану горит нитью, остальное затемняется. Клик по нему ещё раз — всплыть.',
    '  Тап по центру (Ивану) — полный сброс (всё на 100%, камера отъезжает).',
    '  Колесо мыши / щипок двумя пальцами — зум; при сильном приближении точки 3-го уровня',
    '  превращаются в аватарки. Свайп — pan.',
    '',
    'Доступные люди: Иван, Алиса, Павел, Елена, Дмитрий, Олег, Нина, Марина, Света, Кирилл.',
  ].join('\n');
}

// Граф пользователя по логину; если такого нет в датасете — одинокий узел (без связей).
function graphForLogin(login) {
  const key = String(login || '').trim().toLowerCase();
  if (networkGraphUsers[key]) return networkGraphUsers[key];
  return { focusUser: { id: key, login: key, name: key, avatar: null, status: '' }, connections: [] };
}

// Если у фокуса нет прямых связей (например, тапнули по фейковому дальнему узлу) —
// синтезируем 4-6 связей 1-го уровня, чтобы «вселенная» вокруг него не была пустой.
function synthTier1(focusId) {
  const k = 4 + Math.floor(seed01(focusId + ':n') * 3); // 4-6
  const out = [];
  for (let i = 0; i < k; i += 1) {
    const id = `${focusId}__t1_${i}`;
    const s = seed01(id);
    out.push({
      id, login: id, name: DEEP_NAMES[Math.floor(seed01(id + 'n') * DEEP_NAMES.length)],
      avatar: null, photo: null,
      relationType: ['family', 'friend', 'business', 'contact'][i % 4],
      connectionStrength: 0.5 + s * 0.4,
      status: s > 0.78 ? 'shining' : '',
      hasOwnConnections: true, tier: 1,
    });
  }
  return out;
}

// Процедурно достраиваем дальние орбиты: для каждого узла 1-го уровня — 3-5 узлов 2-го уровня,
// для каждого узла 2-го уровня — 3-5 «микрозвёзд» 3-го уровня. Всё детерминировано по id.
function addDeepLevels(model) {
  const focusId = model.focusId;
  const tier1 = model.nodes.filter((n) => String(n.id) !== String(focusId));
  const extra = [];
  tier1.forEach((p) => {
    const k2 = 3 + Math.floor(seed01(p.id + ':2') * 3); // 3-5
    // «общий друг»: детерминированно берём ДРУГОГО друга Ивана — он окажется и в сети p (общая связь).
    const others = tier1.filter((o) => String(o.id) !== String(p.id));
    const common = others.length ? others[Math.floor(seed01(p.id + ':common') * others.length)] : null;
    for (let i = 0; i < k2; i += 1) {
      const id2 = `${p.id}__d2_${i}`;
      const ang2 = (i / k2) * Math.PI * 2 + seed01(p.id) * 0.6;
      // i===0 + есть общий → подставляем узнаваемого друга Ивана как ОБЩУЮ связь (золотой ободок ★)
      if (i === 0 && common) {
        extra.push({
          id: id2, login: id2, name: common.name || common.login,
          avatar: null, photo: common.photo || null, relationType: common.relationType || 'friend',
          strength: 0.5, shining: false, tier: 2, parentId: String(p.id), deepAngle: ang2, common: true,
        });
        continue;
      }
      // узлы 2-го уровня — полноценные (видимые) аватарки: детерминированное фото-лицо (pravatar) + имя
      const face2 = `https://i.pravatar.cc/120?img=${1 + Math.floor(seed01(id2 + 'p') * 70)}`;
      extra.push({
        id: id2, login: id2, name: DEEP_NAMES[Math.floor(seed01(id2) * DEEP_NAMES.length)],
        avatar: null, photo: face2, relationType: p.relationType || 'contact',
        strength: 0.4, shining: false, tier: 2, parentId: String(p.id), deepAngle: ang2,
      });
      const k3 = 3 + Math.floor(seed01(id2 + ':3') * 3); // 3-5
      for (let j = 0; j < k3; j += 1) {
        const id3 = `${id2}_d3_${j}`;
        const ang3 = (j / k3) * Math.PI * 2 + seed01(id2) * 0.9;
        // фото-лицо + имя для LOD: точка-звезда дорисуется в читаемую аватарку при сильном зуме
        const face3 = `https://i.pravatar.cc/100?img=${1 + Math.floor(seed01(id3 + 'p') * 70)}`;
        extra.push({
          id: id3, login: id3, name: DEEP_NAMES[Math.floor(seed01(id3 + 'n') * DEEP_NAMES.length)],
          avatar: null, photo: face3, relationType: 'contact',
          strength: 0.2, shining: seed01(id3) > 0.82, tier: 3, parentId: id2, deepAngle: ang3,
        });
      }
    }
  });
  return { focusId, nodes: [...model.nodes, ...extra] };
}

// Полная модель лаборатории для логина: реальные мок-связи (или синтетика для фейковых
// логинов) + опционально дальние уровни, когда включён режим «Вселенная».
// fromLogin — предыдущий фокус: остаётся на орбите ярким «треком прохождения» (Иван → Олег → …).
function buildLabModel(login, deep, fromLogin) {
  const tz = graphForLogin(login);
  if (!Array.isArray(tz.connections) || tz.connections.length === 0) {
    if (deep) tz.connections = synthTier1(String(tz.focusUser?.id || login));
    else tz.connections = [];
  }
  const base = buildModelFromTz(tz);

  // «Трек прохождения»: предыдущий фокус — на орбите, линия к нему горит ярко (не уходит в ghost).
  if (fromLogin && String(fromLogin).toLowerCase() !== String(login).toLowerCase()) {
    const fid = String(fromLogin);
    const found = base.nodes.find((n) => String(n.id).toLowerCase() === fid.toLowerCase()
      || String(n.login || '').toLowerCase() === fid.toLowerCase());
    if (found) {
      found.track = true; // уже среди связей — просто подсветим трек
    } else {
      const f = graphForLogin(fromLogin).focusUser || {};
      base.nodes.push({
        id: fid, login: f.login || fromLogin, name: f.name || fromLogin,
        avatar: f.avatar && f.avatar !== 'url_to_image' ? f.avatar : null,
        photo: f.photo || null, relationType: 'friend', strength: 0.97,
        shining: false, tier: 1, track: true,
      });
    }
  }
  return deep ? addDeepLevels(base) : base;
}

export function renderNetworkLab({ navigate }) {
  const screen = document.createElement('section');
  screen.className = 'network-screen';

  const appScreenEl = document.getElementById('app-screen');
  appScreenEl?.classList.add('network-scroll-lock');

  const stage = document.createElement('div');
  stage.className = 'network-stage fg-stage';

  const header = renderHeader({
    title: 'Связи · лаборатория',
    leftAction: { label: '←', onClick: () => navigate('network-view') },
    rightActions: [{ label: '?', onClick: () => window.alert(helpText()) }],
  });
  header.classList.add('network-header-overlay');

  let centerLogin = START_LOGIN;
  let deepMode = false;

  // Состояние активного слоя (как в network-view): фокус всегда виден.
  let activeFilter = 'all';
  const filterChips = {};
  function applyFilter(key) {
    if (!FILTERS[key]) return;
    activeFilter = key;
    FILTER_ORDER.forEach((k) => {
      const el = filterChips[k];
      if (el) el.classList.toggle('is-active', k === activeFilter);
    });
    graph.setFilter(FILTERS[key].pred);
  }

  stage.append(header);
  screen.append(stage);

  const model = buildLabModel(centerLogin, deepMode);

  // Объявлено заранее: onDiveChange (вызывается уже при монтировании) ссылается на эти элементы.
  let breadcrumbEl = null; // панель хлебных крошек (создаётся ниже)

  // Монтируем движок синхронно (не через rAF): размеры сцены движок берёт с запасом
  // (window.innerWidth) и корректирует через ResizeObserver, когда сцена попадёт в DOM.
  const graph = createForceGraph({
    stage,
    model,
    // тап по узлу — переключаем карту на сеть выбранного человека (или фейкового дальнего узла);
    // в режиме «Вселенная» вокруг нового центра процедурно генерится дальняя орбита.
    onNodeTap: (node) => {
      if (deepMode) {
        // Умный фокус: клик по ЛЮБОМУ узлу (Нина/её друг) — камера наезжает и центрирует его, ветка
        // раскрывается, путь назад к Ивану горит, остальное затемняется (0.25). Повтор по нему — всплыть.
        graph.diveTo(node);
        return;
      }
      // обычный режим: перецентрирование на выбранного человека (+ трек прохождения)
      const from = centerLogin;
      centerLogin = node.login || node.id;
      graph.setModel(buildLabModel(centerLogin, deepMode, from));
      if (activeFilter !== 'all') graph.setFilter(FILTERS[activeFilter].pred);
    },
    // Наведение мышью / касание пальцем — ВРЕМЕННОЕ раскрытие ветки (превью): выплывает под курсором,
    // втягивается при уходе (если узел не закреплён кликом). Только в режиме «Вселенная».
    onNodeHover: (node, over) => { if (deepMode) graph.setHover(over ? node : null); },
    // Изменение пути погружения → перерисовываем хлебные крошки (Иван › Нина › Ада).
    onDiveChange: (path) => renderBreadcrumb(path),
    onCenterTap: (node) => {
      // в паутине тап по корню (Ивану) — глобальный сброс: свернуть все раскрытые ветки
      if (deepMode) { graph.collapseAll(); return; }
      window.alert(`Профиль: ${node.name || node.login || node.id}`);
    },
    onNodeLongPress: (node, point) => openNodeMenu({
      login: node.name || node.login || node.id,
      relationType: node.relationType,
      point,
      actions: [
        { label: 'Профиль', onClick: () => window.alert(`Профиль: ${node.name || node.login}`) },
        { label: 'Написать', onClick: () => window.alert(`Написать: ${node.name || node.login}`) },
      ],
    }),
  });

  // Панель фильтров слоёв — тот же оверлей-стиль (.fg-filter-bar), что и в network-view.
  const filterBar = document.createElement('div');
  filterBar.className = 'fg-filter-bar';
  // Не даём нажатию на чип «провалиться» в сцену (иначе сцена перехватит указатель и «съест» click).
  filterBar.addEventListener('pointerdown', (e) => e.stopPropagation());
  FILTER_ORDER.forEach((key) => {
    const chip = document.createElement('button');
    chip.type = 'button';
    chip.className = `fg-filter-chip${key === activeFilter ? ' is-active' : ''}`;
    chip.textContent = FILTERS[key].label;
    chip.addEventListener('click', () => applyFilter(key));
    filterChips[key] = chip;
    filterBar.append(chip);
  });
  // Переключатель прототипа «Вселенная» (глубина 2-3 уровней) — отдельный чип.
  const deepChip = document.createElement('button');
  deepChip.type = 'button';
  deepChip.className = 'fg-filter-chip fg-deep-chip';
  deepChip.textContent = '🌌 Вселенная';
  deepChip.addEventListener('click', () => {
    deepMode = !deepMode;
    deepChip.classList.toggle('is-active', deepMode);
    graph.setModel(buildLabModel(centerLogin, deepMode));
    if (activeFilter !== 'all') graph.setFilter(FILTERS[activeFilter].pred);
  });
  filterBar.append(deepChip);
  stage.append(filterBar);

  // --- Поиск + телепорт камеры: ввёл имя → камера летит к узлу (dive в «Вселенной», иначе перецентр) ---
  const searchWrap = document.createElement('div');
  searchWrap.className = 'fg-search';
  searchWrap.addEventListener('pointerdown', (e) => e.stopPropagation());
  const searchIco = document.createElement('span');
  searchIco.className = 'fg-search-ico';
  searchIco.textContent = '🔍';
  const searchInput = document.createElement('input');
  searchInput.type = 'search';
  searchInput.placeholder = 'Найти человека…';
  searchInput.setAttribute('aria-label', 'Поиск по имени');
  function doSearch() {
    const hit = graph.findNode(searchInput.value);
    if (!hit) return;
    if (deepMode) {
      graph.diveTo({ id: hit.id });             // камера летит и центрирует найденного
    } else {
      const from = centerLogin;
      centerLogin = hit.id;
      graph.setModel(buildLabModel(centerLogin, deepMode, from));
      if (activeFilter !== 'all') graph.setFilter(FILTERS[activeFilter].pred);
    }
    searchInput.blur();
  }
  searchInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') doSearch(); });
  searchWrap.append(searchIco, searchInput);
  stage.append(searchWrap);

  // --- Хлебные крошки: стек погружений (Иван › Нина › Ада); клик по крошке — навигация назад ---
  breadcrumbEl = document.createElement('div');
  breadcrumbEl.className = 'fg-breadcrumb';
  breadcrumbEl.addEventListener('pointerdown', (e) => e.stopPropagation());
  stage.append(breadcrumbEl);
  // hoisted-функция: на неё ссылается onDiveChange (вызывается уже после монтирования UI)
  function renderBreadcrumb(path) {
    if (!breadcrumbEl) return;
    breadcrumbEl.innerHTML = '';
    const open = Array.isArray(path) && path.length > 1; // показываем только при активном погружении
    breadcrumbEl.classList.toggle('is-open', open);
    if (!open) return;
    path.forEach((p, i) => {
      if (i) { const sep = document.createElement('span'); sep.className = 'fg-crumb-sep'; sep.textContent = '›'; breadcrumbEl.append(sep); }
      const c = document.createElement('button');
      c.type = 'button';
      c.className = `fg-crumb${i === path.length - 1 ? ' is-last' : ''}`;
      c.textContent = p.name;
      if (i < path.length - 1) {
        c.addEventListener('click', () => { if (i === 0 || p.isFocus) graph.collapseAll(); else graph.diveTo({ id: p.id }); });
      }
      breadcrumbEl.append(c);
    });
  }

  // Автопроверки: ТОЛЬКО при ?fgtest — экспонируем граф и прогоняем self-test (результат в консоль).
  if (typeof window !== 'undefined' && String(location.search).includes('fgtest')) {
    window.__fg = graph;
    import('./selftest.js').then((m) => m.runNetworkSelfTest(graph, deepChip)).catch((e) => console.error('[fg-selftest] не загрузился', e));
  }

  screen.cleanup = () => {
    graph.destroy();
    appScreenEl?.classList.remove('network-scroll-lock');
  };

  return screen;
}
