// router.jsx — Hash-based router + global auth state for uri-jib.com

const { useState, useEffect, useCallback, useMemo, useRef } = React;

// ─── Hash router ─────────────────────────────────────────
function useRoute() {
  const [hash, setHash] = useState(location.hash.slice(1) || '/');
  useEffect(() => {
    const h = () => setHash(location.hash.slice(1) || '/');
    window.addEventListener('hashchange', h);
    return () => window.removeEventListener('hashchange', h);
  }, []);
  return hash;
}

function navigate(path) {
  if (location.hash.slice(1) === path) return;
  location.hash = path;
}

function parseRoute(hash) {
  // /app/detail/eunma → {base:'/app/detail', id:'eunma'}
  const m = hash.match(/^\/app\/detail\/(.+)$/);
  if (m) return { base: '/app/detail', id: m[1] };
  const o = hash.match(/^\/onboarding\/(\d+)$/);
  if (o) return { base: '/onboarding', step: parseInt(o[1], 10) };
  return { base: hash, id: null };
}

// ─── Responsive: 기기 화면 크기 감지 ─────────────────────
// 'mobile' < 640 ≤ 'tablet' < 1024 ≤ 'desktop'
function useBreakpoint() {
  const get = () => {
    const w = window.innerWidth;
    return w < 640 ? 'mobile' : w < 1024 ? 'tablet' : 'desktop';
  };
  const [bp, setBp] = useState(get);
  useEffect(() => {
    let raf;
    const h = () => { cancelAnimationFrame(raf); raf = requestAnimationFrame(() => setBp(get())); };
    window.addEventListener('resize', h);
    window.addEventListener('orientationchange', h);
    return () => { window.removeEventListener('resize', h); window.removeEventListener('orientationchange', h); cancelAnimationFrame(raf); };
  }, []);
  return bp;
}
function useIsMobile() { return useBreakpoint() === 'mobile'; }

// 특정 이벤트 발생 시 컴포넌트를 다시 그린다 (실시간 가격 반영용)
function useRerenderOn(eventName) {
  const [, set] = useState(0);
  useEffect(() => {
    const h = () => set(x => x + 1);
    window.addEventListener(eventName, h);
    return () => window.removeEventListener(eventName, h);
  }, [eventName]);
}

// ─── 실거래가 실시간 동기화 ───────────────────────────────
// 백엔드(/v1/molit)가 연결돼 있으면 주기적으로 최신 실거래가를 받아
// APTS 가격을 갱신한다. 백엔드 없으면 "샘플" 상태를 유지하되,
// 동기화 시각/카운트다운 UI 는 동일하게 동작한다.
const LAWD_BY_REGION = {
  '서울 강남구': '11680', '서울 서초구': '11650', '서울 송파구': '11710',
  '서울 강동구': '11740', '서울 마포구': '11440', '서울 용산구': '11170',
  '서울 성동구': '11200', '서울 광진구': '11215', '서울 양천구': '11470',
  '서울 영등포구': '11560', '서울 동작구': '11590', '서울 노원구': '11350',
  '서울 도봉구': '11320', '서울 성북구': '11290', '서울 강서구': '11500',
  '서울 중구': '11140', '경기 성남시 분당구': '41135', '경기 수원시 영통구': '41117',
  '경기 안양시 동안구': '41173', '경기 고양시 일산서구': '41287', '경기 화성시': '41590',
  '경기 하남시': '41450', '경기 광명시': '41210', '인천 연수구': '28185',
  '인천 서구': '28260', '부산 해운대구': '26350', '부산 수영구': '26500',
  '부산 부산진구': '26230', '대구 수성구': '27260', '대전 유성구': '30200',
  '대전 서구': '30170', '세종특별자치시': '36110', '광주 남구': '29155',
  '울산 남구': '31140',
};

function useLiveSync() {
  const SYNC_KEY = 'urijib_lastsync';
  const INTERVAL_MS = 25 * 1000; // 25초마다 폴링 (실시간 느낌)
  const [state, setState] = useState(() => ({
    lastSync: parseInt(localStorage.getItem(SYNC_KEY) || '0', 10) || null,
    syncing: false,
    connected: !!window.UJTrack.API_BASE,
    updated: 0,
  }));

  const syncNow = useCallback(async () => {
    const API = window.UJTrack.API_BASE;
    setState(s => ({ ...s, syncing: true }));
    window.UJTrack.track('rtms_sync_start', {});
    if (!API) {
      // 데모: 매 틱마다 일부 단지에만 소폭 실거래 반영(평균 회귀) — "살아있는" 느낌
      const pool = window.APTS;
      const k = Math.max(3, Math.floor(pool.length * 0.15));
      let n = 0;
      for (let i = 0; i < k; i++) {
        const a = pool[Math.floor(Math.random() * pool.length)];
        if (!a.basePriceRef) a.basePriceRef = a.currentPrice; // 기준가 기억
        // 기준가 대비 ±1.5% 밴드 안에서 진동
        const target = a.basePriceRef;
        const pull = (target - a.currentPrice) / target * 0.5;
        const noise = (Math.random() - 0.5) * 0.006;
        const np = Math.round(a.currentPrice * (1 + pull + noise));
        if (np !== a.currentPrice) {
          a.priceM1 = a.currentPrice;
          a.currentPrice = np;
          a.lastTradeAt = Date.now();
          a.history[a.history.length - 1] = { t: a.history[a.history.length - 1].t, v: np };
          n++;
        }
      }
      const now = Date.now();
      localStorage.setItem(SYNC_KEY, '' + now);
      setState({ lastSync: now, syncing: false, connected: false, updated: n });
      window.dispatchEvent(new CustomEvent('urijib:synced', { detail: { updated: n, demo: true } }));
      window.UJTrack.track('rtms_sync_done', { updated: n, demo: true });
      return;
    }
    // 실제: 단지가 속한 구별 RTMS 최근 실거래가를 받아 매칭
    try {
      const ym = new Date(); ym.setMonth(ym.getMonth() - 1);
      const dealYmd = ym.getFullYear() + ('' + (ym.getMonth() + 1)).padStart(2, '0');
      const regions = [...new Set(window.APTS.map(a => a.region))].filter(r => LAWD_BY_REGION[r]);
      let updated = 0;
      for (const region of regions) {
        const lawd = LAWD_BY_REGION[region];
        const res = await fetch(`${API}/v1/molit/recent?lawd_code=${lawd}&deal_ymd=${dealYmd}`);
        if (!res.ok) continue;
        const json = await res.json();
        const items = extractMolitItems(json);
        // 단지명 부분일치로 가격 갱신 (만원 단위)
        window.APTS.filter(a => a.region === region).forEach(a => {
          const hit = items.find(it => it.name && (a.name.includes(it.name) || it.name.includes(a.name.replace(/\s/g, ''))));
          if (hit && hit.price) {
            a.priceM1 = a.currentPrice;
            a.currentPrice = hit.price;
            a.history[a.history.length - 1] = { t: a.history[a.history.length - 1].t, v: hit.price };
            updated++;
          }
        });
      }
      const now = Date.now();
      localStorage.setItem(SYNC_KEY, '' + now);
      setState({ lastSync: now, syncing: false, connected: true, updated });
      window.dispatchEvent(new CustomEvent('urijib:synced', { detail: { updated, demo: false } }));
      window.UJTrack.track('rtms_sync_done', { updated, demo: false });
    } catch (e) {
      setState(s => ({ ...s, syncing: false }));
      window.UJTrack.track('rtms_sync_error', { message: ('' + e).slice(0, 120) });
    }
  }, []);

  useEffect(() => {
    syncNow();
    const id = setInterval(syncNow, INTERVAL_MS);
    return () => clearInterval(id);
  }, [syncNow]);

  return { ...state, syncNow };
}

// 국토부 RTMS JSON 응답에서 {name, price(만원)} 추출
function extractMolitItems(json) {
  try {
    const items = json?.data?.response?.body?.items?.item || json?.response?.body?.items?.item || [];
    const arr = Array.isArray(items) ? items : [items];
    return arr.map(it => ({
      name: (it.aptNm || it['아파트'] || '').trim(),
      price: parseInt(('' + (it.dealAmount || it['거래금액'] || '0')).replace(/[^0-9]/g, ''), 10) || 0,
    })).filter(x => x.name);
  } catch (e) { return []; }
}

// ─── Auth (localStorage-backed) ──────────────────────────
function useAuth() {
  const [user, setUser] = useState(() => window.UJTrack.getUser());
  useEffect(() => {
    const h = () => setUser(window.UJTrack.getUser());
    window.addEventListener('urijib:auth', h);
    return () => window.removeEventListener('urijib:auth', h);
  }, []);
  const login = useCallback((u) => {
    window.UJTrack.setUser(u);
    window.UJTrack.track('login_success', { provider: u.provider, method: u.method });
    window.dispatchEvent(new CustomEvent('urijib:auth'));
  }, []);
  const logout = useCallback(() => {
    window.UJTrack.track('logout', {});
    window.UJTrack.setUser(null);
    window.dispatchEvent(new CustomEvent('urijib:auth'));
  }, []);
  return { user, login, logout };
}

// ─── Watchlist (per-user, localStorage) ──────────────────
function useWatchlist() {
  const KEY = 'urijib_watchlist';
  const [ids, setIds] = useState(() => {
    try { return JSON.parse(localStorage.getItem(KEY) || '[]'); } catch (e) { return []; }
  });
  useEffect(() => {
    localStorage.setItem(KEY, JSON.stringify(ids));
  }, [ids]);
  const toggle = useCallback((id) => {
    setIds((prev) => {
      const has = prev.includes(id);
      window.UJTrack.track(has ? 'watchlist_remove' : 'watchlist_add', { apt_id: id });
      return has ? prev.filter(x => x !== id) : [...prev, id];
    });
  }, []);
  const has = useCallback((id) => ids.includes(id), [ids]);
  return { ids, toggle, has };
}

// ─── Toast ───────────────────────────────────────────────
function useToast() {
  const [msg, setMsg] = useState(null);
  const show = useCallback((text, kind = 'info', ms = 2200) => {
    setMsg({ text, kind, id: Date.now() });
    setTimeout(() => setMsg(null), ms);
  }, []);
  const node = msg && (
    <div style={{
      position: 'fixed', bottom: 24, left: '50%', transform: 'translateX(-50%)',
      background: T.cardHi, border: '1px solid ' + T.line, color: T.fg,
      padding: '10px 18px', borderRadius: 4, fontSize: 13,
      fontFamily: T.font, zIndex: 9999,
      boxShadow: '0 12px 32px rgba(0,0,0,0.5)',
      animation: 'ujfadeup .25s ease',
    }}>
      <span style={{
        display: 'inline-block', width: 6, height: 6, borderRadius: 3,
        marginRight: 8, verticalAlign: 'middle',
        background: msg.kind === 'success' ? T.up : msg.kind === 'error' ? T.down : T.hot,
      }} />
      {msg.text}
    </div>
  );
  return { show, node };
}

Object.assign(window, { useRoute, navigate, parseRoute, useAuth, useWatchlist, useToast, useBreakpoint, useIsMobile, useLiveSync, useRerenderOn });
