// search-live.jsx — 전국 실시간 단지 검색 (국토부 RTMS 직접 연동)
// 시도 → 시군구 선택 → 실거래 전체 조회 → 읍면동/단지 그룹 → 클릭 시 AI 상세

function manWon(man) {
  if (!man) return '-';
  if (man >= 10000) { const e = Math.floor(man / 10000), r = man % 10000; return r ? `${e}억 ${r.toLocaleString()}` : `${e}억`; }
  return man.toLocaleString() + '만';
}
function recentYmds(n) {
  const out = [];
  const d = new Date();
  for (let i = 1; i <= n; i++) { const x = new Date(d); x.setMonth(x.getMonth() - i); out.push(x.getFullYear() + ('' + (x.getMonth() + 1)).padStart(2, '0')); }
  return out;
}

// 시군구 실거래 전체 조회 훅
function useSigunguTrades() {
  const [state, setState] = useState({ loading: false, trades: [], error: null, sido: '', sigungu: '', lawd: '' });

  const load = useCallback(async (sido, sigungu, lawd) => {
    const API = window.UJTrack.API_BASE;
    window.UJTrack.track('search_region', { sido, sigungu, lawd });
    if (!API) {
      // 백엔드 미연결 → 데모 실거래 이력
      const all = window.mockRegionTrades ? window.mockRegionTrades(sido + ' ' + sigungu) : [];
      setState({ loading: false, trades: all, error: all.length ? null : 'no_data', sido, sigungu, lawd });
      return;
    }
    setState({ loading: true, trades: [], error: null, sido, sigungu, lawd });
    const months = recentYmds(3);
    const all = [];
    for (const ymd of months) {
      try {
        const r = await fetch(`${API}/v1/molit/recent?lawd_code=${lawd}&deal_ymd=${ymd}`);
        if (!r.ok) continue;
        const d = await r.json();
        (d.items || []).forEach(it => { if (it.price > 0) all.push({ ...it, ymd }); });
      } catch (e) { /* skip */ }
    }
    // 최신순 정렬 (년월일)
    all.sort((a, b) => {
      const ka = +(a.ymd + ('' + (a.day || 0)).padStart(2, '0'));
      const kb = +(b.ymd + ('' + (b.day || 0)).padStart(2, '0'));
      return kb - ka;
    });
    // 실데이터가 없으면(키 미설정/무거래) 데모 실거래로 폴백 — 화면이 항상 채워지도록
    if (!all.length && window.mockRegionTrades) {
      const demo = window.mockRegionTrades(sido + ' ' + sigungu);
      setState({ loading: false, trades: demo, error: demo.length ? null : 'no_data', sido, sigungu, lawd });
      window.UJTrack.track('search_region_result', { sido, sigungu, count: demo.length, demo: true });
      return;
    }
    setState({ loading: false, trades: all, error: all.length ? null : 'no_data', sido, sigungu, lawd });
    window.UJTrack.track('search_region_result', { sido, sigungu, count: all.length });
  }, []);

  return { ...state, load };
}

// 오늘(TODAY) 기준 유틸 — 모든 기준일은 호출 시점의 today 로 산출
function todayInfo() {
  const d = new Date();
  return {
    date: d,
    iso: d.toISOString().slice(0, 10),
    label: `${d.getFullYear()}.${('' + (d.getMonth() + 1)).padStart(2, '0')}.${('' + d.getDate()).padStart(2, '0')}`,
    ym: `${d.getFullYear()}-${('' + (d.getMonth() + 1)).padStart(2, '0')}`,
  };
}
// 매수적기 윈도우 → 종료 시각(ms). custom('YYYY-MM')은 해당 월 말일.
function buyWindowEndTs(win) {
  if (!win || win === 'all') return Infinity;
  const now = new Date();
  if (win === '1m' || win === '3m' || win === '6m' || win === '12m') {
    const n = parseInt(win, 10);
    const e = new Date(now.getFullYear(), now.getMonth() + n + 1, 0, 23, 59, 59); // +n개월 말일
    return e.getTime();
  }
  const m = /^(\d{4})-(\d{2})$/.exec(win);
  if (m) return new Date(+m[1], +m[2], 0, 23, 59, 59).getTime(); // 선택 월 말일
  return Infinity;
}
const BUY_WINDOWS = [
  ['all', '전체'],
  ['1m', '이번 달'],
  ['3m', '3개월 내'],
  ['6m', '6개월 내'],
  ['12m', '연내'],
];

// URL ?signal= → 선택 의견 배열(다중) 초기값
function readOpinionParam() {
  try {
    const p = new URLSearchParams(location.hash.split('?')[1] || '').get('signal');
    if (!p) return [];
    return decodeURIComponent(p).split(',').map(s => window.codeFromLabel(s.trim())).filter(Boolean);
  } catch (e) { return []; }
}

function SearchLivePage() {
  const isMobile = useIsMobile();
  const [sido, setSido] = useState('서울특별시');
  const [sigungu, setSigungu] = useState('강남구');
  const [lawd, setLawd] = useState('11680');
  const [q, setQ] = useState('');
  const [opinions, setOpinions] = useState(readOpinionParam);   // 다중 선택 (빈 배열 = 전체)
  const [buyWindow, setBuyWindow] = useState('all');            // 매수적기 윈도우
  const [customMonth, setCustomMonth] = useState('');          // 사용자 지정 월
  const [today, setToday] = useState(todayInfo);               // 오늘 기준일
  const [selected, setSelected] = useState(null);             // 클릭한 거래
  const feed = useSigunguTrades();

  useEffect(() => {
    document.title = '단지 검색 — 우리집사기';
    // 기준일 항상 최신화 + 페이지 진입 로그 (TODAY 로드)
    const t = todayInfo();
    setToday(t);
    window.UJLog.log(window.UJLog.EVENT_TYPES.PAGE_ENTER, { label: '단지 검색', today: t.iso, region: sido + ' ' + sigungu });
  }, []);
  useEffect(() => { feed.load(sido, sigungu, lawd); }, [lawd]);
  // URL ?signal= 변경 시 필터 동기화 (대시보드 KPI에서 진입)
  useEffect(() => {
    const onHash = () => { const o = readOpinionParam(); if (o.length) setOpinions(o); };
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);

  const sigunguList = LAWD_TREE[sido] || [];
  const regionLabel = sido + ' ' + sigungu;

  // 단지 집계 + AI 분석 1회 계산 (카운트·필터·카드 동일 소스)
  const allApts = useMemo(() => {
    const filtered = feed.trades.filter(t => {
      if (!q) return true;
      const s = (t.name + ' ' + (t.dong || '')).toLowerCase();
      return s.includes(q.toLowerCase());
    });
    const byKey = {};
    filtered.forEach(t => {
      const dong = t.dong || '기타';
      const key = dong + '|' + t.name;
      if (!byKey[key]) byKey[key] = { code: lawd + '-' + key, name: t.name, dong, trades: [], latest: 0, area: t.area, buildYear: t.buildYear };
      byKey[key].trades.push(t);
      if (t.price > byKey[key].latest) byKey[key].latest = t.price;
    });
    const list = Object.values(byKey);
    list.forEach(apt => {
      try { apt.ai = window.analyzeUnit({ name: apt.name, region: regionLabel, trades: apt.trades, area: apt.area, buildYear: apt.buildYear }); }
      catch (e) { apt.ai = null; }
    });
    return list;
  }, [feed.trades, q, regionLabel, lawd]);

  // 매수적기 윈도우로 1차 필터 (의견 카운트는 이 결과 기준 → 항상 의미 있음)
  const windowEndTs = buyWindowEndTs(buyWindow === 'custom' ? customMonth : buyWindow);
  const dateFiltered = useMemo(
    () => allApts.filter(a => !a.ai || a.ai.bestBuyTs <= windowEndTs),
    [allApts, windowEndTs]
  );

  // 의견별 건수 (다중선택 칩 배지)
  const opinionCounts = useMemo(() => {
    const c = { ALL: dateFiltered.length, BUY: 0, ACC: 0, WATCH: 0, HOLD: 0, AVOID: 0 };
    dateFiltered.forEach(a => { if (a.ai && c[a.ai.signal] != null) c[a.ai.signal]++; });
    return c;
  }, [dateFiltered]);

  // 의견 다중선택 적용 후 읍면동 그룹화
  const grouped = useMemo(() => {
    const byDong = {};
    dateFiltered.filter(a => opinions.length === 0 || (a.ai && opinions.includes(a.ai.signal)))
      .forEach(a => { (byDong[a.dong] = byDong[a.dong] || []).push(a); });
    return Object.entries(byDong).map(([dong, apts]) => ({
      dong, apts: apts.sort((a, b) => b.latest - a.latest),
    })).sort((a, b) => b.apts.length - a.apts.length);
  }, [dateFiltered, opinions]);

  const infra = window.aiInfraFor(regionLabel);
  const totalApts = grouped.reduce((s, g) => s + g.apts.length, 0);

  // ── 액션 핸들러 (전부 로그 적재) ──
  const LOG = window.UJLog;
  const doSearch = () => {
    feed.load(sido, sigungu, lawd);
    setToday(todayInfo());
    LOG.log(LOG.EVENT_TYPES.SEARCH, { query: q || '(전체)', region: regionLabel, lawd, filterValues: { opinions, buyWindow: buyWindow === 'custom' ? customMonth : buyWindow } });
  };
  const toggleOpinion = (code) => {
    setOpinions(prev => {
      const next = prev.includes(code) ? prev.filter(c => c !== code) : [...prev, code];
      LOG.log(LOG.EVENT_TYPES.FILTER_CHANGE, { filterType: 'AI_OPINION', filterValues: { opinions: next }, region: regionLabel });
      return next;
    });
  };
  const clearOpinions = () => { setOpinions([]); LOG.log(LOG.EVENT_TYPES.FILTER_CHANGE, { filterType: 'AI_OPINION', filterValues: { opinions: [] }, region: regionLabel }); };
  const setWindow = (win) => {
    setBuyWindow(win);
    if (win !== 'custom') setCustomMonth('');
    LOG.log(LOG.EVENT_TYPES.FILTER_CHANGE, { filterType: 'BUY_TIMING', filterValues: { buyWindow: win }, region: regionLabel });
  };
  const onCustomMonth = (v) => {
    setCustomMonth(v); setBuyWindow(v ? 'custom' : 'all');
    LOG.log(LOG.EVENT_TYPES.FILTER_CHANGE, { filterType: 'BUY_TIMING', filterValues: { buyWindow: v || 'all' }, region: regionLabel });
  };
  const openApt = (apt) => {
    LOG.log(LOG.EVENT_TYPES.CLICK, { target: 'apt_card', aptCode: apt.code, aptName: apt.name, region: regionLabel, opinion: apt.ai && apt.ai.signal });
    setSelected({ apt, region: regionLabel });
  };

  const activeOpinionLabel = opinions.length ? opinions.map(c => window.opinionLabel(c)).join('·') : null;

  return (
    <div style={{ padding: isMobile ? 12 : 20 }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
        <PageHead title="전국 단지 검색" sub={feed.loading ? '국토부 RTMS 조회 중…' : `${sido} ${sigungu} · ${feed.trades.length}건 실거래 · ${totalApts}개 단지${activeOpinionLabel ? ' · ' + activeOpinionLabel : ''}`} />
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6, padding: '6px 11px', background: T.card, border: '1px solid ' + T.line, borderRadius: 999, fontFamily: T.mono, fontSize: 11, color: T.fgDim, whiteSpace: 'nowrap', marginTop: 4 }}>
          <span style={{ width: 6, height: 6, borderRadius: 3, background: T.up }} className="uj-blink" />기준일 {today.label}
        </span>
      </div>

      <SearchLegend isMobile={isMobile} />

      {/* 지역 + 검색 */}
      <Panel style={{ marginBottom: 12 }}>
        <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'center' }}>
          <RegionSelect label="시·도" value={sido} options={Object.keys(LAWD_TREE)}
            onChange={(v) => { setSido(v); const first = LAWD_TREE[v][0]; setSigungu(first[0]); setLawd(first[1]); }} />
          <RegionSelect label="시·군·구" value={sigungu} options={sigunguList.map(s => s[0])}
            onChange={(v) => { const found = sigunguList.find(s => s[0] === v); setSigungu(v); setLawd(found[1]); }} />
          <input value={q} onChange={(e) => setQ(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') doSearch(); }} placeholder="단지명·읍면동 검색"
            style={{ flex: 1, minWidth: 180, padding: '9px 12px', borderRadius: 4, background: T.cardLo, color: T.fg, border: '1px solid ' + T.line, fontSize: 13, outline: 'none' }} />
          <button onClick={doSearch} disabled={feed.loading} data-track="search_submit"
            style={{ padding: '9px 18px', borderRadius: 4, background: T.hot, color: T.bg, border: 'none', fontSize: 13, fontWeight: 700, cursor: feed.loading ? 'default' : 'pointer' }}>
            {feed.loading ? '조회 중…' : <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}><Ico name="search" size={13} color={T.bg} />검색</span>}
          </button>
        </div>
        {/* AI 인프라 배지 */}
        <div style={{ marginTop: 12, display: 'flex', alignItems: 'center', gap: 10, padding: '10px 12px', background: 'rgba(139,92,246,0.08)', border: '1px solid ' + T.ai + '40', borderRadius: 6, flexWrap: 'wrap' }}>
          <div style={{ fontSize: 11, fontFamily: T.mono, color: T.ai, fontWeight: 700, letterSpacing: 1, whiteSpace: 'nowrap' }}>AI 인프라 {infra.score}</div>
          <div style={{ fontSize: 12, color: T.fgDim, flex: 1, minWidth: 140 }}>{infra.label}</div>
          <div style={{ display: 'flex', gap: 4, flexWrap: 'wrap' }}>
            {infra.tags.map(t => <span key={t} style={{ fontSize: 9, fontFamily: T.mono, color: T.ai, padding: '1px 6px', border: '1px solid ' + T.ai + '50', borderRadius: 2 }}>{t}</span>)}
          </div>
        </div>
      </Panel>

      {/* 필터: 매수적기 + AI 의견 다중선택 */}
      <Panel style={{ marginBottom: 16 }}>
        {/* 매수적기 날짜 필터 */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap', marginBottom: 14 }}>
          <span style={{ fontSize: 11, fontFamily: T.mono, color: T.fgMuted, letterSpacing: 1, whiteSpace: 'nowrap' }}>매수적기 (오늘 {today.label} 기준)</span>
          <div className="uj-xscroll" style={{ display: 'flex', gap: 6 }}>
            {BUY_WINDOWS.map(([win, label]) => {
              const active = (buyWindow === win) || (win === 'all' && buyWindow === 'custom' && !customMonth);
              return (
                <button key={win} onClick={() => setWindow(win)} data-track="buy_window" data-track-window={win}
                  style={{ padding: '6px 12px', borderRadius: 999, whiteSpace: 'nowrap', background: active ? T.info : T.card, color: active ? '#fff' : T.fgDim, border: '1px solid ' + (active ? T.info : T.line), fontSize: 12, fontWeight: 600, cursor: 'pointer', fontFamily: T.font }}>
                  {label}
                </button>
              );
            })}
          </div>
          <label style={{ display: 'inline-flex', alignItems: 'center', gap: 6, fontSize: 11, color: T.fgMuted, fontFamily: T.mono }}>
            직접 선택
            <input type="month" value={customMonth} min={today.ym} onChange={(e) => onCustomMonth(e.target.value)}
              style={{ padding: '6px 10px', borderRadius: 4, background: T.cardLo, color: T.fg, border: '1px solid ' + (buyWindow === 'custom' ? T.info : T.lineHi), fontSize: 12, fontFamily: T.mono, colorScheme: 'dark', cursor: 'pointer' }} />
          </label>
        </div>

        {/* AI 의견 다중선택 칩 */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8, flexWrap: 'wrap' }}>
          <span style={{ fontSize: 11, fontFamily: T.mono, color: T.fgMuted, letterSpacing: 1 }}>AI 의견 (다중 선택)</span>
          {opinions.length > 0 && (
            <button onClick={clearOpinions} style={{ fontSize: 10, fontFamily: T.mono, color: T.fgMuted, background: 'transparent', border: '1px solid ' + T.line, borderRadius: 999, padding: '2px 8px', cursor: 'pointer' }}>전체 해제 ({opinions.length})</button>
          )}
        </div>
        <div className="uj-xscroll" style={{ display: 'flex', gap: 6, paddingBottom: 2 }}>
          {window.AI_OPINION_LIST.map(op => {
            const active = opinions.includes(op.code);
            const cnt = opinionCounts[op.code] || 0;
            return (
              <button key={op.code} onClick={() => toggleOpinion(op.code)} data-track="opinion_chip" data-track-opinion={op.code} aria-pressed={active}
                style={{
                  display: 'inline-flex', alignItems: 'center', gap: 7, padding: '7px 13px', borderRadius: 999, whiteSpace: 'nowrap',
                  background: active ? op.color : op.bg, color: active ? '#0B1220' : op.color,
                  border: '1px solid ' + op.color + (active ? '' : '66'), fontSize: 12, fontWeight: 700, cursor: 'pointer', fontFamily: T.font,
                  boxShadow: active ? '0 0 0 1px ' + op.color : 'none',
                }}>
                <span style={{ width: 12, height: 12, borderRadius: 3, border: '1.5px solid ' + (active ? '#0B1220' : op.color), background: active ? '#0B1220' : 'transparent', display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
                  {active && <Ico name="check" size={9} color={op.color} />}
                </span>
                {op.label}
                <span style={{ fontFamily: T.mono, fontSize: 11, opacity: 0.85 }}>{cnt}</span>
              </button>
            );
          })}
        </div>
      </Panel>

      {/* 시도별 빠른 이동 */}
      <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginBottom: 16 }}>
        {Object.keys(LAWD_TREE).map(s => (
          <button key={s} onClick={() => { setSido(s); const f = LAWD_TREE[s][0]; setSigungu(f[0]); setLawd(f[1]); }}
            data-track="sido_chip" data-track-sido={s}
            style={{ padding: '5px 11px', borderRadius: 999, background: sido === s ? T.hot : T.card, color: sido === s ? T.bg : T.fgDim, border: '1px solid ' + (sido === s ? T.hot : T.line), fontSize: 11, fontWeight: 600, cursor: 'pointer' }}>
            {SIDO_SHORT[s]}
          </button>
        ))}
      </div>

      {/* 결과 */}
      {feed.error === 'no_backend' ? (
        <EmptyState title="백엔드 연결 필요" desc="전국 실시간 실거래가를 조회하려면 백엔드 + 국토부 RTMS 키 연결이 필요합니다." cta="연결 가이드" ctaHref="deploy/no-terminal-guide.html" />
      ) : feed.loading ? (
        <div style={{ padding: 48, textAlign: 'center', color: T.fgMuted, fontFamily: T.mono, fontSize: 13 }}>
          <span className="uj-blink">●</span> {sido} {sigungu} 국토부 실거래가 조회 중…
        </div>
      ) : feed.error === 'no_data' ? (
        <EmptyState title="최근 3개월 거래가 없습니다" desc="다른 지역을 선택하거나 검색해보세요." />
      ) : totalApts === 0 ? (
        <EmptyState title="조건에 맞는 단지가 없습니다" desc="AI 의견·매수적기 필터를 완화하거나 지역을 바꿔보세요." cta="필터 초기화" ctaHref={'#/app/search'} />
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>
          {grouped.map(group => (
            <div key={group.dong}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
                <h3 style={{ fontSize: 15, fontWeight: 700, margin: 0 }}>{group.dong}</h3>
                <span style={{ fontSize: 11, color: T.fgMuted, fontFamily: T.mono }}>{group.apts.length}개 단지</span>
                <div style={{ flex: 1, height: 1, background: T.line }} />
              </div>
              <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(auto-fill, minmax(320px, 1fr))', gap: 10 }}>
                {group.apts.map((apt, i) => (
                  <LiveAptCard key={apt.name + i} apt={apt} region={regionLabel} ai={apt.ai} onClick={() => openApt(apt)} />
                ))}
              </div>
            </div>
          ))}
        </div>
      )}

      {selected && <TradeDetailModal data={selected} isMobile={isMobile} onClose={() => setSelected(null)} />}
    </div>
  );
}

// 검색 페이지 용어 설명
function SearchLegend({ isMobile }) {
  const [open, setOpen] = useState(true);
  const sigs = window.AI_OPINION_LIST.map(op => [op.label, op.color, op.desc]);
  if (!open) {
    return <button onClick={() => setOpen(true)} style={{ marginBottom: 12, padding: '6px 12px', background: T.card, border: '1px solid ' + T.line, borderRadius: 4, color: T.fgDim, fontSize: 12, cursor: 'pointer', fontFamily: T.font }}>ⓘ 카드 용어 설명 보기</button>;
  }
  return (
    <div style={{ marginBottom: 16, background: T.card, border: '1px solid ' + T.lineHi, borderRadius: 6, padding: isMobile ? 12 : 16 }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 10 }}>
        <span style={{ fontSize: 12, fontFamily: T.mono, color: T.hot, letterSpacing: 1, fontWeight: 700 }}>ⓘ 카드 보는 법</span>
        <button onClick={() => setOpen(false)} style={{ background: 'transparent', border: 'none', color: T.fgMuted, cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 4, fontSize: 12 }}><Ico name="close" size={13} />닫기</button>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: isMobile ? '1fr' : 'repeat(2, 1fr)', gap: '8px 24px', marginBottom: 12 }}>
        <Term k="최근 실거래" v="국토부 RTMS에 신고된 가장 최근 거래가" />
        <Term k="매수적기 26.11" v="AI가 예측한 가장 유리한 매수 시점 = 2026년 11월 (연.월)" />
        <Term k="AI 예측 +4.7%" v="향후 12개월 예상 가격 변동률" />
        <Term k="N건 거래" v="해당 기간 실거래 신고 건수" />
      </div>
      <div style={{ fontSize: 11, fontFamily: T.mono, color: T.fgMuted, letterSpacing: 1, marginBottom: 6 }}>AI 의견 (우측 상단 뱃지)</div>
      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
        {sigs.map(([label, c, desc]) => (
          <div key={label} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
            <span style={{ padding: '2px 8px', borderRadius: 3, fontSize: 10, fontWeight: 700, fontFamily: T.mono, color: c, background: c + '20', border: '1px solid ' + c + '50' }}>{label}</span>
            <span style={{ fontSize: 11, color: T.fgMuted }}>{desc}</span>
          </div>
        ))}
      </div>
    </div>
  );
}
function Term({ k, v }) {
  return (
    <div style={{ display: 'flex', gap: 8, alignItems: 'baseline' }}>
      <span style={{ flexShrink: 0, fontSize: 12, fontWeight: 700, color: T.hot, fontFamily: T.mono, minWidth: 90 }}>{k}</span>
      <span style={{ fontSize: 12, color: T.fgMuted }}>{v}</span>
    </div>
  );
}

function RegionSelect({ label, value, options, onChange }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
      <span style={{ fontSize: 11, color: T.fgMuted, fontFamily: T.mono, whiteSpace: 'nowrap' }}>{label}</span>
      <select value={value} onChange={(e) => onChange(e.target.value)}
        style={{ padding: '8px 12px', borderRadius: 4, background: T.cardLo, color: T.fg, border: '1px solid ' + T.lineHi, fontSize: 13, fontFamily: T.font, cursor: 'pointer', minWidth: 120 }}>
        {options.map(o => <option key={o} value={o}>{o}</option>)}
      </select>
    </div>
  );
}

function LiveAptCard({ apt, region, onClick, ai: aiProp }) {
  const latest = apt.latest;
  const ai = useMemo(() => aiProp || window.analyzeUnit({ name: apt.name, region, trades: apt.trades, area: apt.area, buildYear: apt.buildYear }), [apt.name, aiProp]);
  return (
    <button onClick={onClick} data-track="live_apt_card"
      style={{ textAlign: 'left', background: T.card, border: '1px solid ' + T.line, borderRadius: 8, padding: 14, cursor: 'pointer', color: T.fg, fontFamily: T.font, transition: 'border .15s' }}
      onMouseEnter={(e) => e.currentTarget.style.borderColor = T.hot + '70'}
      onMouseLeave={(e) => e.currentTarget.style.borderColor = T.line}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 8 }}>
        <div style={{ minWidth: 0, flex: 1 }}>
          <div style={{ fontSize: 14, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{apt.name}</div>
          <div style={{ fontSize: 11, color: T.fgMuted, fontFamily: T.mono, marginTop: 2 }}>
            {apt.dong} · {apt.trades.length}건 거래{apt.buildYear ? ` · ${apt.buildYear}년식` : ''}
          </div>
        </div>
        <SignalBadge kind={ai.signal} size="sm" />
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginTop: 12 }}>
        <div>
          <div style={{ fontSize: 9, color: T.fgMuted, fontFamily: T.mono, letterSpacing: 1 }}>최근 실거래</div>
          <div className="uj-num" style={{ fontSize: 19, fontWeight: 700 }}>{manWon(latest)}</div>
        </div>
        <div style={{ textAlign: 'right' }}>
          <div style={{ fontSize: 9, color: T.fgMuted, fontFamily: T.mono }}>AI 예측 {ai.annualGrowth > 0 ? '+' : ''}{ai.annualGrowth}%</div>
          <div style={{ fontSize: 11, color: T.hot, fontFamily: T.mono, fontWeight: 700 }}>매수적기 {ai.bestBuyMonth}</div>
        </div>
      </div>
    </button>
  );
}

Object.assign(window, { SearchLivePage, useSigunguTrades, manWon });
