const DEVICE_ID_KEY = 'fb_comments_export_device_id';
const TELEMETRY_URL = 'https://toolfb.cloud/api/telemetry/event';

chrome.runtime.onInstalled.addListener(async (details) => {
  if (details.reason === 'install') {
    await sendTelemetryEvent('install');
  }
});

chrome.action.onClicked.addListener(async (tab) => {
  const targetTabId = tab?.id ? `&targetTabId=${encodeURIComponent(tab.id)}` : '';
  const popupUrl = chrome.runtime.getURL(`popup.html?detached=1${targetTabId}`);

  try {
    const existingTabs = await chrome.tabs.query({
      url: chrome.runtime.getURL('popup.html*')
    });
    const existingTab = existingTabs[0];

    if (existingTab?.id && existingTab.windowId) {
      await chrome.windows.update(existingTab.windowId, {
        focused: true
      });
      return;
    }
  } catch (error) {
    // Open a new detached window if Chrome cannot query/focus an existing one.
  }

  chrome.windows.create({
    url: popupUrl,
    type: 'popup',
    width: 470,
    height: 720,
    focused: true
  });
});

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.action !== 'RESOLVE_UID_BATCH' && request.action !== 'DEBUG_UID') {
    return false;
  }

  const task = request.action === 'DEBUG_UID' ? debugUid(request) : resolveUidBatch(request);

  task
    .then((result) => sendResponse(result))
    .catch((error) => {
      sendResponse({
        ok: false,
        error: error.message || String(error)
      });
    });

  return true;
});

async function resolveUidBatch(request) {
  const serverUrl = normalizeServerUrl(request.serverUrl || 'http://127.0.0.1:8787');
  const response = await fetchWithTimeout(`${serverUrl}/resolve`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      urls: Array.isArray(request.urls) ? request.urls : [],
      pauseMs: Number(request.pauseMs || 0),
      userAgent: request.userAgent || ''
    })
  });

  if (!response.ok) {
    throw new Error(`Local resolver returned HTTP ${response.status}`);
  }

  return response.json();
}

async function debugUid(request) {
  const serverUrl = normalizeServerUrl(request.serverUrl || 'http://127.0.0.1:8787');
  const response = await fetchWithTimeout(`${serverUrl}/debug`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url: request.url || '',
      userAgent: request.userAgent || ''
    })
  });

  if (!response.ok) {
    throw new Error(`Local resolver debug returned HTTP ${response.status}`);
  }

  return response.json();
}

async function fetchWithTimeout(url, options = {}, timeoutMs = 15000) {
  const controller = new AbortController();
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);

  try {
    return await fetch(url, {
      ...options,
      signal: controller.signal
    });
  } catch (error) {
    if (error?.name === 'AbortError') {
      throw new Error('Local resolver timeout. Start the UID resolver server and try again.');
    }
    throw error;
  } finally {
    clearTimeout(timeoutId);
  }
}

function normalizeServerUrl(value) {
  const url = new URL(value);
  if (!['http:', 'https:'].includes(url.protocol)) {
    throw new Error('Local resolver URL must start with http:// or https://');
  }
  return `${url.protocol}//${url.host}`;
}

async function sendTelemetryEvent(event) {
  try {
    const deviceId = await getOrCreateTelemetryDeviceId();
    await fetch(TELEMETRY_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        event,
        deviceId,
        extensionVersion: chrome.runtime.getManifest().version
      })
    });
  } catch (error) {
    // Telemetry must never block extension usage.
  }
}

async function getOrCreateTelemetryDeviceId() {
  const stored = await chrome.storage.local.get(DEVICE_ID_KEY);
  if (stored?.[DEVICE_ID_KEY]) {
    return stored[DEVICE_ID_KEY];
  }

  const generated = crypto.randomUUID ? crypto.randomUUID() : createFallbackDeviceId();
  await chrome.storage.local.set({ [DEVICE_ID_KEY]: generated });
  return generated;
}

function createFallbackDeviceId() {
  const bytes = new Uint8Array(16);
  crypto.getRandomValues(bytes);
  return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('');
}
