// tracker.jsx — uri-jib.com 사용자 행동 로그 수집 라이브러리
// 모든 페이지뷰, 클릭, 검색, 폼 제출, 에러를 localStorage 에 적재하고
// 백엔드 엔드포인트로 배치 전송한다. 실제 배포 시 /api/events 로 fetch.

(function () {
  const LS_KEY = 'urijib_events_v1';
  const LS_QUEUE = 'urijib_queue_v1';
  const LS_SID = 'urijib_session';
  const LS_UID = 'urijib_uid';
  const LS_USER = 'urijib_user';
  const SESSION_TIMEOUT_MIN = 30;
  const FLUSH_INTERVAL_MS = 8000;
  const MAX_LOCAL_EVENTS = 5000;

  function uid() {
    return 'u_' + Math.random().toString(36).slice(2, 10) + Date.now().toString(36).slice(-4);
  }
  function sid() {
    return 's_' + Math.random().toString(36).slice(2, 10) + Date.now().toString(36).slice(-4);
  }
  function now() { return Date.now(); }

  // ─── Session / User ────────────────────────────────────────
  function getOrCreateUid() {
    let u = localStorage.getItem(LS_UID);
    if (!u) { u = uid(); localStorage.setItem(LS_UID, u); }
    return u;
  }
  function getOrCreateSession() {
    const raw = localStorage.getItem(LS_SID);
    let s;
    try { s = raw ? JSON.parse(raw) : null; } catch (e) { s = null; }
    const t = now();
    if (!s || t - s.last > SESSION_TIMEOUT_MIN * 60 * 1000) {
      s = { id: sid(), start: t, last: t, pages: 0 };
    } else {
      s.last = t;
    }
    localStorage.setItem(LS_SID, JSON.stringify(s));
    return s;
  }
  function getUser() {
    const raw = localStorage.getItem(LS_USER);
    try { return raw ? JSON.parse(raw) : null; } catch (e) { return null; }
  }
  function setUser(user) {
    if (user) localStorage.setItem(LS_USER, JSON.stringify(user));
    else localStorage.removeItem(LS_USER);
  }

  // ─── Storage ───────────────────────────────────────────────
  function readAll() {
    try { return JSON.parse(localStorage.getItem(LS_KEY) || '[]'); }
    catch (e) { return []; }
  }
  function writeAll(arr) {
    if (arr.length > MAX_LOCAL_EVENTS) arr = arr.slice(-MAX_LOCAL_EVENTS);
    localStorage.setItem(LS_KEY, JSON.stringify(arr));
  }

  // ─── Event capture ─────────────────────────────────────────
  function track(event, props) {
    const session = getOrCreateSession();
    const user = getUser();
    const e = {
      id: 'e_' + Math.random().toString(36).slice(2, 12),
      ts: now(),
      event,
      props: props || {},
      uid: getOrCreateUid(),
      sid: session.id,
      authed: !!user,
      user_id: user ? user.id : null,
      user_email: user ? user.email : null,
      path: location.hash.slice(1) || '/',
      referrer: document.referrer || '',
      ua: navigator.userAgent,
      lang: navigator.language,
      vw: window.innerWidth,
      vh: window.innerHeight,
      tz: Intl.DateTimeFormat().resolvedOptions().timeZone,
      origin: location.origin,
    };
    const all = readAll();
    all.push(e);
    writeAll(all);

    // 큐에 쌓고 주기적으로 flush
    const q = JSON.parse(localStorage.getItem(LS_QUEUE) || '[]');
    q.push(e);
    localStorage.setItem(LS_QUEUE, JSON.stringify(q));

    window.dispatchEvent(new CustomEvent('urijib:event', { detail: e }));
    return e;
  }

  // ─── Batch flush to backend (mocked) ───────────────────────
  let flushing = false;
  async function flush() {
    if (flushing) return;
    flushing = true;
    try {
      const q = JSON.parse(localStorage.getItem(LS_QUEUE) || '[]');
      if (!q.length) return;
      // 실제 배포 시: POST https://api.uri-jib.com/v1/events
      // 지금은 mock — 그래도 동작과 telemetry 는 동일
      const ok = await mockSend(q);
      if (ok) {
        localStorage.setItem(LS_QUEUE, '[]');
        window.dispatchEvent(new CustomEvent('urijib:flushed', { detail: { count: q.length } }));
      }
    } catch (e) {
      console.warn('[tracker] flush failed', e);
    } finally {
      flushing = false;
    }
  }
  function mockSend(batch) {
    return new Promise((res) => {
      // 가짜 네트워크 지연
      setTimeout(() => res(true), 120);
    });
  }

  // ─── Auto: pageview on hashchange ──────────────────────────
  function pageView() {
    const session = getOrCreateSession();
    session.pages = (session.pages || 0) + 1;
    localStorage.setItem(LS_SID, JSON.stringify(session));
    track('page_view', { title: document.title, page: location.hash.slice(1) || '/' });
  }

  // ─── Auto: clicks on [data-track] ──────────────────────────
  function onClick(e) {
    const el = e.target.closest('[data-track]');
    if (!el) return;
    const name = el.getAttribute('data-track');
    const props = {};
    for (const a of el.attributes) {
      if (a.name.startsWith('data-track-')) {
        props[a.name.slice(11)] = a.value;
      }
    }
    if (el.tagName === 'A' && el.href) props.href = el.href;
    if (el.textContent) props.label = el.textContent.trim().slice(0, 80);
    track('click', { target: name, ...props });
  }

  // ─── Errors ────────────────────────────────────────────────
  function onError(e) {
    track('error', {
      message: (e.message || e.reason && e.reason.message || 'unknown').slice(0, 240),
      filename: e.filename || '',
      lineno: e.lineno || 0,
    });
  }

  // ─── Visibility / engagement ───────────────────────────────
  let lastFocus = now();
  function onVisibility() {
    if (document.hidden) {
      track('engagement', { ms_active: now() - lastFocus });
      flush();
    } else {
      lastFocus = now();
    }
  }

  // ─── Init ──────────────────────────────────────────────────
  function init() {
    getOrCreateUid();
    getOrCreateSession();
    window.addEventListener('hashchange', pageView);
    document.addEventListener('click', onClick, true);
    window.addEventListener('error', onError);
    window.addEventListener('unhandledrejection', onError);
    document.addEventListener('visibilitychange', onVisibility);
    setInterval(flush, FLUSH_INTERVAL_MS);
    // 첫 진입 page_view
    setTimeout(pageView, 0);
    track('session_start', { entry: location.hash.slice(1) || '/' });
  }

  // ─── Admin helpers ─────────────────────────────────────────
  function clearAll() {
    localStorage.removeItem(LS_KEY);
    localStorage.removeItem(LS_QUEUE);
    window.dispatchEvent(new CustomEvent('urijib:cleared'));
  }
  function seed(n = 200) {
    // 데모용 가짜 트래픽 — admin 페이지에서 호출
    const events = ['page_view', 'click', 'search', 'login_success', 'signup_complete',
      'watchlist_add', 'filter_change', 'onboarding_step', 'engagement'];
    const paths = ['/', '/login', '/signup', '/onboarding/1', '/onboarding/3', '/app/dashboard',
      '/app/detail/eunma', '/app/detail/jeongja-ip', '/app/search', '/app/portfolio',
      '/app/compare', '/app/loan', '/app/profile'];
    const all = readAll();
    const base = now() - 7 * 24 * 60 * 60 * 1000;
    for (let i = 0; i < n; i++) {
      const t = base + Math.random() * 7 * 24 * 60 * 60 * 1000;
      all.push({
        id: 'e_seed' + i,
        ts: t,
        event: events[Math.floor(Math.random() * events.length)],
        props: { seed: true },
        uid: 'u_seed' + Math.floor(Math.random() * 40),
        sid: 's_seed' + Math.floor(Math.random() * 80),
        authed: Math.random() > 0.4,
        path: paths[Math.floor(Math.random() * paths.length)],
        ua: 'Mozilla/5.0 (seed)',
        lang: 'ko-KR',
        vw: 1440, vh: 900, tz: 'Asia/Seoul',
      });
    }
    writeAll(all);
    window.dispatchEvent(new CustomEvent('urijib:event'));
  }

  window.UJTrack = {
    track, flush, pageView, init,
    getUser, setUser, getUid: getOrCreateUid, getSid: () => getOrCreateSession().id,
    readAll, clearAll, seed,
  };

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();
