/* ============================================================
   atlas.js — Protein Atlas 탭 (단백질 그리드 + NGL 3D 구조)
   ============================================================ */
(function () {
  'use strict';

  const AXIS_LABELS = {
    AND: "안드로겐(AR/DHT)", Wnt: "Wnt/β-catenin", BMP: "BMP/TGFβ", SHH: "Hedgehog",
    INF: "염증/JAK-STAT", APO: "세포사멸/산화", DP: "진피유두/성장인자", HFSC: "모낭 줄기세포",
  };
  const AXIS_COLOR = {
    AND: "#f87171", Wnt: "#6699ff", BMP: "#a78bfa", SHH: "#22d3ee",
    INF: "#fbbf24", APO: "#fb923c", DP: "#34d399", HFSC: "#f472b6", "—": "#64748b",
  };

  let nglStage = null, selectedGene = null;
  function el(id) { return document.getElementById(id); }

  function init() {
    const axisSel = el('atlas-axis'), disSel = el('atlas-disease');
    const axes = [...new Set(Store.catalog.proteins.map(p => p.twin_node))].filter(a => a && a !== '—');
    axes.forEach(a => axisSel.add(new Option(AXIS_LABELS[a] || a, a)));
    const diseases = [...new Set(Store.catalog.proteins.flatMap(p => p.diseases || []))].sort();
    diseases.forEach(d => disSel.add(new Option(d, d)));

    ['atlas-search', 'atlas-axis', 'atlas-disease', 'atlas-sort'].forEach(id =>
      el(id).addEventListener('input', renderGrid));
    // resize 핸들러는 단 한 번만 등록 (이전: loadStructure 마다 추가 → 누수)
    window.addEventListener('resize', () => nglStage && nglStage.handleResize());
    renderGrid();
  }

  function filtered() {
    const q = el('atlas-search').value.trim().toLowerCase();
    const ax = el('atlas-axis').value, dis = el('atlas-disease').value, sort = el('atlas-sort').value;
    let list = Store.catalog.proteins.filter(p => {
      if (ax && p.twin_node !== ax) return false;
      if (dis && !(p.diseases || []).includes(dis)) return false;
      if (q && !(p.gene.toLowerCase().includes(q) || (p.name || '').toLowerCase().includes(q))) return false;
      return true;
    });
    const plddt = p => (p.structure && p.structure.mean_plddt) || 0;
    const sorters = {
      evidence: (a, b) => b.n_evidence - a.n_evidence || b.mention_count - a.mention_count,
      mention: (a, b) => b.mention_count - a.mention_count,
      plddt: (a, b) => plddt(b) - plddt(a),
      gene: (a, b) => a.gene.localeCompare(b.gene),
    };
    return list.sort(sorters[sort] || sorters.evidence);
  }

  function renderGrid() {
    const list = filtered();
    el('atlas-count').textContent = list.length;
    const grid = el('atlas-grid');
    grid.innerHTML = list.map(p => {
      const ax = p.twin_node || '—';
      const seed = p.in_model ? '<span class="pc-seed">●seed</span>' : `<span class="pc-ev">${p.n_evidence}편</span>`;
      return `<div class="prot-card${p.gene === selectedGene ? ' selected' : ''}" data-gene="${p.gene}">
        ${seed}
        <div class="pc-gene">${p.gene}</div>
        <div class="pc-name">${p.name || ''}</div>
        <div class="pc-tags">
          <span class="axis-tag" style="background:${hex(AXIS_COLOR[ax], .16)};color:${AXIS_COLOR[ax]}">${ax}</span>
          <span class="axis-tag role-${p.role}">${p.role || ''}</span>
        </div></div>`;
    }).join('');
    grid.querySelectorAll('.prot-card').forEach(c =>
      c.onclick = () => showDetail(c.dataset.gene));
  }

  function hex(h, a) {
    const n = parseInt((h || '#64748b').slice(1), 16);
    return `rgba(${n >> 16 & 255},${n >> 8 & 255},${n & 255},${a})`;
  }

  function showDetail(gene) {
    const p = Store.proteinByGene[gene];
    if (!p) return;
    if (gene === selectedGene && !el('atlas-detail').classList.contains('hidden')) return; // 동일 단백질 재로딩 방지
    selectedGene = gene;
    document.querySelectorAll('.prot-card').forEach(c => c.classList.toggle('selected', c.dataset.gene === gene));
    el('atlas-detail-empty').classList.add('hidden');
    el('atlas-detail').classList.remove('hidden');

    el('d-gene').textContent = p.gene;
    el('d-name').textContent = p.uniprot_name || p.name || '';
    const st = p.structure || {};
    el('d-badges').innerHTML = [
      p.in_model ? '<span class="dbadge" style="color:#a855f7">트윈 wired</span>' : '',
      `<span class="dbadge">${AXIS_LABELS[p.twin_node] || '축 미배정'}</span>`,
      `<span class="dbadge role-${p.role}">${p.role || ''}</span>`,
    ].filter(Boolean).join('');

    // 메타 그리드
    el('d-meta').innerHTML = [
      ['경로 (Pathway)', p.pathway || '—'],
      ['UniProt', st.accession || '—'],
      ['질환', (p.diseases || []).join(', ') || '—'],
      ['서열 길이', p.length ? p.length + ' aa' : '—'],
      ['PDB 실험구조', (p.pdb_count || 0) + '개'],
      ['논문 언급', p.mention_count + '회'],
    ].map(([k, v]) => `<div class="dg"><div class="k">${k}</div><div class="v">${v}</div></div>`).join('');

    el('d-mech').textContent = p.mechanism || p.function || '기전 정보 없음';
    el('d-drugs').innerHTML = (p.drugs || []).length
      ? p.drugs.map(d => `<span class="gene-pill">${d}</span>`).join('')
      : '<span class="panel-subtitle">등록된 표적 약물 없음</span>';

    // 근거 논문
    const ev = (p.evidence_paper_ids || []);
    el('d-evcount').textContent = ev.length;
    el('d-evidence').innerHTML = ev.length ? ev.slice(0, 30).map(id => {
      const info = Store.papersIdx[id] || {};
      return `<a class="evidence-item" href="https://pubmed.ncbi.nlm.nih.gov/${id}/" target="_blank" style="text-decoration:none;color:inherit;display:block">
        <span class="ey">${info.year || ''}</span>${info.title || ('PMID ' + id)}</a>`;
    }).join('') : '<span class="panel-subtitle">초록 스캔/추출 근거 없음 (캐논 표적)</span>';

    // 실제 논문 전문 근거 (검증 인용) — 요소 없을 때(구버전 HTML 캐시) 안전 가드
    const gr = p.grounding || [];
    const gcEl = el('d-groundcount'); if (gcEl) gcEl.textContent = gr.length;
    const grEl = el('d-grounding');
    if (grEl) grEl.innerHTML = gr.length ? gr.map(h =>
      `<div class="grounding-item"><div class="gr-paper">📄 ${h.paper} <span class="gr-hits">${h.n_hits}회 언급</span></div>
        <div class="gr-quote">"…${(h.quote || '').replace(/"/g, '&quot;')}…"</div></div>`).join('')
      : (p.grounded_in_corpus === false
          ? '<span class="panel-subtitle">분석 코퍼스(papers/) 전문에 근거 없음 — 웹 발굴(2024–26) 또는 canonical 경로 멤버</span>'
          : '<span class="panel-subtitle">—</span>');

    // 외부 링크
    el('d-links').innerHTML = [
      st.uniprot_url ? `<a href="${st.uniprot_url}" target="_blank">UniProt ↗</a>` : '',
      st.af_entry_url ? `<a href="${st.af_entry_url}" target="_blank">AlphaFold DB ↗</a>` : '',
    ].filter(Boolean).join('');

    el('d-plddt').textContent = st.mean_plddt ? `평균 pLDDT ${st.mean_plddt} (${st.plddt_band || ''})` : '구조 신뢰도 미계산';
    loadStructure(p);
  }

  function loadStructure(p) {
    const viewer = el('ngl-viewer');
    const st = p.structure || {};
    const afLink = st.af_entry_url || (st.accession ? `https://alphafold.ebi.ac.uk/entry/${st.accession}` : null);
    const fallback = (msg) => {
      viewer.innerHTML = `<div class="ngl-loading" style="flex-direction:column;gap:8px;text-align:center">${msg}` +
        (afLink ? `<a href="${afLink}" target="_blank" style="color:var(--primary);text-decoration:underline">AlphaFold에서 3D 구조 보기 ↗</a>` : '') + `</div>`;
    };
    viewer.innerHTML = '<div class="ngl-loading">AlphaFold 구조 로딩 중…</div>';
    if (typeof NGL === 'undefined') { fallback('NGL 라이브러리 미로딩'); return; }
    if (!st.accession) { fallback('구조 정보 없음'); return; }
    if (nglStage) { try { nglStage.dispose(); } catch (e) {} nglStage = null; }
    try {
      nglStage = new NGL.Stage('ngl-viewer', { backgroundColor: '#0e0d0b' });
    } catch (e) { fallback('3D 뷰어(WebGL) 사용 불가'); return; }

    // 서빙 디렉토리/오프라인 무관 — 로컬(프로젝트루트) → 원격 AlphaFold 순 폴백
    const candidates = [];
    if (st.local_pdb) candidates.push(['../' + st.local_pdb.replace(/\\/g, '/'), 'pdb']);
    if (st.af_cif_url) candidates.push([st.af_cif_url, 'cif']);
    if (st.af_pdb_url) candidates.push([st.af_pdb_url, 'pdb']);

    (function tryLoad(i) {
      if (i >= candidates.length) { fallback('구조 로드 실패 (네트워크/경로)'); return; }
      const [url, ext] = candidates[i];
      let comp_done = false;
      nglStage.loadFile(url, { ext }).then(comp => {
        const ld = viewer.querySelector('.ngl-loading'); if (ld) ld.remove();
        comp.addRepresentation('cartoon', {
          colorScheme: 'bfactor', colorScale: ['#FF7D45', '#FFDB13', '#65CBF3', '#0053D6'],
          colorDomain: [40, 100], smoothSheet: true,
        });
        comp.autoView();
        try { nglStage.setSpin(true); } catch (e) {}
        comp_done = true;
      }).catch(() => tryLoad(i + 1));
    })(0);
  }

  window.AtlasTab = { init, resize: () => nglStage && nglStage.handleResize() };
  window.openProtein = function (gene) {
    document.querySelector('.tab-btn[data-tab="atlas"]').click();
    setTimeout(() => showDetail(gene), 60);
  };
})();
