
(function(){
  const ONLINE_TRACKER_IDS_KEY = "onlineTrackerIds";
  const ONLINE_TRACKER_ENABLED_KEY = "onlineTrackerEnabled";
  const ONLINE_TRACKER_RECENT_KEY = "onlineTrackerRecentNotifications";
  const ONLINE_TRACKER_SOUND_KEY = "onlineTrackerSoundEnabled";
  const ONLINE_TRACKER_SOUND_VOLUME_KEY = "onlineTrackerSoundVolume";
  const ONLINE_TRACKER_CHAT_CACHE_KEY = "onlineTrackerChatCache";
  const SOCKET_NOTIFICATIONS_KEY = "socketNotifications";
  let trackedIds = [];
  let trackedChatCache = Object.create(null);
  let isTrackerEnabled = false;
  let recentNotifications = [];
  let isSoundEnabled = false;
  let soundVolume = 70;
  let renderRefresh = null;

  function uniqIds(input){
    const arr = Array.isArray(input) ? input : String(input || "").split(/[\s,;]+/);
    return [...new Set(arr.map(v => String(v || "").trim()).filter(Boolean))];
  }

  function h(tag, props, ...children){
    const el = document.createElement(tag);
    if (props) {
      for (const [k,v] of Object.entries(props)) {
        if (k === 'style') el.style.cssText = v;
        else if (k === 'className') el.className = v;
        else if (k.startsWith('on') && typeof v === 'function') el.addEventListener(k.slice(2), v);
        else if (k === 'checked') el.checked = !!v;
        else if (k === 'value') el.value = v;
        else if (v !== undefined && v !== null) el.setAttribute(k, String(v));
      }
    }
    for (const child of children.flat()) {
      if (child == null) continue;
      el.appendChild(typeof child === 'string' ? document.createTextNode(child) : child);
    }
    return el;
  }

  async function loadTrackerSettings(){
    try {
      const result = await chrome.storage.local.get([ONLINE_TRACKER_IDS_KEY, ONLINE_TRACKER_ENABLED_KEY, ONLINE_TRACKER_RECENT_KEY, ONLINE_TRACKER_SOUND_KEY, ONLINE_TRACKER_SOUND_VOLUME_KEY, ONLINE_TRACKER_CHAT_CACHE_KEY]);
      trackedIds = uniqIds(result[ONLINE_TRACKER_IDS_KEY] || []);
      isTrackerEnabled = result[ONLINE_TRACKER_ENABLED_KEY] === true;
      recentNotifications = Array.isArray(result[ONLINE_TRACKER_RECENT_KEY]) ? result[ONLINE_TRACKER_RECENT_KEY] : [];
      isSoundEnabled = result[ONLINE_TRACKER_SOUND_KEY] === true;
      const rawVolume = Number(result[ONLINE_TRACKER_SOUND_VOLUME_KEY]);
      soundVolume = Number.isFinite(rawVolume) ? Math.min(100, Math.max(0, rawVolume)) : 70;
      trackedChatCache = result[ONLINE_TRACKER_CHAT_CACHE_KEY] && typeof result[ONLINE_TRACKER_CHAT_CACHE_KEY] === 'object' ? result[ONLINE_TRACKER_CHAT_CACHE_KEY] : Object.create(null);
      console.log('[Pulse Online Spy] Tracker settings loaded', { trackedIds: trackedIds.length, cachedChats: Object.keys(trackedChatCache || {}).length, isTrackerEnabled, isSoundEnabled, soundVolume });
      if (isTrackerEnabled) socketClient.setToken(getToken() || null);
      else socketClient.disconnect();
    } catch (error) {
      console.error('[Pulse Online Spy] Error loading tracker settings:', error);
    }
    refreshUi();
  }

  chrome.storage.onChanged.addListener((changes, areaName) => {
    if (areaName !== 'local') return;
    let needRefresh = false;
    if (changes[ONLINE_TRACKER_IDS_KEY]) {
      trackedIds = uniqIds(changes[ONLINE_TRACKER_IDS_KEY].newValue || []);
      needRefresh = true;
    }
    if (changes[ONLINE_TRACKER_ENABLED_KEY]) {
      isTrackerEnabled = changes[ONLINE_TRACKER_ENABLED_KEY].newValue === true;
      if (isTrackerEnabled) socketClient.setToken(getToken() || null);
      else socketClient.disconnect();
      needRefresh = true;
    }
    if (changes[ONLINE_TRACKER_RECENT_KEY]) {
      recentNotifications = Array.isArray(changes[ONLINE_TRACKER_RECENT_KEY].newValue) ? changes[ONLINE_TRACKER_RECENT_KEY].newValue : [];
      needRefresh = true;
    }
    if (changes[ONLINE_TRACKER_SOUND_KEY]) {
      isSoundEnabled = changes[ONLINE_TRACKER_SOUND_KEY].newValue === true;
      needRefresh = true;
    }
    if (changes[ONLINE_TRACKER_SOUND_VOLUME_KEY]) {
      const rawVolume = Number(changes[ONLINE_TRACKER_SOUND_VOLUME_KEY].newValue);
      soundVolume = Number.isFinite(rawVolume) ? Math.min(100, Math.max(0, rawVolume)) : 70;
      needRefresh = true;
    }
    if (changes[ONLINE_TRACKER_CHAT_CACHE_KEY]) {
      trackedChatCache = changes[ONLINE_TRACKER_CHAT_CACHE_KEY].newValue && typeof changes[ONLINE_TRACKER_CHAT_CACHE_KEY].newValue === 'object' ? changes[ONLINE_TRACKER_CHAT_CACHE_KEY].newValue : Object.create(null);
      needRefresh = true;
    }
    if (needRefresh) refreshUi();
  });

  class SimpleSocketClient {
    constructor(){
      this.socket = null;
      this.token = null;
      this.isConnecting = false;
      this.reconnectTimeout = null;
      this.reconnectAttempts = 0;
      this.maxReconnectAttempts = 10;
      this.reconnectDelay = 3000;
      this.handlers = [];
      this.isConnected = false;
    }
    setToken(token){
      if (!isTrackerEnabled) {
        this.token = token || null;
        this.disconnect();
        return;
      }
      const tokenChanged = this.token !== token;
      this.token = token;
      if (tokenChanged && this.socket) {
        this.disconnect();
        if (token) this.connect();
      } else if (token && !this.socket) {
        this.connect();
      }
    }
    connect(){
      if (!isTrackerEnabled) return;
      if (!this.token) return;
      if (this.isConnecting || (this.socket && this.socket.readyState === WebSocket.OPEN)) return;
      this.isConnecting = true;
      const wsUrl = `wss://alpha.date/api/v3/socket/ws/?token=${this.token}&EIO=3&transport=websocket`;
      try {
        this.socket = new WebSocket(wsUrl);
        this.socket.onopen = () => {
          this.isConnecting = false;
          this.isConnected = true;
          this.reconnectAttempts = 0;
          console.log('[Pulse Online Spy] Socket connected');
        };
        this.socket.onmessage = (event) => this.handleMessage(event.data);
        this.socket.onerror = (error) => console.error('[Pulse Online Spy] Socket error', error);
        this.socket.onclose = () => {
          this.isConnecting = false;
          this.isConnected = false;
          this.socket = null;
          console.log('[Pulse Online Spy] Socket disconnected');
          this.scheduleReconnect();
        };
      } catch (err) {
        console.error('[Pulse Online Spy] Socket connection error:', err);
        this.isConnecting = false;
        this.scheduleReconnect();
      }
    }
    disconnect(){
      if (this.reconnectTimeout) {
        clearTimeout(this.reconnectTimeout);
        this.reconnectTimeout = null;
      }
      if (this.socket) {
        this.socket.close();
        this.socket = null;
      }
      this.isConnected = false;
      this.isConnecting = false;
      this.reconnectAttempts = 0;
    }
    scheduleReconnect(){
      if (!isTrackerEnabled) return;
      if (this.reconnectTimeout) return;
      if (this.reconnectAttempts >= this.maxReconnectAttempts) return;
      if (!this.token) return;
      this.reconnectAttempts++;
      const delay = this.reconnectDelay * Math.min(this.reconnectAttempts, 5);
      this.reconnectTimeout = setTimeout(() => {
        this.reconnectTimeout = null;
        this.connect();
      }, delay);
    }
    handleMessage(rawData){
      try {
        if (rawData === '2') {
          if (this.socket && this.socket.readyState === WebSocket.OPEN) this.socket.send('3');
          return;
        }
        if (typeof rawData !== 'string' || !rawData.startsWith('42')) return;
        const payload = JSON.parse(rawData.slice(2));
        if (Array.isArray(payload) && payload.length >= 2) {
          const [channel, message] = payload;
          this.handlers.forEach((handler) => {
            try { handler(message, channel); } catch (err) { console.error('[Pulse Online Spy] Handler error', err); }
          });
        }
      } catch (err) {
        console.error('[Pulse Online Spy] Message handling error', err);
      }
    }
    subscribeToProfileCounters(handler){
      this.handlers.push(handler);
      return () => {
        const index = this.handlers.indexOf(handler);
        if (index > -1) this.handlers.splice(index, 1);
      };
    }
  }

  const socketClient = new SimpleSocketClient();

  function getToken(){
    try { return localStorage.getItem('token'); } catch (e) { return null; }
  }

  function watchToken(){
    let lastToken = getToken() || null;
    if (isTrackerEnabled) socketClient.setToken(lastToken);
    else socketClient.disconnect();
    setInterval(() => {
      const nextToken = getToken() || null;
      if (nextToken !== lastToken) {
        lastToken = nextToken;
        socketClient.setToken(nextToken);
      }
    }, 2000);
    window.addEventListener('storage', (e) => {
      if (e.key === 'token') socketClient.setToken(getToken() || null);
    });
  }

  function generateNotificationId(){
    return `notification_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
  }

  async function saveRecentNotification(data){
    const entry = {
      id: generateNotificationId(),
      external_id: String(data.external_id || ''),
      name: String(data.name || 'Unknown'),
      age: data.age || '',
      photo_link: data.photo_link || null,
      notification_type: 'user_online',
      timestamp: data.timestamp || Date.now()
    };
    recentNotifications = [entry, ...recentNotifications.filter(item => String(item.external_id) !== entry.external_id)].slice(0, 20);
    await chrome.storage.local.set({ [ONLINE_TRACKER_RECENT_KEY]: recentNotifications });
  }

  async function saveSocketNotification(notificationData){
    try {
      const result = await chrome.storage.local.get([SOCKET_NOTIFICATIONS_KEY]);
      const notifications = Array.isArray(result[SOCKET_NOTIFICATIONS_KEY]) ? result[SOCKET_NOTIFICATIONS_KEY] : [];
      notifications.push(notificationData);
      await chrome.storage.local.set({ [SOCKET_NOTIFICATIONS_KEY]: notifications });
    } catch (error) {
      console.error('[Pulse Online Spy] Error saving socket notification:', error);
    }
  }

  function normalizeId(value){
    return String(value == null ? '' : value).trim();
  }

  function getCachedChatUid(externalId){
    const key = normalizeId(externalId);
    return key ? normalizeId(trackedChatCache?.[key]?.chat_uid) : '';
  }

  async function saveTrackedChatUid(externalId, chatUid){
    const candidateId = normalizeId(externalId);
    const normalizedChatUid = normalizeId(chatUid);
    if (!candidateId || !normalizedChatUid) return normalizedChatUid;
    trackedChatCache = {
      ...(trackedChatCache && typeof trackedChatCache === 'object' ? trackedChatCache : {}),
      [candidateId]: {
        candidate_id: candidateId,
        chat_uid: normalizedChatUid,
        updated_at: Date.now()
      }
    };
    await chrome.storage.local.set({ [ONLINE_TRACKER_CHAT_CACHE_KEY]: trackedChatCache });
    return normalizedChatUid;
  }

  async function pruneTrackedChatCache(validIds){
    const keep = new Set((Array.isArray(validIds) ? validIds : []).map(normalizeId).filter(Boolean));
    const nextCache = Object.create(null);
    let changed = false;
    const current = trackedChatCache && typeof trackedChatCache === 'object' ? trackedChatCache : {};
    for (const [candidateId, entry] of Object.entries(current)) {
      if (keep.has(candidateId)) nextCache[candidateId] = entry;
      else changed = true;
    }
    if (changed) {
      trackedChatCache = nextCache;
      await chrome.storage.local.set({ [ONLINE_TRACKER_CHAT_CACHE_KEY]: trackedChatCache });
    }
  }

  function getTokenCandidates(){
    const out = [];
    const seen = new Set();
    const push = (value) => {
      const token = normalizeId(value).replace(/^Bearer\s+/i, '');
      if (!token || seen.has(token)) return;
      seen.add(token);
      out.push(token);
    };
    try {
      push(localStorage.getItem('token'));
      push(localStorage.getItem('jwt'));
      push(sessionStorage.getItem('token'));
      push(sessionStorage.getItem('jwt'));
      Object.keys(localStorage || {}).forEach((key) => /token|jwt/i.test(key) && push(localStorage.getItem(key)));
      Object.keys(sessionStorage || {}).forEach((key) => /token|jwt/i.test(key) && push(sessionStorage.getItem(key)));
    } catch (error) {}
    return out;
  }

  async function pulseApiPost(url, body, token){
    const headers = {
      'accept': 'application/json, text/plain, */*',
      'content-type': 'application/json'
    };
    if (token) headers.authorization = 'Bearer ' + token;
    const response = await fetch(url, {
      method: 'POST',
      headers,
      credentials: 'include',
      body: JSON.stringify(body || {})
    });
    const json = await response.json().catch(() => ({}));
    return { ok: response.ok, status: response.status, json };
  }

  async function resolveChatUidByCandidateId(candidateExternalId){
    const candidateId = normalizeId(candidateExternalId);
    if (!candidateId) return '';
    const cached = getCachedChatUid(candidateId);
    if (cached) return cached;

    const tokens = getTokenCandidates();
    const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    for (const token of tokens.length ? tokens : ['']) {
      const chatUidPool = [];
      const seenChatUids = new Set();

      for (let page = 1; page <= 2; page++) {
        const { ok, status, json } = await pulseApiPost('/api/chatList/chatListByUserID', { page, chat_uid: true }, token);
        if (status === 429) {
          await sleep(1200);
          page -= 1;
          continue;
        }
        if (!ok) break;
        const rows = Array.isArray(json?.response) ? json.response : [];
        if (!rows.length) break;
        for (const row of rows) {
          const uid = normalizeId(row?.chat_uid);
          if (!uid || seenChatUids.has(uid)) continue;
          seenChatUids.add(uid);
          chatUidPool.push(uid);
        }
        await sleep(250);
      }

      if (!chatUidPool.length) continue;

      const { ok, json } = await pulseApiPost('/api/chatList/lastMessage', { chat_uid: chatUidPool }, token);
      if (!ok) continue;

      const rows = Array.isArray(json?.response) ? json.response : [];
      const hit = rows.find((row) => [
        row?.recipient_external_id,
        row?.sender_external_id,
        row?.external_id,
        row?.male_external_id,
        row?.female_external_id,
        row?.user_id
      ].map(normalizeId).includes(candidateId));

      const chatUid = normalizeId(hit?.chat_uid);
      if (chatUid) {
        await saveTrackedChatUid(candidateId, chatUid);
        return chatUid;
      }
    }

    return '';
  }

  async function openTrackedCandidateChat(externalId, triggerEl){
    const candidateId = normalizeId(externalId);
    if (!candidateId) return '';
    const button = triggerEl || null;
    const originalText = button ? button.textContent : '';
    const restore = () => {
      if (button) {
        button.disabled = false;
        button.textContent = originalText || 'Open chat';
      }
    };
    try {
      if (button) {
        button.disabled = true;
        button.textContent = 'Searching...';
      }
      const chatUid = getCachedChatUid(candidateId) || await resolveChatUidByCandidateId(candidateId);
      if (!chatUid) return '';
      window.open(`https://alpha.date/chat/${chatUid}`, '_blank', 'noopener,noreferrer');
      return chatUid;
    } catch (error) {
      console.error('[Pulse Online Spy] Failed to open chat', { candidateId, error });
      return '';
    } finally {
      restore();
    }
  }

  function createAvatar(photoLink, alt = 'Avatar', size = 32) {
    const avatarContainer = document.createElement('div');
    avatarContainer.style.cssText = `width:${size}px;height:${size}px;border-radius:50%;overflow:hidden;background:#e5e7eb;display:flex;align-items:center;justify-content:center;flex-shrink:0;`;
    if (photoLink) {
      const img = document.createElement('img');
      img.src = photoLink;
      img.alt = alt;
      img.style.cssText = 'width:100%;height:100%;object-fit:cover;';
      img.onerror = () => avatarContainer.innerHTML = '<div style="color:#9ca3af;font-size:16px;">👤</div>';
      avatarContainer.appendChild(img);
    } else {
      avatarContainer.innerHTML = '<div style="color:#9ca3af;font-size:16px;">👤</div>';
    }
    return avatarContainer;
  }

  function getNotificationsContainer(){
    const notificationList = document.querySelector('[data-testid="paid-notification-list"]');
    if (!notificationList) return null;
    const childDivs = Array.from(notificationList.children).filter((child) => child.tagName === 'DIV');
    return childDivs[1] || notificationList;
  }

  function ensurePulseAnimationStyle(){
    if (document.getElementById('pulse-online-tracker-styles')) return;
    const style = document.createElement('style');
    style.id = 'pulse-online-tracker-styles';
    style.textContent = `
      @keyframes pulseOnlineSpyPulse{0%{opacity:1;transform:scale(1)}50%{opacity:.55;transform:scale(.92)}100%{opacity:1;transform:scale(1)}}
      @keyframes pulseOnlineSpyGlow{0%{box-shadow:0 0 0 rgba(34,197,94,.0), inset 0 1px 0 rgba(255,255,255,.18)}50%{box-shadow:0 0 26px rgba(45,212,191,.24), inset 0 1px 0 rgba(255,255,255,.28)}100%{box-shadow:0 0 0 rgba(34,197,94,.0), inset 0 1px 0 rgba(255,255,255,.18)}}
      .pulse-online-notification{position:relative;overflow:hidden;padding:12px;margin:8px 0;border-radius:16px;border:1px solid rgba(110,231,183,.30);background:linear-gradient(135deg,rgba(10,18,30,.78),rgba(19,36,49,.72));backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;box-shadow:0 14px 32px rgba(2,6,23,.24), inset 0 1px 0 rgba(255,255,255,.14);animation:pulseOnlineSpyGlow 4.2s ease-in-out infinite}
      .pulse-online-notification::before{content:"";position:absolute;inset:0;background:radial-gradient(circle at top right,rgba(45,212,191,.16),transparent 34%), radial-gradient(circle at bottom left,rgba(96,165,250,.12),transparent 36%);pointer-events:none}
      .pulse-online-notification__top{display:flex;gap:10px;align-items:flex-start;position:relative;z-index:1}
      .pulse-online-notification__meta{flex:1;min-width:0;display:flex;flex-direction:column;gap:6px}
      .pulse-online-notification__title{display:flex;align-items:center;gap:8px;min-width:0;flex-wrap:wrap}
      .pulse-online-notification__name{font-weight:700;font-size:14px;line-height:1.2;color:#f8fafc;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
      .pulse-online-notification__status{display:inline-flex;align-items:center;gap:5px;padding:3px 8px;border-radius:999px;background:rgba(34,197,94,.12);border:1px solid rgba(74,222,128,.18);color:#86efac;font-size:11px;font-weight:700;letter-spacing:.02em}
      .pulse-online-notification__status-dot{width:7px;height:7px;border-radius:999px;background:#34d399;animation:pulseOnlineSpyPulse 1.8s ease-in-out infinite}
      .pulse-online-notification__sub{font-size:11px;color:rgba(226,232,240,.72)}
      .pulse-online-notification__hint{font-size:12px;color:rgba(191,219,254,.82)}
      .pulse-online-notification__close{background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.08);font-size:18px;line-height:1;color:#cbd5e1;cursor:pointer;padding:0;width:26px;height:26px;display:flex;align-items:center;justify-content:center;border-radius:10px;flex-shrink:0;transition:all .18s ease}
      .pulse-online-notification__close:hover{background:rgba(255,255,255,.12);color:#fff;transform:translateY(-1px)}
      .pulse-online-notification__footer{position:relative;z-index:1;display:flex;justify-content:flex-end;margin-top:10px}
      .pulse-online-notification__chat{display:inline-flex;align-items:center;justify-content:center;width:100%;text-decoration:none;padding:9px 12px;border-radius:12px;background:linear-gradient(135deg,rgba(34,211,238,.22),rgba(59,130,246,.26));border:1px solid rgba(125,211,252,.28);color:#e0f2fe;font-size:12px;font-weight:700;letter-spacing:.01em;box-shadow:inset 0 1px 0 rgba(255,255,255,.12);transition:all .18s ease}
      .pulse-online-notification__chat:hover{transform:translateY(-1px);background:linear-gradient(135deg,rgba(34,211,238,.28),rgba(59,130,246,.34));box-shadow:0 8px 18px rgba(14,165,233,.14), inset 0 1px 0 rgba(255,255,255,.16)}
      .pulse-online-notification__avatar{box-shadow:0 10px 18px rgba(15,23,42,.22), 0 0 0 1px rgba(255,255,255,.06)}
    `;
    document.head.appendChild(style);
  }

  function createUserOnlineNotification(userData){
    ensurePulseAnimationStyle();
    const id = generateNotificationId();
    const notificationDiv = document.createElement('div');
    notificationDiv.className = 'pulse-online-notification';
    notificationDiv.setAttribute('data-notification-id', id);
    notificationDiv.setAttribute('data-notification-type', 'user_online');

    const top = document.createElement('div');
    top.className = 'pulse-online-notification__top';

    const avatar = createAvatar(userData.photo_link, userData.name, 40);
    avatar.classList.add('pulse-online-notification__avatar');

    const meta = document.createElement('div');
    meta.className = 'pulse-online-notification__meta';

    const title = document.createElement('div');
    title.className = 'pulse-online-notification__title';

    const nameSpan = document.createElement('span');
    nameSpan.className = 'pulse-online-notification__name';
    nameSpan.textContent = `${userData.name || 'Unknown'}${userData.age ? `, ${userData.age}` : ''}`;

    const status = document.createElement('span');
    status.className = 'pulse-online-notification__status';
    const statusDot = document.createElement('span');
    statusDot.className = 'pulse-online-notification__status-dot';
    const statusText = document.createElement('span');
    statusText.textContent = 'Online now';
    status.appendChild(statusDot);
    status.appendChild(statusText);

    const sub = document.createElement('div');
    sub.className = 'pulse-online-notification__sub';
    sub.textContent = `ID: ${userData.external_id}`;

    const hint = document.createElement('div');
    hint.className = 'pulse-online-notification__hint';
    hint.textContent = 'Candidate appeared online.';

    title.appendChild(nameSpan);
    title.appendChild(status);
    meta.appendChild(title);
    meta.appendChild(sub);
    meta.appendChild(hint);

    const closeButton = document.createElement('button');
    closeButton.type = 'button';
    closeButton.className = 'pulse-online-notification__close';
    closeButton.setAttribute('aria-label', 'Close notification');
    closeButton.textContent = '×';
    closeButton.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); notificationDiv.remove(); });

    top.appendChild(avatar);
    top.appendChild(meta);
    top.appendChild(closeButton);

    const footer = document.createElement('div');
    footer.className = 'pulse-online-notification__footer';

    const chatButton = document.createElement('button');
    chatButton.type = 'button';
    chatButton.className = 'pulse-online-notification__chat';
    chatButton.textContent = 'Open chat';
    chatButton.title = getCachedChatUid(userData.external_id) ? 'Open cached chat' : 'Find and open chat';
    chatButton.addEventListener('click', async (event) => {
      event.preventDefault();
      event.stopPropagation();
      await openTrackedCandidateChat(userData.external_id, chatButton);
    });

    footer.appendChild(chatButton);
    notificationDiv.appendChild(top);
    notificationDiv.appendChild(footer);
    return { element: notificationDiv, id };
  }


  async function injectUserOnlineNotification(userData){
    try {
      const container = getNotificationsContainer();
      if (!container) return;
      const { element: notification, id } = createUserOnlineNotification(userData);
      await saveSocketNotification({
        id,
        action: 'user_online',
        payload: userData,
        userDetails: userData,
        timestamp: Date.now()
      });
      const childDivs = Array.from(container.children).filter((child) => child.tagName === 'DIV');
      if (childDivs.length === 0) container.appendChild(notification);
      else container.insertBefore(notification, childDivs[0]);
      setTimeout(() => {
        if (notification.parentNode) notification.remove();
      }, 30000);
    } catch (error) {
      console.error('[Pulse Online Spy] Error injecting user online notification:', error);
    }
  }


  function getSoundVolumeMultiplier(){
    return Math.min(1.875, Math.max(0, (soundVolume / 100) * 1.5));
  }

  function playOnlineSound(force = false){
    if (!force && !isSoundEnabled) return;
    try {
      const audioUrl = chrome.runtime.getURL('sounds/diling-meloboom.mp3');
      const audio = new Audio(audioUrl);
      audio.preload = 'auto';
      audio.volume = Math.min(1, Math.max(0, getSoundVolumeMultiplier() / 1.875));
      const playPromise = audio.play();
      if (playPromise && typeof playPromise.catch === 'function') {
        playPromise.catch((error) => {
          console.error('[Pulse Online Spy] Sound playback error:', error);
        });
      }
    } catch (error) {
      console.error('[Pulse Online Spy] Sound playback error:', error);
    }
  }

  async function handleUserOnlineMessage(payload){
    if (!isTrackerEnabled) return;
    let userData = payload;
    if (userData?.message?.message) userData = userData.message.message;
    else if (userData?.message) userData = userData.message;
    const externalId = userData?.external_id;
    if (!externalId) return;
    const externalIdStr = String(externalId);
    const isTracked = trackedIds.includes(externalIdStr) || trackedIds.includes(externalId);
    if (!isTracked) return;
    const notificationData = {
      external_id: externalIdStr,
      name: userData.name || 'Unknown',
      age: userData.age || '',
      photo_link: userData.photo_link || null,
      notification_type: 'user_online',
      timestamp: Date.now()
    };
    if ('Notification' in window && Notification.permission === 'granted') {
      try {
        new Notification(`${notificationData.name}, ${notificationData.age} is now online!`, {
          body: `User ID: ${notificationData.external_id}`,
          icon: notificationData.photo_link || undefined,
          tag: `online_${notificationData.external_id}`
        });
      } catch (error) {
        console.error('[Pulse Online Spy] Browser notification error:', error);
      }
    }
    try {
      chrome.runtime.sendMessage({ type: 'USER_ONLINE_NOTIFICATION', data: notificationData });
    } catch (error) {
      console.error('[Pulse Online Spy] Error sending notification to extension:', error);
    }
    playOnlineSound();
    await saveRecentNotification(notificationData);
    await injectUserOnlineNotification(notificationData);
  }

  function handleSocketMessage(payload, channel) {
    if (typeof channel === 'string' && channel === 'user_online') {
      handleUserOnlineMessage(payload);
    }
  }
  socketClient.subscribeToProfileCounters(handleSocketMessage);

  function formatTime(ts){
    const d = new Date(ts || Date.now());
    return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`;
  }

  function buildTrackerSwitch(){
    const input = h('input', { type: 'checkbox' });
    input.checked = isTrackerEnabled;
    input.addEventListener('change', async (event) => {
      const enabled = !!event.target.checked;
      await chrome.storage.local.set({ [ONLINE_TRACKER_ENABLED_KEY]: enabled });
      if (enabled && 'Notification' in window && Notification.permission === 'default') {
        try { await Notification.requestPermission(); } catch (e) {}
      }
    });
    const slider = h('span', { className: 'slider' });
    const sw = h('span', { className: 'switch' }, input, slider);
    return h('label', { style: 'display:flex;align-items:center;gap:12px;font-size:14px;' }, sw, h('span', null, 'Tracking enabled'));
  }


  function buildSoundControls(){
    const input = h('input', { type: 'checkbox' });
    input.checked = isSoundEnabled;
    input.addEventListener('change', async (event) => {
      const enabled = !!event.target.checked;
      await chrome.storage.local.set({ [ONLINE_TRACKER_SOUND_KEY]: enabled });
      if (enabled) playOnlineSound(true);
    });
    const slider = h('span', { className: 'slider' });
    const sw = h('span', { className: 'switch' }, input, slider);

    const range = h('input', {
      type: 'range',
      min: '0',
      max: '100',
      step: '1',
      value: String(soundVolume),
      style: 'width:118px;accent-color:#49e3b1;cursor:pointer;'
    });
    const valueLabel = h('span', { style: 'min-width:36px;font-size:12px;opacity:.82;' }, `${soundVolume}%`);

    range.addEventListener('input', (event) => {
      const value = Math.min(100, Math.max(0, Number(event.target.value) || 0));
      valueLabel.textContent = `${value}%`;
    });

    range.addEventListener('change', async (event) => {
      const value = Math.min(100, Math.max(0, Number(event.target.value) || 0));
      await chrome.storage.local.set({ [ONLINE_TRACKER_SOUND_VOLUME_KEY]: value });
      if (isSoundEnabled && value > 0) playOnlineSound(true);
    });

    return h('div', { style: 'display:flex;align-items:center;gap:12px;font-size:14px;flex-wrap:wrap;' },
      h('label', { style: 'display:flex;align-items:center;gap:12px;font-size:14px;' }, sw, h('span', null, 'Sound notification')),
      h('div', { style: 'display:flex;align-items:center;gap:8px;padding:4px 10px;border-radius:999px;background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);' },
        h('span', { style: 'font-size:12px;opacity:.74;' }, 'Volume'),
        range,
        valueLabel
      )
    );
  }

  function renderRecentList(container){
    container.innerHTML = '';
    if (!recentNotifications.length) {
      container.appendChild(h('div', { style: 'opacity:.65;font-size:12px' }, 'No online notifications yet.'));
      return;
    }
    recentNotifications.forEach((item) => {
      container.appendChild(h('div', {
        style: 'display:flex;justify-content:space-between;gap:10px;padding:8px 10px;border:1px solid rgba(255,255,255,.08);border-radius:8px;background:rgba(255,255,255,.03);margin-bottom:8px'
      },
        h('div', { style: 'min-width:0' },
          h('div', { style: 'font-weight:700;color:#8df0c8' }, `${item.name || 'Unknown'}${item.age ? `, ${item.age}` : ''}`),
          h('div', { style: 'font-size:12px;opacity:.78' }, `ID: ${item.external_id}`)
        ),
        h('div', { style: 'font-size:12px;white-space:nowrap;opacity:.7' }, formatTime(item.timestamp))
      ));
    });
  }

  function refreshUi(){
    if (typeof renderRefresh === 'function') renderRefresh();
  }

  window.renderOnlineSpyPulse = function(container){
    const wrap = h('div', { style: 'display:flex;flex-direction:column;gap:14px' });
    const idsArea = h('textarea', {
      id: 'pulse-online-tracker-ids',
      placeholder: 'Enter external IDs (one per line or separated by spaces)',
      style: 'width:100%;min-height:140px;resize:vertical;padding:10px;border-radius:8px;border:1px solid rgba(255,255,255,.1);background:rgba(255,255,255,.04);color:#e9eef6;box-sizing:border-box'
    });
    idsArea.value = trackedIds.join('\n');
    const saveStatus = h('div', { style: 'font-size:12px;opacity:.72' }, `Saved ${trackedIds.length} ID(s). Cache: ${Object.keys(trackedChatCache || {}).length}.`);
    const saveBtn = h('button', {
      style: 'align-self:flex-start;padding:9px 14px;border-radius:8px;border:1px solid rgba(255,255,255,.12);background:#0d7f5f;color:#fff;cursor:pointer',
      onclick: async () => {
        const ids = uniqIds(idsArea.value);
        await chrome.storage.local.set({ [ONLINE_TRACKER_IDS_KEY]: ids });
        await pruneTrackedChatCache(ids);
        saveStatus.textContent = `Saved ${ids.length} ID(s). Cache: ${Object.keys(trackedChatCache || {}).length}.`;
      }
    }, 'Save tracked IDs');
    const recentTitle = h('div', { style: 'font-weight:700;margin-top:4px' }, 'Recent Online Notifications');
    const recentBox = h('div', { style: 'margin-top:4px' });
    renderRecentList(recentBox);
    wrap.append(
      h('div', { style: 'display:flex;flex-wrap:wrap;gap:18px;align-items:center' }, buildTrackerSwitch(), buildSoundControls()),
      h('div', { style: 'font-size:12px;opacity:.75' }, 'Tracks exact external IDs and reacts to socket event user_online.'),
      idsArea,
      saveBtn,
      saveStatus,
      recentTitle,
      recentBox
    );
    container.appendChild(wrap);
    renderRefresh = () => {
      const active = document.getElementById('ah-body');
      const checkboxes = active ? active.querySelectorAll('input[type="checkbox"]') : [];
      if (checkboxes[0]) checkboxes[0].checked = isTrackerEnabled;
      if (checkboxes[1]) checkboxes[1].checked = isSoundEnabled;
      const volumeSlider = active ? active.querySelector('input[type="range"]') : null;
      if (volumeSlider && document.activeElement !== volumeSlider) volumeSlider.value = String(soundVolume);
      const volumeLabel = volumeSlider ? volumeSlider.parentElement?.querySelector('span:last-child') : null;
      if (volumeLabel) volumeLabel.textContent = `${soundVolume}%`;
      const area = document.getElementById('pulse-online-tracker-ids');
      if (area && document.activeElement !== area) area.value = trackedIds.join('\n');
      saveStatus.textContent = `Saved ${trackedIds.length} ID(s). Cache: ${Object.keys(trackedChatCache || {}).length}.`;
      renderRecentList(recentBox);
    };
  };

  loadTrackerSettings();
  watchToken();
})();
