// insights.jsx — 호재/악재 상세 + 12개 지표 상세 페이지 + 대시보드 실시간 피드
// 라우트: #/app/events, #/app/event/:id, #/app/factor/:id
// 전역 의존: T, won, pct, Panel, PageHead, Spark, Delta, SignalBadge, GradePill,
//            ScoreBar, useIsMobile, navigate, APTS, FACTORS, MARKET_EVENTS, FACTOR_INFO

// ─── 영향 배지 (호재/악재/정책/중립) ─────────────────────
function impactMeta(impact) {
  if (impact === 'positive') return { c: T.up, bg: T.upBg, arrow: '▲', word: '호재' };
  if (impact === 'negative') return { c: T.down, bg: T.downBg, arrow: '▼', word: '악재' };
  return { c: T.info, bg: T.infoBg, arrow: '◆', word: '중립' };
}
function KindTag({ kind, impact }) {
  const m = impactMeta(impact);
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, padding: '2px 8px', borderRadius: 3, background: m.bg, color: m.c, border: '1px solid ' + m.c + '40', fontFamily: T.mono, fontSize: 10, fontWeight: 700, whiteSpace: 'nowrap' }}>
      <span style={{ fontSize: 8 }}>{m.arrow}</span>{kind || m.word}
    </span>
  );
}
// 영향 강도 막대 (mag 1~5)
function MagBar({ mag, impact }) {
  const m = impactMeta(impact);
  return (
    <div style={{ display: 'flex', gap: 3 }}>
      {[1, 2, 3, 4, 5].map(i => (
        <span key={i} style={{ width: 14, height: 5, borderRadius: 2, background: i <= mag ? m.c : T.cardLo, boxShadow: i <= mag ? '0 0 6px ' + m.c + '70' : 'none' }} />
      ))}
    </div>
  );
}

// ─── 지표 아이콘 ──────────────────────────────────────
function FactorIcon({ id, size = 20, color = 'currentColor' }) {
  const s = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none', stroke: color, strokeWidth: 1.7, strokeLinecap: 'round', strokeLinejoin: 'round', style: { display: 'block' } };
  const ic = (FACTOR_INFO[id] || {}).icon;
  switch (ic) {
    case 'pulse': return <svg {...s}><path d="M3 12h4l2 6 4-14 2 8h6"/></svg>;
    case 'box': return <svg {...s}><path d="M21 8l-9-5-9 5 9 5 9-5z"/><path d="M3 8v8l9 5 9-5V8"/></svg>;
    case 'percent': return <svg {...s}><path d="M19 5L5 19"/><circle cx="7.5" cy="7.5" r="2.5"/><circle cx="16.5" cy="16.5" r="2.5"/></svg>;
    case 'train': return <svg {...s}><rect x="5" y="3" width="14" height="14" rx="3"/><path d="M5 11h14M9 21l-2-2M15 21l2-2"/><circle cx="9" cy="14" r="0.6" fill={color}/><circle cx="15" cy="14" r="0.6" fill={color}/></svg>;
    case 'book': return <svg {...s}><path d="M4 5a2 2 0 0 1 2-2h12v16H6a2 2 0 0 0-2 2z"/><path d="M4 19a2 2 0 0 1 2-2h12"/></svg>;
    case 'crane': return <svg {...s}><path d="M5 21V4l14 3M5 7h14M9 7v4M5 21h8"/><rect x="7" y="11" width="4" height="4"/></svg>;
    case 'scale': return <svg {...s}><path d="M12 3v18M5 21h14M7 7l-4 7h8zM17 7l-4 7h8zM7 7l5-2 5 2"/></svg>;
    case 'globe': return <svg {...s}><circle cx="12" cy="12" r="9"/><path d="M3 12h18M12 3c3 3 3 15 0 18M12 3c-3 3-3 15 0 18"/></svg>;
    case 'swap': return <svg {...s}><path d="M7 4v13M7 4L3 8M7 4l4 4M17 20V7M17 20l4-4M17 20l-4-4"/></svg>;
    case 'layers': return <svg {...s}><path d="M12 3l9 5-9 5-9-5 9-5zM3 13l9 5 9-5M3 17l9 5 9-5"/></svg>;
    case 'wallet': return <svg {...s}><rect x="3" y="6" width="18" height="13" rx="2"/><path d="M16 12h2"/><path d="M3 9h13a1 1 0 0 1 1 1"/></svg>;
    case 'users': return <svg {...s}><circle cx="9" cy="8" r="3"/><path d="M3 20c0-3 3-5 6-5s6 2 6 5"/><path d="M16 6a3 3 0 0 1 0 6M21 20c0-2.5-1.5-4-4-4.5"/></svg>;
    default: return <svg {...s}><circle cx="12" cy="12" r="8"/><path d="M12 8v4l3 2"/></svg>;
  }
}

// ─── 큰 미니 차트 (지표 추이) ─────────────────────────
function TrendChart({ data, color, w = 560, h = 120, unit }) {
  if (!data || data.length < 2) return null;
  const min = Math.min(...data), max = Math.max(...data);
  const range = max - min || 1;
  const pad = { l: 6, r: 6, t: 10, b: 16 };
  const iw = w - pad.l - pad.r, ih = h - pad.t - pad.b;
  const xAt = i => pad.l + (i / (data.length - 1)) * iw;
  const yAt = v => pad.t + (1 - (v - min) / range) * ih;
  const path = 'M ' + data.map((v, i) => xAt(i) + ' ' + yAt(v)).join(' L ');
  const area = path + ` L ${xAt(data.length - 1)} ${h - pad.b} L ${xAt(0)} ${h - pad.b} Z`;
  const c = color || T.hot;
  const months = ['25.06', '25.08', '25.10', '25.12', '26.02', '26.05'];
  return (
    <svg width={w} height={h} viewBox={`0 0 ${w} ${h}`} preserveAspectRatio="none" style={{ display: 'block', width: '100%', height: 'auto' }}>
      {[0.25, 0.5, 0.75].map((f, i) => (
        <line key={i} x1={pad.l} x2={w - pad.r} y1={pad.t + ih * f} y2={pad.t + ih * f} stroke={T.line} strokeWidth="1" strokeDasharray="2 3" />
      ))}
      <path d={area} fill={c} fillOpacity="0.12" />
      <path d={path} stroke={c} strokeWidth="2" fill="none" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={xAt(data.length - 1)} cy={yAt(data[data.length - 1])} r="3.5" fill={c} stroke={T.bg} strokeWidth="1.5" />
    </svg>
  );
}

// ─── 이벤트 카드 (목록/관련용) ─────────────────────────
function EventRow({ ev, onClick, showFactor }) {
  const m = impactMeta(ev.impact);
  return (
    <a href={'#/app/event/' + ev.id} data-track="event_open" data-track-id={ev.id}
      onClick={onClick}
      style={{ display: 'flex', gap: 12, padding: '14px', textDecoration: 'none', borderBottom: '1px solid ' + T.line, alignItems: 'flex-start', cursor: 'pointer' }}
      onMouseEnter={e => e.currentTarget.style.background = T.cardHi}
      onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
      <div style={{ width: 8, height: 8, borderRadius: 4, background: m.c, boxShadow: '0 0 8px ' + m.c, marginTop: 6, flexShrink: 0 }} />
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 4, flexWrap: 'wrap' }}>
          <KindTag kind={ev.kind} impact={ev.impact} />
          <span style={{ fontSize: 10, color: T.fgMuted, fontFamily: T.mono }}>{ev.region}</span>
          {ev.hot && <span style={{ fontSize: 9, color: T.hot, fontFamily: T.mono, fontWeight: 700 }}>● HOT</span>}
          <span style={{ marginLeft: 'auto', fontSize: 10, color: T.fgFaint, fontFamily: T.mono }}>{ev.date}</span>
        </div>
        <div style={{ fontSize: 14, fontWeight: 600, color: T.fg, lineHeight: 1.4 }}>{ev.title}</div>
        <div style={{ fontSize: 12, color: T.fgDim, marginTop: 4, lineHeight: 1.5 }}>{ev.summary}</div>
        {showFactor && FACTOR_INFO[ev.factor] && (
          <div style={{ marginTop: 6, fontSize: 11, color: T.ai, fontFamily: T.mono }}>관련 지표 · {FACTOR_INFO[ev.factor].title} →</div>
        )}
      </div>
      <span style={{ color: T.fgMuted, fontSize: 16, flexShrink: 0, alignSelf: 'center' }}>›</span>
    </a>
  );
}

// ─── 네이버 뉴스 라이브 훅 (백엔드 /v1/news 경유) ─────────
// 백엔드(네이버 검색 API)가 살아있으면 실거래가 관련 뉴스를 받아 호재/악재 자동 분류.
// 미연결 시 items=null → 큐레이션 이벤트로 폴백.
function useLiveMarketNews() {
  const [state, setState] = useState({ loading: true, items: null });
  useEffect(() => {
    let alive = true;
    // 같은 도메인 Pages Functions → 상대경로가 가장 확실 (호스트 감지 불필요)
    const bases = ['', window.UJTrack.API_BASE].filter((v, i, a) => a.indexOf(v) === i);
    const tryLoad = async () => {
      for (const b of bases) {
        try {
          const r = await fetch(b + '/v1/news?query=' + encodeURIComponent('부동산 아파트 실거래가'), { cache: 'no-store' });
          if (!r.ok) continue;
          const d = await r.json();
          const raw = (d.items || []).slice().sort((a, b) => new Date(b.pubDate || 0) - new Date(a.pubDate || 0));
          if (raw.length) {
            const mapped = raw.slice(0, 10).map((n, i) => {
              const cls = classifyNews((n.title || '') + ' ' + (n.description || ''));
              return { id: 'news_' + i, live: true, title: stripTags(n.title), summary: stripTags(n.description), link: n.link, pub: n.pubDate, kind: cls.kind, impact: cls.impact };
            });
            if (alive) setState({ loading: false, items: mapped });
            return;
          }
        } catch (e) { /* 다음 후보 시도 */ }
      }
      if (alive) setState({ loading: false, items: null });
    };
    tryLoad();
    const onBase = () => tryLoad();
    window.addEventListener('urijib:apibase', onBase);
    const id = setInterval(tryLoad, 120000);
    return () => { alive = false; window.removeEventListener('urijib:apibase', onBase); clearInterval(id); };
  }, []);
  return state;
}

function naverAgo(pub) {
  try { const m = Math.floor((Date.now() - new Date(pub).getTime()) / 60000); return m < 60 ? m + '분 전' : m < 1440 ? Math.floor(m / 60) + '시간 전' : Math.floor(m / 1440) + '일 전'; } catch (e) { return ''; }
}

// ─── 대시보드: 실시간 호재·악재 피드 ─────────────────────
function MarketFeed({ isMobile }) {
  const news = useLiveMarketNews();
  const liveMode = !!(news.items && news.items.length);
  // "살아있는" 느낌: 각 이벤트에 수신시각 부여, 주기적으로 한 건을 맨 위로 갱신
  const base = MARKET_EVENTS;
  const [order, setOrder] = useState(() => base.map((_, i) => i));
  const [recv, setRecv] = useState(() => {
    const now = Date.now();
    return base.map((_, i) => now - (i * 7 + 2) * 60000 - Math.floor(Math.random() * 60000));
  });
  const [, force] = useState(0);

  useEffect(() => {
    // 1초마다 "N분 전" 갱신
    const t1 = setInterval(() => force(x => x + 1), 1000);
    // 11초마다 무작위 이벤트 1건을 "방금" 수신 → 맨 위로 (실시간 피드 느낌)
    const t2 = setInterval(() => {
      setOrder(prev => {
        const pool = prev.slice();
        const pick = pool[Math.floor(Math.random() * Math.min(pool.length, 6)) + Math.floor(pool.length / 2)] ?? pool[pool.length - 1];
        const idx = pool.indexOf(pick);
        if (idx > 0) { pool.splice(idx, 1); pool.unshift(pick); }
        setRecv(r => { const c = r.slice(); c[pick] = Date.now(); return c; });
        return pool;
      });
    }, 11000);
    return () => { clearInterval(t1); clearInterval(t2); };
  }, []);

  const ago = (ts) => {
    const s = Math.floor((Date.now() - ts) / 1000);
    if (s < 60) return '방금 전';
    const mm = Math.floor(s / 60);
    if (mm < 60) return mm + '분 전';
    const hh = Math.floor(mm / 60);
    if (hh < 24) return hh + '시간 전';
    return Math.floor(hh / 24) + '일 전';
  };

  const items = order.map(i => ({ ev: base[i], ts: recv[i], idx: i }));
  const pos = base.filter(e => e.impact === 'positive').length;
  const neg = base.filter(e => e.impact === 'negative').length;

  const liveCounts = liveMode ? {
    pos: news.items.filter(n => n.impact === 'positive').length,
    neg: news.items.filter(n => n.impact === 'negative').length,
  } : null;

  return (
    <Panel title="실시간 호재·악재" subtitle={liveMode ? '네이버 뉴스 · 자동 분류' : '시장 이슈 트래커'} action={
      <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
        <span className="uj-blink" style={{ width: 7, height: 7, borderRadius: 4, background: T.up, boxShadow: '0 0 8px ' + T.up }} />
        <span style={{ fontSize: 10, fontFamily: T.mono, color: T.up }}>{liveMode ? 'LIVE 뉴스' : 'LIVE'}</span>
      </div>
    }>
      <div style={{ display: 'flex', gap: 12, marginBottom: 10, fontSize: 10, fontFamily: T.mono, alignItems: 'center' }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: T.up }}><span style={{ width: 6, height: 6, borderRadius: 3, background: T.up }} />호재 {liveMode ? liveCounts.pos : pos}</span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 4, color: T.down }}><span style={{ width: 6, height: 6, borderRadius: 3, background: T.down }} />악재 {liveMode ? liveCounts.neg : neg}</span>
        <span style={{ color: T.fgMuted, marginLeft: 'auto' }}>{liveMode ? '네이버 실시간' : '전체 ' + base.length + '건'} · 클릭 시 상세</span>
      </div>

      {liveMode ? (
        <div className="uj-scroll" style={{ maxHeight: isMobile ? 360 : 460, overflowY: 'auto', display: 'flex', flexDirection: 'column' }}>
          {news.items.map((n) => {
            const m = impactMeta(n.impact);
            return (
              <a key={n.id} href={n.link} target="_blank" rel="noopener noreferrer" data-track="feed_news" data-track-impact={n.impact}
                style={{ display: 'flex', gap: 10, padding: '9px 4px', textDecoration: 'none', borderBottom: '1px solid ' + T.line, alignItems: 'flex-start' }}
                onMouseEnter={e => e.currentTarget.style.background = T.cardHi}
                onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
                <span style={{ width: 7, height: 7, borderRadius: 4, background: m.c, boxShadow: '0 0 7px ' + m.c, marginTop: 5, flexShrink: 0 }} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 2 }}>
                    <KindTag kind={n.kind} impact={n.impact} />
                    <span style={{ marginLeft: 'auto', fontSize: 9, color: T.fgFaint, fontFamily: T.mono, whiteSpace: 'nowrap' }}>{naverAgo(n.pub)}</span>
                  </div>
                  <div style={{ fontSize: 13, fontWeight: 600, color: T.fg, lineHeight: 1.35 }}>{n.title}</div>
                </div>
                <Ico name="ext" size={12} color={T.fgMuted} style={{ marginTop: 5 }} />
              </a>
            );
          })}
        </div>
      ) : (
        <div className="uj-scroll" style={{ maxHeight: isMobile ? 360 : 460, overflowY: 'auto', display: 'flex', flexDirection: 'column' }}>
          {items.map(({ ev, ts }) => {
            const m = impactMeta(ev.impact);
            const fresh = Date.now() - ts < 4000;
            return (
              <a key={ev.id} href={'#/app/event/' + ev.id} data-track="feed_event" data-track-id={ev.id}
                style={{ display: 'flex', gap: 10, padding: '9px 4px', textDecoration: 'none', borderBottom: '1px solid ' + T.line, alignItems: 'flex-start', background: fresh ? m.bg : 'transparent', transition: 'background .4s' }}
                onMouseEnter={e => e.currentTarget.style.background = T.cardHi}
                onMouseLeave={e => e.currentTarget.style.background = fresh ? m.bg : 'transparent'}>
                <span style={{ width: 7, height: 7, borderRadius: 4, background: m.c, boxShadow: '0 0 7px ' + m.c, marginTop: 5, flexShrink: 0 }} />
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 2 }}>
                    <KindTag kind={ev.kind} impact={ev.impact} />
                    <span style={{ fontSize: 9, color: T.fgMuted, fontFamily: T.mono, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{ev.region}</span>
                    <span style={{ marginLeft: 'auto', fontSize: 9, color: fresh ? m.c : T.fgFaint, fontFamily: T.mono, whiteSpace: 'nowrap', fontWeight: fresh ? 700 : 400 }}>{ago(ts)}</span>
                  </div>
                  <div style={{ fontSize: 13, fontWeight: 600, color: T.fg, lineHeight: 1.35 }}>{ev.title}</div>
                </div>
              </a>
            );
          })}
        </div>
      )}

      <a href="#/app/events" data-track="view_all_events" style={{ display: 'flex', justifyContent: 'flex-end', alignItems: 'center', gap: 4, marginTop: 8, fontSize: 11, color: T.hot, textDecoration: 'none' }}>
        전체 호재·악재 보기 <Ico name="arrow" size={11} color={T.hot} />
      </a>
    </Panel>
  );
}

// ─── 지역 통계 패널 (통계누리: 미분양·공급·개발·교통) ─────
// /v1/molit/stats 호출 → 미분양 위험·공급 변동률·도시개발·교통 호재
function RegionStatsPanel({ isMobile }) {
  const [st, setSt] = React.useState({ loading: true, data: null });
  React.useEffect(() => {
    let alive = true;
    // 관심지역 1순위 → lawd 코드 (없으면 강남)
    let lawd = '11680', region = '강남구';
    try {
      const prof = JSON.parse(localStorage.getItem('uj.profile') || localStorage.getItem('urijib_onboard') || '{}');
      const regions = prof.regions || [];
      if (regions[0] && window.LAWD_FROM_NAME) { const m = window.LAWD_FROM_NAME(regions[0]); if (m) { lawd = m.lawd; region = m.name; } }
    } catch (e) {}
    fetch('/v1/molit/stats?lawd_code=' + lawd + '&region=' + encodeURIComponent(region), { cache: 'no-store' })
      .then(r => r.json()).then(d => { if (alive) setSt({ loading: false, data: d }); })
      .catch(() => { if (alive) setSt({ loading: false, data: null }); });
    return () => { alive = false; };
  }, []);

  const d = st.data;
  const cMap = { up: T.up, down: T.down, info: T.info };
  return (
    <Panel title="지역 통계·개발 현황" subtitle={d ? (d.region || '관심지역') + (d.source === 'fallback' ? ' · 공시 기반' : ' · 통계누리') : '국토부 통계누리'}>
      {st.loading ? (
        <div style={{ padding: 16, textAlign: 'center', color: T.fgMuted, fontSize: 12 }}><span className="uj-blink">통계 불러오는 중…</span></div>
      ) : !d ? (
        <div style={{ padding: 16, textAlign: 'center', color: T.fgMuted, fontSize: 12 }}>통계를 불러오지 못했습니다.</div>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {/* 미분양 + 공급 */}
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
            <div style={{ background: T.cardLo, borderRadius: 6, padding: 10, border: '1px solid ' + T.line }}>
              <div style={{ fontSize: 9, fontFamily: T.mono, color: T.fgMuted, letterSpacing: 1, marginBottom: 4 }}>미분양 위험</div>
              <div className="uj-num" style={{ fontSize: 18, fontWeight: 700 }}>{d.unsold.count.toLocaleString()}<span style={{ fontSize: 11, color: T.fgMuted }}>호</span></div>
              <span style={{ fontSize: 10, fontFamily: T.mono, color: cMap[d.unsold.color] || T.fgDim, fontWeight: 700 }}>{d.unsold.grade}</span>
            </div>
            <div style={{ background: T.cardLo, borderRadius: 6, padding: 10, border: '1px solid ' + T.line }}>
              <div style={{ fontSize: 9, fontFamily: T.mono, color: T.fgMuted, letterSpacing: 1, marginBottom: 4 }}>공급 변동률</div>
              <div className="uj-num" style={{ fontSize: 18, fontWeight: 700, color: d.supply.delta > 0 ? T.down : T.up }}>{d.supply.delta > 0 ? '+' : ''}{d.supply.delta}%</div>
              <span style={{ fontSize: 10, color: T.fgMuted }}>{d.supply.label}</span>
            </div>
          </div>
          {/* 도시개발 */}
          <div>
            <div style={{ fontSize: 10, fontFamily: T.mono, color: T.fgMuted, letterSpacing: 1, marginBottom: 6 }}>진행 도시개발</div>
            {d.developments.map(dev => (
              <div key={dev.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 0', fontSize: 12, color: T.fgDim }}>
                <span style={{ width: 5, height: 5, borderRadius: 3, background: T.ai, flexShrink: 0 }} />{dev.name}
                <span style={{ marginLeft: 'auto', fontSize: 9, fontFamily: T.mono, color: T.ai }}>{dev.status}</span>
              </div>
            ))}
          </div>
          {/* 교통 호재 타임라인 */}
          <div>
            <div style={{ fontSize: 10, fontFamily: T.mono, color: T.fgMuted, letterSpacing: 1, marginBottom: 6 }}>교통 호재 타임라인</div>
            {d.transit.map(tr => (
              <div key={tr.id} style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '5px 0', fontSize: 12, color: T.fgDim }}>
                <span style={{ width: 5, height: 5, borderRadius: 3, background: T.hot, flexShrink: 0 }} />{tr.name}
                <span style={{ marginLeft: 'auto', fontSize: 9, fontFamily: T.mono, color: T.hot }}>{tr.when}</span>
              </div>
            ))}
          </div>
        </div>
      )}
    </Panel>
  );
}

// ─── 호재·악재 전체 페이지 ─────────────────────────────
function MarketEventsPage() {
  const isMobile = useIsMobile();
  const [filter, setFilter] = useState('all');
  useEffect(() => { document.title = '호재·악재 — 우리집사기'; window.UJTrack.track('view_events', {}); }, []);

  const filters = [['all', '전체'], ['positive', '호재'], ['negative', '악재'], ['neutral', '정책·중립']];
  const list = latestEvents().filter(e => filter === 'all' ? true : e.impact === filter);
  const pos = MARKET_EVENTS.filter(e => e.impact === 'positive').length;
  const neg = MARKET_EVENTS.filter(e => e.impact === 'negative').length;

  return (
    <div style={{ padding: isMobile ? 12 : 20, maxWidth: 920, margin: '0 auto' }}>
      <PageHead title="실시간 호재·악재" sub="부동산 시장을 움직이는 이슈 · 클릭 시 상세 분석" />

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 12, marginBottom: 16 }}>
        <Panel pad={14}><KPI label="전체 이슈" value={MARKET_EVENTS.length} big sub="추적 중" /></Panel>
        <Panel pad={14}><KPI label="호재" value={pos} big sub="상방 요인" /></Panel>
        <Panel pad={14}><KPI label="악재" value={neg} big sub="하방 요인" /></Panel>
      </div>

      <div style={{ display: 'flex', gap: 6, marginBottom: 14, flexWrap: 'wrap' }}>
        {filters.map(([id, label]) => (
          <button key={id} onClick={() => { setFilter(id); window.UJTrack.track('events_filter', { filter: id }); }}
            style={{ padding: '7px 14px', borderRadius: 999, background: filter === id ? T.hot : T.card, color: filter === id ? T.bg : T.fgDim, border: '1px solid ' + (filter === id ? T.hot : T.line), fontSize: 12, fontWeight: 600, cursor: 'pointer', fontFamily: T.font }}>{label}</button>
        ))}
      </div>

      <Panel noPad>
        {list.map(ev => <EventRow key={ev.id} ev={ev} showFactor />)}
        {list.length === 0 && <div style={{ padding: 32, textAlign: 'center', color: T.fgMuted, fontSize: 13 }}>해당 조건의 이슈가 없습니다.</div>}
      </Panel>

      <div style={{ fontSize: 10, color: T.fgFaint, fontFamily: T.mono, lineHeight: 1.7, padding: '12px 4px 24px' }}>
        ※ 호재·악재는 공개 보도·공시자료 기반 시장 이슈 요약입니다. RTMS 백엔드 연결 시 실시간 뉴스·공시로 자동 보강됩니다. 투자 자문이 아닙니다.
      </div>
    </div>
  );
}

// ─── 호재·악재 상세 페이지 ─────────────────────────────
function EventDetailPage({ id }) {
  const ev = getEvent(id);
  const isMobile = useIsMobile();
  useEffect(() => {
    document.title = (ev ? ev.title : '이슈') + ' — 우리집사기';
    window.UJTrack.track('view_event_detail', { event_id: id });
  }, [id]);

  if (!ev) {
    return (
      <div style={{ padding: 20 }}>
        <PageHead title="이슈를 찾을 수 없습니다" sub="삭제되었거나 잘못된 주소입니다." />
        <a href="#/app/events" style={{ color: T.hot, textDecoration: 'none', fontSize: 13 }}>← 호재·악재 전체 보기</a>
      </div>
    );
  }

  const m = impactMeta(ev.impact);
  const fi = FACTOR_INFO[ev.factor];
  const affected = (ev.affected || []).map(aid => APTS.find(a => a.id === aid)).filter(Boolean);

  return (
    <div style={{ padding: isMobile ? 12 : 20, maxWidth: 900, margin: '0 auto' }}>
      <a href="#/app/events" data-track="event_back" style={{ color: T.fgDim, textDecoration: 'none', fontSize: 13 }}>← 호재·악재</a>

      <div style={{ margin: '14px 0 16px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10, flexWrap: 'wrap' }}>
          <KindTag kind={ev.kind} impact={ev.impact} />
          <span style={{ fontSize: 12, color: T.fgMuted, fontFamily: T.mono }}>{ev.region} · {ev.area}</span>
          <span style={{ fontSize: 12, color: T.fgFaint, fontFamily: T.mono }}>· {ev.date}</span>
          {ev.hot && <span style={{ fontSize: 10, color: T.hot, fontFamily: T.mono, fontWeight: 700 }}>● HOT</span>}
        </div>
        <h1 style={{ fontSize: isMobile ? 22 : 28, fontWeight: 700, margin: 0, lineHeight: 1.3, color: T.fg }}>{ev.title}</h1>
        <div style={{ fontSize: 14, color: T.fgDim, marginTop: 8, lineHeight: 1.6 }}>{ev.summary}</div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1fr 300px', gap: 16 }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16, minWidth: 0 }}>
          <Panel title="핵심 포인트">
            <ul style={{ margin: 0, padding: 0, listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 10 }}>
              {ev.points.map((p, i) => (
                <li key={i} style={{ display: 'flex', gap: 10, fontSize: 13, color: T.fgDim, lineHeight: 1.5 }}>
                  <span style={{ color: m.c, fontWeight: 700, flexShrink: 0 }}>{m.arrow}</span>{p}
                </li>
              ))}
            </ul>
          </Panel>

          <Panel title="상세 분석">
            <p style={{ margin: 0, fontSize: 13.5, color: T.fg, lineHeight: 1.8 }}>{ev.detail}</p>
          </Panel>

          {affected.length > 0 && (
            <Panel title="영향 단지" subtitle={affected.length + '개 · 클릭 시 분석'} noPad>
              {affected.map(a => (
                <a key={a.id} href={'#/app/detail/' + a.id} data-track="event_apt_click" data-track-id={a.id}
                  style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 14px', textDecoration: 'none', borderBottom: '1px solid ' + T.line }}
                  onMouseEnter={e => e.currentTarget.style.background = T.cardHi}
                  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
                  <ScoreRing score={a.score} size={40} stroke={4} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 13, fontWeight: 600, color: T.fg }}>{a.name}</div>
                    <div style={{ fontSize: 11, color: T.fgMuted }}>{a.region} · {a.dong}</div>
                  </div>
                  <div style={{ textAlign: 'right' }}>
                    <div className="uj-num" style={{ fontSize: 14, fontWeight: 700 }}>{won(a.currentPrice)}</div>
                    <Delta value={a.delta1y} size={11} />
                  </div>
                  <SignalBadge kind={a.signal} size="sm" />
                </a>
              ))}
            </Panel>
          )}
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <Panel title="시장 영향">
            <div style={{ textAlign: 'center', padding: '8px 0 12px' }}>
              <div style={{ fontSize: 11, fontFamily: T.mono, color: T.fgMuted, letterSpacing: 1 }}>영향 방향</div>
              <div style={{ fontSize: 26, fontWeight: 700, color: m.c, margin: '6px 0' }}>{m.arrow} {m.word}</div>
            </div>
            <div style={{ borderTop: '1px solid ' + T.line, paddingTop: 12 }}>
              <div style={{ fontSize: 11, color: T.fgMuted, fontFamily: T.mono, marginBottom: 8 }}>영향 강도</div>
              <MagBar mag={ev.mag} impact={ev.impact} />
              <div style={{ fontSize: 11, color: T.fgDim, marginTop: 6 }}>{['', '제한적', '약함', '보통', '강함', '매우 강함'][ev.mag]}</div>
            </div>
          </Panel>

          {fi && (
            <Panel title="관련 지표">
              <a href={'#/app/factor/' + ev.factor} data-track="event_to_factor" data-track-factor={ev.factor}
                style={{ display: 'flex', alignItems: 'center', gap: 10, textDecoration: 'none', padding: 4 }}>
                <span style={{ color: T.hot }}><FactorIcon id={ev.factor} size={22} /></span>
                <div style={{ flex: 1 }}>
                  <div style={{ fontSize: 13, fontWeight: 600, color: T.fg }}>{fi.title}</div>
                  <div style={{ fontSize: 11, color: T.fgMuted }}>{fi.now}</div>
                </div>
                <span style={{ color: T.hot }}>→</span>
              </a>
            </Panel>
          )}

          <Panel title="출처">
            <a href={ev.source.url} target="_blank" rel="noopener noreferrer" data-track="event_source"
              style={{ display: 'flex', alignItems: 'center', gap: 8, textDecoration: 'none', fontSize: 12, color: T.info }}>
              {ev.source.label} ↗
            </a>
          </Panel>
        </div>
      </div>
    </div>
  );
}

// ─── 지표 상세 페이지 (12개 요인) ──────────────────────
function FactorDetailPage({ id }) {
  const isMobile = useIsMobile();
  const fi = FACTOR_INFO[id];
  const fr = (window.FACTORS || []).find(f => f.id === id);
  useEffect(() => {
    document.title = (fi ? fi.title : '지표') + ' — 우리집사기';
    window.UJTrack.track('view_factor_detail', { factor_id: id });
  }, [id]);

  if (!fi) {
    return (
      <div style={{ padding: 20 }}>
        <PageHead title="지표를 찾을 수 없습니다" sub="잘못된 주소입니다." />
        <a href="#/app/references" style={{ color: T.hot, textDecoration: 'none', fontSize: 13 }}>← 모델 근거 보기</a>
      </div>
    );
  }

  const ns = impactMeta(fi.nowState);
  const weight = fr ? fr.value : null;
  const events = eventsForFactor(id);
  const idx = (window.FACTORS || []).findIndex(f => f.id === id);
  const prev = idx > 0 ? window.FACTORS[idx - 1] : null;
  const next = idx >= 0 && idx < (window.FACTORS || []).length - 1 ? window.FACTORS[idx + 1] : null;

  return (
    <div style={{ padding: isMobile ? 12 : 20, maxWidth: 920, margin: '0 auto' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 4, flexWrap: 'wrap' }}>
        <a href="#/app/dashboard" data-track="factor_back" style={{ color: T.fgDim, textDecoration: 'none', fontSize: 13 }}>← 대시보드</a>
        <span style={{ color: T.fgFaint }}>·</span>
        <a href="#/app/references" style={{ color: T.fgDim, textDecoration: 'none', fontSize: 13 }}>모델 근거 전체</a>
      </div>

      <div style={{ display: 'flex', alignItems: 'center', gap: 14, margin: '14px 0 18px' }}>
        <div style={{ width: 52, height: 52, borderRadius: 10, background: ns.bg, border: '1px solid ' + ns.c + '50', display: 'flex', alignItems: 'center', justifyContent: 'center', color: ns.c, flexShrink: 0 }}>
          <FactorIcon id={id} size={26} />
        </div>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
            <h1 style={{ fontSize: isMobile ? 21 : 26, fontWeight: 700, margin: 0, color: T.fg }}>{fi.title}</h1>
            {weight != null && <span style={{ padding: '3px 9px', borderRadius: 4, background: T.hotBg, color: T.hot, fontFamily: T.mono, fontSize: 12, fontWeight: 700 }}>가중치 {weight}%</span>}
          </div>
          <div style={{ fontSize: 13, color: T.fgDim, marginTop: 5, lineHeight: 1.5 }}>{fi.one}</div>
        </div>
      </div>

      {/* 현재 수치 + 추이 */}
      <Panel title="현재 수치" subtitle="모델 반영값" style={{ marginBottom: 16 }} action={
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontFamily: T.mono, fontSize: 11, color: ns.c }}>
          {ns.arrow} {ns.word}
        </span>
      }>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 10, marginBottom: 14, flexWrap: 'wrap' }}>
          <span style={{ fontSize: isMobile ? 18 : 22, fontWeight: 700, color: T.fg, lineHeight: 1.3 }}>{fi.now}</span>
        </div>
        <TrendChart data={fi.trend} color={ns.c} />
        <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 10, color: T.fgFaint, fontFamily: T.mono, marginTop: 4 }}>
          <span>최근 12개월 추이</span><span>단위: {fi.unit}</span>
        </div>
      </Panel>

      {/* 무엇을 / 왜 / 어떻게 */}
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(3, 1fr)', gap: 12, marginBottom: 16 }}>
        {[['무엇을 보나', fi.what, T.info], ['왜 중요한가', fi.why, T.hot], ['모델에서 어떻게 쓰나', fi.how, T.ai]].map(([k, v, c]) => (
          <Panel key={k} pad={14}>
            <div style={{ fontSize: 11, fontFamily: T.mono, color: c, letterSpacing: 1, marginBottom: 8 }}>{k}</div>
            <div style={{ fontSize: 13, color: T.fg, lineHeight: 1.65 }}>{v}</div>
          </Panel>
        ))}
      </div>

      {/* 지역별 현황 */}
      <Panel title="지역·항목별 현황" style={{ marginBottom: 16 }} noPad>
        <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 13 }}>
          <tbody>
            {fi.regions.map((r, i) => (
              <tr key={i} style={{ borderBottom: i < fi.regions.length - 1 ? '1px solid ' + T.line : 'none' }}>
                <td style={{ padding: '12px 16px', color: T.fgDim, width: '40%' }}>{r[0]}</td>
                <td style={{ padding: '12px 8px', fontFamily: T.mono, fontWeight: 700, color: T.fg }}>{r[1]}</td>
                <td style={{ padding: '12px 16px', textAlign: 'right' }}>
                  <span style={{ fontSize: 11, color: T.fgMuted }}>{r[2]}</span>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </Panel>

      {/* 관련 호재·악재 */}
      {events.length > 0 && (
        <Panel title="관련 호재·악재" subtitle={events.length + '건'} style={{ marginBottom: 16 }} noPad>
          {events.map(ev => <EventRow key={ev.id} ev={ev} />)}
        </Panel>
      )}

      {/* 근거 자료 */}
      <Panel title="근거 자료" style={{ marginBottom: 16 }}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {fi.sources.map(([label, url], i) => (
            <a key={i} href={url} target="_blank" rel="noopener noreferrer" data-track="factor_source"
              style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '10px 12px', background: T.card, border: '1px solid ' + T.line, borderRadius: 6, textDecoration: 'none', fontSize: 12, color: T.fgDim }}>
              <span style={{ color: T.info }}>↗</span>{label}
            </a>
          ))}
        </div>
      </Panel>

      {/* 이전/다음 지표 */}
      <div style={{ display: 'flex', gap: 10, marginBottom: 24 }}>
        {prev && <a href={'#/app/factor/' + prev.id} style={{ flex: 1, padding: 12, background: T.card, border: '1px solid ' + T.line, borderRadius: 6, textDecoration: 'none' }}>
          <div style={{ fontSize: 10, color: T.fgMuted, fontFamily: T.mono }}>← 이전 지표</div>
          <div style={{ fontSize: 13, color: T.fg, fontWeight: 600, marginTop: 3 }}>{prev.label}</div>
        </a>}
        {next && <a href={'#/app/factor/' + next.id} style={{ flex: 1, padding: 12, background: T.card, border: '1px solid ' + T.line, borderRadius: 6, textDecoration: 'none', textAlign: 'right' }}>
          <div style={{ fontSize: 10, color: T.fgMuted, fontFamily: T.mono }}>다음 지표 →</div>
          <div style={{ fontSize: 13, color: T.fg, fontWeight: 600, marginTop: 3 }}>{next.label}</div>
        </a>}
      </div>
    </div>
  );
}

Object.assign(window, { MarketFeed, MarketEventsPage, EventDetailPage, FactorDetailPage, KindTag, impactMeta, FactorIcon });
