const $ = s => document.querySelector(s);
const $$ = s => document.querySelectorAll(s);
const api = (path, opts = {}) => fetch(`/api/${path}`, {
  headers: { 'Content-Type': 'application/json' },
  ...opts,
  body: opts.body ? JSON.stringify(opts.body) : undefined,
}).then(r => r.json());

const PAGE_SIZE = 50;
const state = { projectPage: 1, userPage: 1 };

function parseTags(t) {
  try { return typeof t === 'string' ? JSON.parse(t) : (t || []); } catch { return []; }
}
function escHtml(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
function debounce(fn, ms) { let t; return (...a) => { clearTimeout(t); t = setTimeout(() => fn(...a), ms); }; }

// Tab 切换
function switchTab(tab) {
  $$('.nav-item').forEach(i => i.classList.remove('active'));
  $$('.tab-panel').forEach(p => p.classList.remove('active'));
  const navItem = $(`.nav-item[data-tab="${tab}"]`);
  if (navItem) navItem.classList.add('active');
  const panel = $(`#tab-${tab}`);
  if (panel) panel.classList.add('active');
  loadTab(tab);
}

$$('.nav-item').forEach(item => {
  item.addEventListener('click', () => switchTab(item.dataset.tab));
});

// Modal
function showModal(title, html, onSave) {
  $('#modal-title').textContent = title;
  $('#modal-content').innerHTML = html;
  $('#modal-save').style.display = onSave ? 'block' : 'none';
  $('#modal-save').onclick = onSave;
  $('#modal').classList.remove('hidden');
}
function hideModal() { $('#modal').classList.add('hidden'); }
$$('.modal-close').forEach(b => b.addEventListener('click', hideModal));
$('.modal-overlay').addEventListener('click', hideModal);

// 渲染记忆卡片（BEM: memory-card）
function renderMemoryCard(m) {
  const tags = parseTags(m.tags);
  return `<div class="memory-card">
    <div class="memory-card__header">
      <div class="memory-card__id">${m.id}</div>
      <div class="memory-card__actions">
        <button class="btn btn--ghost btn--sm" onclick="editMemory('${m.id}')">编辑</button>
        <button class="btn btn--ghost-danger btn--sm" onclick="deleteMemory('${m.id}')">删除</button>
      </div>
    </div>
    <div class="memory-card__content">${escHtml(m.content)}</div>
    <div class="memory-card__footer">
      <div class="memory-card__tags">${tags.map(t => `<span class="tag">${escHtml(t)}</span>`).join('')}</div>
      <div class="memory-card__time">${m.created_at || ''}</div>
    </div>
  </div>`;
}

// 分页渲染（BEM: pager）
function renderPager(containerId, page, total, onPage) {
  const pages = Math.ceil(total / PAGE_SIZE) || 1;
  if (pages <= 1) { $(containerId).innerHTML = ''; return; }
  let btns = '';
  for (let i = 1; i <= pages; i++) {
    btns += `<button class="pager__btn${i === page ? ' pager__btn--active' : ''}" data-page="${i}">${i}</button>`;
  }
  $(containerId).innerHTML = `<span class="pager__info">共 ${total} 条，第 ${page}/${pages} 页</span>${btns}`;
  $(containerId).querySelectorAll('.pager__btn').forEach(btn => {
    btn.addEventListener('click', () => onPage(parseInt(btn.dataset.page)));
  });
}

// 加载记忆（通用）
async function loadMemoriesByScope(scope, listId, pagerId, searchId, countId, pageKey) {
  const query = $(searchId).value;
  const page = state[pageKey];
  const offset = (page - 1) * PAGE_SIZE;
  const params = `memories?scope=${scope}&limit=${PAGE_SIZE}&offset=${offset}` + (query ? `&query=${encodeURIComponent(query)}` : '');
  const data = await api(params);
  const memories = data.memories || [];
  const total = data.total || memories.length;

  $(countId).textContent = `共 ${total} 条`;
  $(listId).innerHTML = memories.length
    ? memories.map(renderMemoryCard).join('')
    : '<div class="empty-state">暂无记忆</div>';

  renderPager(pagerId, page, total, p => { state[pageKey] = p; loadMemoriesByScope(scope, listId, pagerId, searchId, countId, pageKey); });
}

function loadProjectMemories() {
  loadMemoriesByScope('project', '#project-memory-list', '#project-pager', '#project-search', '#project-count', 'projectPage');
}
function loadUserMemories() {
  loadMemoriesByScope('user', '#user-memory-list', '#user-pager', '#user-search', '#user-count', 'userPage');
}

// 编辑记忆
window.editMemory = async (id) => {
  const m = await api(`memories/${id}`);
  const tags = parseTags(m.tags);
  showModal('编辑记忆', `
    <div class="form-field"><label class="form-label">内容</label>
      <textarea class="form-textarea" id="edit-content">${escHtml(m.content)}</textarea></div>
    <div class="form-field"><label class="form-label">标签（逗号分隔）</label>
      <input class="form-input" id="edit-tags" value="${tags.join(', ')}"></div>
  `, async () => {
    const content = $('#edit-content').value;
    const newTags = $('#edit-tags').value.split(',').map(t => t.trim()).filter(Boolean);
    await api(`memories/${id}`, { method: 'PUT', body: { content, tags: newTags } });
    hideModal();
    loadProjectMemories();
    loadUserMemories();
  });
};

// 删除记忆
window.deleteMemory = async (id) => {
  if (!confirm('确认删除？')) return;
  await api(`memories/${id}`, { method: 'DELETE' });
  loadProjectMemories();
  loadUserMemories();
};

function bindSearchClear(inputId, clearId, pageKey, loadFn) {
  const input = $(inputId), btn = $(clearId);
  const toggle = () => btn.classList.toggle('hidden', !input.value);
  input.addEventListener('input', debounce(() => { toggle(); state[pageKey] = 1; loadFn(); }, 300));
  btn.addEventListener('click', () => { input.value = ''; toggle(); state[pageKey] = 1; loadFn(); });
}
bindSearchClear('#project-search', '#project-search-clear', 'projectPage', loadProjectMemories);
bindSearchClear('#user-search', '#user-search-clear', 'userPage', loadUserMemories);

// 弹窗展示记忆列表
const MODAL_PAGE_SIZE = 10;

async function showMemoryModal(title, scope, query, page = 1, tag = null) {
  const offset = (page - 1) * MODAL_PAGE_SIZE;
  let params = `memories?scope=${scope}&limit=${MODAL_PAGE_SIZE}&offset=${offset}`;
  if (tag) params += `&tag=${encodeURIComponent(tag)}`;
  else if (query) params += `&query=${encodeURIComponent(query)}`;
  const data = await api(params);
  const memories = data.memories || [];
  const total = data.total || memories.length;
  const pages = Math.ceil(total / MODAL_PAGE_SIZE) || 1;

  const list = memories.length
    ? memories.map(renderMemoryCard).join('')
    : '<div class="empty-state">暂无记忆</div>';

  let pagerHtml = '';
  if (pages > 1) {
    let btns = '';
    for (let i = 1; i <= pages; i++) {
      btns += `<button class="pager__btn${i === page ? ' pager__btn--active' : ''}" data-page="${i}">${i}</button>`;
    }
    pagerHtml = `<div class="pager"><span class="pager__info">共 ${total} 条，第 ${page}/${pages} 页</span>${btns}</div>`;
  }

  showModal(title, `<div class="modal-list">${list}</div>${pagerHtml}`);
  $$('#modal-content .pager__btn').forEach(btn => {
    btn.addEventListener('click', () => showMemoryModal(title, scope, query, parseInt(btn.dataset.page), tag));
  });
}

async function showIssueModal(title, status, page = 1) {
  const url = status === 'archived' ? 'issues?status=archived' : `issues?status=${status}`;
  const data = await api(url);
  const issues = data.issues || [];
  const total = issues.length;
  const pages = Math.ceil(total / MODAL_PAGE_SIZE) || 1;
  const start = (page - 1) * MODAL_PAGE_SIZE;
  const slice = issues.slice(start, start + MODAL_PAGE_SIZE);

  const badgeMap = { pending: 'warning', in_progress: 'info', completed: 'success' };
  const list = slice.length ? slice.map(i => {
    const isArchived = !!i.archived_at;
    const badge = isArchived ? 'muted' : (badgeMap[i.status] || 'muted');
    const label = isArchived ? 'archived' : i.status;
    const meta = isArchived ? `${i.date} · 归档于 ${i.archived_at}` : `${i.date} · 创建于 ${i.created_at}`;
    return `
    <div class="issue-card">
      <div class="issue-card__header">
        <div class="issue-card__title"><span class="issue-card__number">#${i.issue_number}</span>${escHtml(i.title)}</div>
        <span class="badge badge--${badge}">${escHtml(label)}</span>
      </div>
      ${i.content ? `<div class="issue-card__content">${escHtml(i.content)}</div>` : ''}
      <div class="issue-card__meta">${meta}</div>
    </div>`;
  }).join('') : '<div class="empty-state">暂无问题</div>';

  let pagerHtml = '';
  if (pages > 1) {
    let btns = '';
    for (let i = 1; i <= pages; i++) {
      btns += `<button class="pager__btn${i === page ? ' pager__btn--active' : ''}" data-page="${i}">${i}</button>`;
    }
    pagerHtml = `<div class="pager"><span class="pager__info">共 ${total} 条，第 ${page}/${pages} 页</span>${btns}</div>`;
  }

  showModal(title, `<div class="modal-list">${list}</div>${pagerHtml}`);
  $$('#modal-content .pager__btn').forEach(btn => {
    btn.addEventListener('click', () => showIssueModal(title, status, parseInt(btn.dataset.page)));
  });
}

// 统计概览
async function loadStats() {
  const s = await api('stats');
  const mem = s.memories || {};
  const issues = s.issues || {};
  const tags = s.tags || {};
  const tagList = Object.entries(tags).sort((a, b) => b[1] - a[1]);
  const tagListTop5 = tagList.slice(0, 10);
  const issueTotal = Object.values(issues).reduce((a, b) => a + b, 0);

  const badgeMap = { pending: 'warning', in_progress: 'info', completed: 'success', archived: 'muted' };
  const labelMap = { pending: '待处理', in_progress: '进行中', completed: '已完成', archived: '已归档' };

  $('#stats-content').innerHTML = `
    <div class="stat-card stat-card--primary">
      <div class="stat-card__header">
        <span class="stat-card__label">记忆总数</span>
        <svg class="stat-card__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
          <circle cx="12" cy="6" r="2.5"/><circle cx="6" cy="16" r="2"/><circle cx="18" cy="16" r="2"/><circle cx="12" cy="22" r="1.5"/>
          <line x1="12" y1="8.5" x2="6" y2="14"/><line x1="12" y1="8.5" x2="18" y2="14"/><line x1="6" y1="18" x2="12" y2="20.5"/><line x1="18" y1="18" x2="12" y2="20.5"/>
        </svg>
      </div>
      <div class="stat-card__number">${mem.total || 0}</div>
      <div class="stat-card__detail">
        <a class="stat-link" data-action="goto-tab" data-tab="project-memories">项目级 <strong>${mem.project || 0}</strong></a>
        ·
        <a class="stat-link" data-action="goto-tab" data-tab="user-memories">用户级 <strong>${mem.user || 0}</strong></a>
      </div>
    </div>
    <div class="stat-card stat-card--success">
      <div class="stat-card__header">
        <span class="stat-card__label">问题统计</span>
        <svg class="stat-card__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>
      </div>
      <div class="stat-card__number">${issueTotal}</div>
      <ul class="stat-list">
        ${['pending', 'in_progress', 'completed', 'archived'].map(k =>
          `<li><a class="stat-link" data-action="filter-issues" data-status="${k}"><span>${labelMap[k]}</span><span class="badge badge--${badgeMap[k]}">${issues[k] || 0}</span></a></li>`
        ).join('')}
      </ul>
    </div>
    <div class="stat-card stat-card--accent">
      <div class="stat-card__header">
        <span class="stat-card__label">标签分布</span>
        <a class="stat-card__more stat-link" data-action="show-all-tags">查看更多</a>
      </div>
      <ul class="stat-list stat-list--tags">
        ${tagListTop5.length ? tagListTop5.map(([k, v]) =>
          `<li><a class="stat-link" data-action="filter-tag" data-tag="${escHtml(k)}"><span>${escHtml(k)}</span><span class="tag-count">${v}</span></a></li>`
        ).join('') : '<li><span>暂无</span></li>'}
      </ul>
    </div>
  `;

  // 向量记忆网络可视化
  renderVectorNetwork(tagList);

  // stat-link 点击事件
  $$('#stats-content .stat-link').forEach(link => {
    link.addEventListener('click', () => {
      const action = link.dataset.action;
      if (action === 'filter-issues') {
        const labelMap2 = { pending: '待处理', in_progress: '进行中', completed: '已完成', archived: '已归档' };
        showIssueModal(labelMap2[link.dataset.status] || '问题列表', link.dataset.status);
      } else if (action === 'filter-tag') {
        showMemoryModal(`标签：${link.dataset.tag}`, 'all', '', 1, link.dataset.tag);
      } else if (action === 'show-all-tags') {
        const html = tagList.length ? `<ul class="stat-list stat-list--tags">${tagList.map(([k, v]) =>
          `<li><a class="stat-link" data-tag="${escHtml(k)}" style="cursor:pointer"><span>${escHtml(k)}</span><span class="tag-count">${v}</span></a></li>`
        ).join('')}</ul>` : '<div class="empty-state">暂无标签</div>';
        showModal(`全部标签（${tagList.length}）`, html);
        $$('#modal-content .stat-link').forEach(t => {
          t.addEventListener('click', () => { hideModal(); showMemoryModal(`标签：${t.dataset.tag}`, 'all', '', 1, t.dataset.tag); });
        });
      } else if (action === 'goto-tab') {
        const tab = link.dataset.tab;
        const scope = tab === 'user-memories' ? 'user' : 'project';
        const title = scope === 'user' ? '用户记忆' : '项目记忆';
        showMemoryModal(title, scope, '');
      }
    });
  });
}

// 向量记忆网络可视化
function renderVectorNetwork(tagList) {
  const W = 800, H = 360, MAX_NODES = 15, FL = 600, R = 130;
  const items = tagList.slice(0, MAX_NODES);
  if (!items.length) { $('#vector-network-container').innerHTML = ''; return; }

  const maxC = items[0][1], minC = items[items.length - 1][1] || 1;
  const colors = ['#3B82F6','#2563EB','#60A5FA','#818CF8','#A78BFA','#34D399','#F59E0B','#EF4444','#EC4899','#14B8A6','#8B5CF6','#F97316','#06B6D4','#84CC16','#E879F9'];

  const nodes3d = items.map(([label, count], i) => {
    const t = maxC === minC ? 0.5 : (count - minC) / (maxC - minC);
    const baseR = 6 + t * 14;
    const phi = Math.acos(1 - 2 * (i + 0.5) / items.length);
    const theta = Math.PI * (1 + Math.sqrt(5)) * i;
    return { label, count, baseR, x: R * Math.sin(phi) * Math.cos(theta), y: R * Math.cos(phi), z: R * Math.sin(phi) * Math.sin(theta), px: 0, py: 0, pz: 0 };
  });

  const edges = [];
  for (let i = 0; i < nodes3d.length; i++) {
    if (i + 1 < nodes3d.length) edges.push([i, i + 1]);
    if (i + 3 < nodes3d.length) edges.push([i, i + 3]);
  }
  if (nodes3d.length > 2) edges.push([nodes3d.length - 1, 0]);

  const container = $('#vector-network-container');
  container.innerHTML = `
    <div class="vector-network">
      <div class="vector-network__header">
        <span class="vector-network__label">记忆向量网络</span>
        <span class="vector-network__sub">语义关联 · 3D 拓扑 · 鼠标旋转</span>
      </div>
      <svg class="vector-graph" viewBox="0 0 ${W} ${H}"></svg>
    </div>`;

  const svg = container.querySelector('.vector-graph');
  const ns = 'http://www.w3.org/2000/svg';

  // 创建边 DOM（一次性）
  const edgeEls = edges.map(([a, b]) => {
    const line = document.createElementNS(ns, 'line');
    line.setAttribute('class', a % 3 === 0 ? 'vg-edge vg-edge--weak' : 'vg-edge');
    svg.appendChild(line);
    return { el: line, a, b };
  });

  // 创建节点 DOM（一次性）
  const nodeEls = nodes3d.map((n, i) => {
    const g = document.createElementNS(ns, 'g');
    g.setAttribute('class', 'vg-node');
    const color = colors[i % colors.length];
    const glow = document.createElementNS(ns, 'circle');
    glow.setAttribute('class', 'vg-node__glow');
    glow.style.fill = color + '15';
    const core = document.createElementNS(ns, 'circle');
    core.setAttribute('class', 'vg-node__core');
    core.style.fill = color;
    const text = document.createElementNS(ns, 'text');
    text.setAttribute('class', 'vg-node__label');
    text.textContent = n.label;
    g.appendChild(glow); g.appendChild(core); g.appendChild(text);
    svg.appendChild(g);
    g.addEventListener('click', (e) => {
      const dx = e.clientX - startX, dy = e.clientY - startY;
      if (dx * dx + dy * dy > 25) return;
      showMemoryModal(`关键词：${n.label}`, 'all', '', 1, n.label);
    });
    return { g, glow, core, text };
  });

  let rotY = 0, rotX = 0.3, autoSpeed = 0.003, isHovering = false;
  let dragging = false, lastX = 0, lastY = 0, startX = 0, startY = 0;

  const update = () => {
    const cosY = Math.cos(rotY), sinY = Math.sin(rotY), cosX = Math.cos(rotX), sinX = Math.sin(rotX);
    nodes3d.forEach(n => {
      const x1 = n.x * cosY - n.z * sinY, z1 = n.x * sinY + n.z * cosY;
      n.px = x1; n.py = n.y * cosX - z1 * sinX; n.pz = n.y * sinX + z1 * cosX;
    });

    // z-sort：先画远的
    const order = nodes3d.map((_, i) => i).sort((a, b) => nodes3d[b].pz - nodes3d[a].pz);

    // 更新边
    edgeEls.forEach(({ el, a, b }) => {
      const na = nodes3d[a], nb = nodes3d[b];
      const sa = FL / (FL + na.pz), sb = FL / (FL + nb.pz);
      el.setAttribute('x1', (W / 2 + na.px * sa).toFixed(1));
      el.setAttribute('y1', (H / 2 + na.py * sa).toFixed(1));
      el.setAttribute('x2', (W / 2 + nb.px * sb).toFixed(1));
      el.setAttribute('y2', (H / 2 + nb.py * sb).toFixed(1));
      el.style.opacity = (0.08 + 0.25 * ((na.pz + nb.pz) / 2 + R) / (2 * R)).toFixed(2);
    });

    // 更新节点（按 z-order 重排 DOM）
    order.forEach(i => {
      const n = nodes3d[i], el = nodeEls[i];
      const s = FL / (FL + n.pz);
      const depth = (n.pz + R) / (2 * R);
      const cr = n.baseR * s, gr = cr * 2.5;
      el.g.setAttribute('transform', `translate(${(W / 2 + n.px * s).toFixed(1)},${(H / 2 + n.py * s).toFixed(1)})`);
      el.g.style.opacity = (0.4 + 0.6 * depth).toFixed(2);
      el.glow.setAttribute('r', gr.toFixed(1));
      el.core.setAttribute('r', cr.toFixed(1));
      el.text.setAttribute('dy', (gr + 10).toFixed(0));
      svg.appendChild(el.g);
    });
  };

  let animId;
  const animate = () => {
    if (!isHovering) rotY += autoSpeed;
    update();
    animId = requestAnimationFrame(animate);
  };

  svg.addEventListener('mouseenter', () => { isHovering = true; });
  svg.addEventListener('mouseleave', () => { isHovering = false; dragging = false; });
  svg.addEventListener('mousedown', (e) => { dragging = true; startX = e.clientX; startY = e.clientY; lastX = e.clientX; lastY = e.clientY; e.preventDefault(); });
  svg.addEventListener('mousemove', (e) => {
    if (!dragging) return;
    rotY += (e.clientX - lastX) * 0.008;
    rotX = Math.max(-1.2, Math.min(1.2, rotX + (e.clientY - lastY) * 0.008));
    lastX = e.clientX; lastY = e.clientY;
  });
  svg.addEventListener('mouseup', () => { dragging = false; });

  update();
  animate();

  const observer = new MutationObserver(() => {
    if (!document.contains(svg)) { cancelAnimationFrame(animId); observer.disconnect(); }
  });
  observer.observe(document.body, { childList: true, subtree: true });
}

// 会话状态（BEM: status-grid, status-section）
async function loadStatus() {
  const s = await api('status');
  if (s.empty) { $('#status-content').innerHTML = '<div class="empty-state">暂无会话状态</div>'; return; }

  const isBlocked = s.is_blocked;
  const dotClass = isBlocked ? 'status-dot--blocked' : 'status-dot--ok';
  const blockText = isBlocked ? `是 - ${escHtml(s.block_reason || '')}` : '无';

  const gridItems = [
    ['阻塞状态', `<span class="status-dot ${dotClass}"></span>${blockText}`, 'status-item--alert'],
    ['当前任务', escHtml(s.current_task || '-')],
    ['下一步', escHtml(s.next_step || '-')],
    ['更新时间', s.updated_at || '-'],
  ];

  const sections = [
    ['进度', s.progress],
    ['最近修改', s.recent_changes],
    ['待处理', s.pending],
  ].filter(([, arr]) => arr && arr.length);

  $('#status-content').innerHTML = `
    <div class="status-grid">
      ${gridItems.map(([label, value, cls]) =>
        `<div class="status-item${cls ? ' ' + cls : ''}">
          <div class="status-item__label">${label}</div>
          <div class="status-item__value">${value}</div>
        </div>`
      ).join('')}
    </div>
    ${sections.map(([title, items]) => `
      <div class="status-section">
        <div class="status-section__title">${title}</div>
        <div class="status-section__list">
          ${items.map(p => `<div class="status-section__item">· ${escHtml(p)}</div>`).join('')}
        </div>
      </div>
    `).join('')}
  `;
}

// 问题跟踪（BEM: issue-card）
async function loadIssues() {
  const date = $('#issue-date').value;
  const status = $('#issue-status-filter').value;
  let url = 'issues?';
  if (date) url += `date=${date}&`;
  if (status === 'archived') url += 'include_archived=true';
  else if (status) url += `status=${status}`;
  const data = await api(url);
  const issues = data.issues || [];

  const badgeMap = { pending: 'warning', in_progress: 'info', completed: 'success' };

  $('#issue-list').innerHTML = issues.length ? issues.map(i => {
    const isArchived = !!i.archived_at;
    const badge = isArchived ? 'muted' : (badgeMap[i.status] || 'muted');
    const label = isArchived ? 'archived' : i.status;
    const meta = isArchived ? `${i.date} · 归档于 ${i.archived_at}` : `${i.date} · 创建于 ${i.created_at}`;
    return `
    <div class="issue-card">
      <div class="issue-card__header">
        <div class="issue-card__title">
          <span class="issue-card__number">#${i.issue_number}</span>
          ${escHtml(i.title)}
        </div>
        <span class="badge badge--${badge}">${escHtml(label)}</span>
      </div>
      ${i.content ? `<div class="issue-card__content">${escHtml(i.content)}</div>` : ''}
      <div class="issue-card__meta">${meta}</div>
    </div>`;
  }).join('') : '<div class="empty-state">暂无问题</div>';
}

$('#issue-date').addEventListener('change', loadIssues);
$('#issue-status-filter').addEventListener('change', loadIssues);

function loadTab(tab) {
  ({
    stats: loadStats,
    'project-memories': loadProjectMemories,
    'user-memories': loadUserMemories,
    status: loadStatus,
    issues: loadIssues,
  })[tab]?.();
}

// 初始加载
loadStats();
