// content.js — connection manager & relay between page and background (stateful)
(() => {
  console.log("[CONTENT] Content script loaded on:", location.hostname);

  const ALLOWED_HOSTS = [
    "localhost",
    "leadsniper.online",
    "www.leadsniper.online",
    "demo.leadsniper.online",
    "app.leadsniper.online",
    "ahmad.leadsniper.online",
    "www.app.leadsniper.online",
    "leadsniper.com",
    "www.leadsniper.com",
    "demo.leadsniper.com",
    "app.leadsniper.com",
    "ahmad.leadsniper.com",
    "www.app.leadsniper.com"
  ];

  const EMAIL_BRIDGE = Object.freeze({
    REQUEST: "EXT_EMAIL_SENDER_REQUEST",
    RESPONSE: "EXT_EMAIL_SENDER_RESPONSE",
    EVENT: "EXT_EMAIL_SENDER_EVENT"
  });

  const currentHost = location.hostname;
  const isFileProtocol = location.protocol === "file:";
  const isLocalhost = currentHost === "localhost" || currentHost === "127.0.0.1";

  if (!ALLOWED_HOSTS.includes(currentHost) && !isLocalhost && !isFileProtocol) {
    console.warn("[CONTENT] Not an allowed host:", currentHost);
    return;
  }

  console.log("[CONTENT] Host is allowed, setting up message listeners");

  const postBack = (payload) => {
    try { window.postMessage(payload, "*"); } catch {}
  };

  const STATES = Object.freeze({
    IDLE: "idle",
    CONNECTING: "connecting",
    CONNECTED: "connected",
    TERMINATING: "terminating",
    TERMINATED: "terminated"
  });

  let state = STATES.IDLE;
  let jobActive = false;
  let contextInvalidated = false;
  let port = null;
  let reconnectTimer = null;
  let connectAttempts = 0;
  let yelpKeepAlivePort = null;
  let yelpKeepAliveRetryTimer = null;
  let yellowPagesKeepAlivePort = null;
  let yellowPagesKeepAliveRetryTimer = null;

  const BASE_RETRY_MS = 400;
  const MAX_RETRY_MS = 8000;
  const MAX_RECONNECT_ATTEMPTS = 6;

  const pendingMessages = [];
  const lifecycleLogs = new Set();
  const CONTEXT_INVALID_RE = /extension context invalidated/i;

  const runtimeReady = () => typeof chrome !== "undefined" && !!chrome.runtime && typeof chrome.runtime.connect === "function";

  let yelpContentRegistered = false;
  let yellowPagesContentRegistered = false;
  const registerYelpContent = () => {
    if (yelpContentRegistered) return;
    if (!runtimeReady() || !chrome.runtime?.sendMessage) return;
    yelpContentRegistered = true;
    try { chrome.runtime.sendMessage({ type: 'yelp-register-content' }); } catch {}
  };

  const unregisterYelpContent = () => {
    if (!yelpContentRegistered) return;
    if (!runtimeReady() || !chrome.runtime?.sendMessage) return;
    try { chrome.runtime.sendMessage({ type: 'yelp-unregister-content' }); } catch {}
    yelpContentRegistered = false;
    stopYelpKeepAlive();
  };

  const registerYellowPagesContent = () => {
    if (yellowPagesContentRegistered) return;
    if (!runtimeReady() || !chrome.runtime?.sendMessage) return;
    yellowPagesContentRegistered = true;
    try { chrome.runtime.sendMessage({ type: 'yellowpages-register-content' }); } catch {}
  };

  const unregisterYellowPagesContent = () => {
    if (!yellowPagesContentRegistered) return;
    if (!runtimeReady() || !chrome.runtime?.sendMessage) return;
    try { chrome.runtime.sendMessage({ type: 'yellowpages-unregister-content' }); } catch {}
    yellowPagesContentRegistered = false;
    stopYellowPagesKeepAlive();
  };

  function logOnce(key, fn) {
    if (lifecycleLogs.has(key)) return;
    lifecycleLogs.add(key);
    try { fn(); } catch {}
  }

  function resetLifecycleLogs() {
    lifecycleLogs.clear();
  }

  function scheduleYelpKeepAliveRetry() {
    if (yelpKeepAliveRetryTimer) return;
    yelpKeepAliveRetryTimer = setTimeout(() => {
      yelpKeepAliveRetryTimer = null;
      startYelpKeepAlive();
    }, 1600);
  }

  function scheduleYellowPagesKeepAliveRetry() {
    if (yellowPagesKeepAliveRetryTimer) return;
    yellowPagesKeepAliveRetryTimer = setTimeout(() => {
      yellowPagesKeepAliveRetryTimer = null;
      startYellowPagesKeepAlive();
    }, 1600);
  }

  function startYelpKeepAlive() {
    if (yelpKeepAlivePort || !runtimeReady() || !chrome.runtime?.connect) return;
    try {
      yelpKeepAlivePort = chrome.runtime.connect({ name: 'yelpScraperUi' });
      yelpKeepAlivePort.onDisconnect.addListener(() => {
        yelpKeepAlivePort = null;
        scheduleYelpKeepAliveRetry();
      });
    } catch (error) {
      const message = error?.message || String(error || '');
      if (/extension context invalidated/i.test(message) || /cannot access contents of chrome-extension/i.test(message)) {
        scheduleYelpKeepAliveRetry();
      } else {
        console.warn('[CONTENT] Yelp keep-alive failed', message);
      }
      yelpKeepAlivePort = null;
    }
  }

  function stopYelpKeepAlive() {
    if (yelpKeepAlivePort) {
      try { yelpKeepAlivePort.disconnect(); } catch {}
      yelpKeepAlivePort = null;
    }
    if (yelpKeepAliveRetryTimer) {
      clearTimeout(yelpKeepAliveRetryTimer);
      yelpKeepAliveRetryTimer = null;
    }
  }

  function startYellowPagesKeepAlive() {
    if (yellowPagesKeepAlivePort || !runtimeReady() || !chrome.runtime?.connect) return;
    try {
      yellowPagesKeepAlivePort = chrome.runtime.connect({ name: 'yellowPagesScraperUi' });
      yellowPagesKeepAlivePort.onDisconnect.addListener(() => {
        yellowPagesKeepAlivePort = null;
        scheduleYellowPagesKeepAliveRetry();
      });
    } catch (error) {
      const message = error?.message || String(error || '');
      if (/extension context invalidated/i.test(message) || /cannot access contents of chrome-extension/i.test(message)) {
        scheduleYellowPagesKeepAliveRetry();
      } else {
        console.warn('[CONTENT] Yellow Pages keep-alive failed', message);
      }
      yellowPagesKeepAlivePort = null;
    }
  }

  function stopYellowPagesKeepAlive() {
    if (yellowPagesKeepAlivePort) {
      try { yellowPagesKeepAlivePort.disconnect(); } catch {}
      yellowPagesKeepAlivePort = null;
    }
    if (yellowPagesKeepAliveRetryTimer) {
      clearTimeout(yellowPagesKeepAliveRetryTimer);
      yellowPagesKeepAliveRetryTimer = null;
    }
  }

  function notifyEmailBridgeReady(reason) {
    try {
      window.postMessage({
        type: EMAIL_BRIDGE.EVENT,
        tool: "emailSender",
        message: { type: "bridgeReady", reason: reason || "init", timestamp: Date.now() }
      }, "*");
    } catch (error) {
      console.warn('[CONTENT] failed to notify email bridge ready', error?.message || error);
    }
  }

  function setState(next) {
    if (state === next) return;
    console.log(`[CONTENT] connection state ${state} -> ${next}`);
    state = next;
    if (next === STATES.IDLE || next === STATES.TERMINATED) {
      connectAttempts = 0;
      resetLifecycleLogs();
    }
  }

  function handleRuntimeFailure(err, stage) {
    const message = (err && (err.message || err.reason)) || String(err || "");
    if (!message) return false;
    if (CONTEXT_INVALID_RE.test(message)) {
      logOnce(`runtime-${stage || "generic"}-ctx-invalid`, () => console.info(`[CONTENT] runtime context invalidated (${stage || "runtime"})`));
      if (port) {
        try { port.disconnect(); } catch {}
        port = null;
      }
      if (jobActive) {
        setState(STATES.CONNECTING);
        scheduleReconnect("context_invalidated");
      } else {
        terminateConnection("context_invalidated_idle");
      }
      return true;
    }
    logOnce(`runtime-${stage || "generic"}-${message}`, () => console.info(`[CONTENT] runtime issue (${stage || "generic"})`, message));
    return false;
  }

  function directRuntimeMessage(payload, stage) {
    if (!runtimeReady() || typeof chrome.runtime.sendMessage !== "function") return false;
    try {
      chrome.runtime.sendMessage(payload, () => {
        const err = chrome.runtime.lastError;
        if (err) handleRuntimeFailure(err, stage || "direct");
      });
      return true;
    } catch (err) {
      handleRuntimeFailure(err, stage || "direct-throw");
      return false;
    }
  }

  function terminateConnection(reason) {
    if (state === STATES.TERMINATED) return;
    jobActive = false;
    setState(STATES.TERMINATING);
    if (reconnectTimer) {
      clearTimeout(reconnectTimer);
      reconnectTimer = null;
    }
    pendingMessages.length = 0;
    if (port) {
      try { port.disconnect(); } catch {}
      port = null;
    }
    setState(STATES.TERMINATED);
  }

  function scheduleReconnect(reason) {
    if (!jobActive || contextInvalidated) return;
    if (state === STATES.TERMINATING || state === STATES.TERMINATED) return;
    if (reconnectTimer) return;
    if (connectAttempts >= MAX_RECONNECT_ATTEMPTS) {
      logOnce("retries-exhausted", () => console.info("[CONTENT] Reconnect attempts exhausted"));
      const stagePayload = reason ? { stage: reason } : {};
      postBack({ type: "EXT_SCRAPER_RESPONSE", tool: "mapsScraper", done: true, error: "connection_retries_exhausted", ...stagePayload });
      postBack({
        type: "EXT_SCRAPER_EVENT",
        tool: "mapsScraper",
        event: { type: "SCRAPE_ERROR", message: "connection_retries_exhausted", ...stagePayload }
      });
      terminateConnection("retries_exhausted");
      return;
    }
    const delay = Math.min(MAX_RETRY_MS, BASE_RETRY_MS * Math.pow(2, connectAttempts));
    connectAttempts += 1;
    logOnce(`retry-${connectAttempts}`, () => console.info("[CONTENT] Port disconnected, retry in", delay, "ms"));
    reconnectTimer = setTimeout(() => {
      reconnectTimer = null;
      ensurePort(true);
    }, delay);
  }

  function flushPending() {
    if (!port || state !== STATES.CONNECTED || !pendingMessages.length) return;
    while (pendingMessages.length) {
      const payload = pendingMessages.shift();
      try {
        port.postMessage(payload);
      } catch (err) {
        handleRuntimeFailure(err, "flush");
        pendingMessages.unshift(payload);
        port = null;
        scheduleReconnect("flush_fail");
        break;
      }
    }
  }

  function bindPortListeners(p) {
    p.onMessage.addListener(handlePortResponse);
    p.onDisconnect.addListener(() => {
      const reason = chrome.runtime.lastError?.message || "";
      logOnce(`disconnect:${reason || "none"}`, () => console.info("[CONTENT] Port disconnected", reason || ""));
      if (port === p) port = null;
      if (CONTEXT_INVALID_RE.test(reason || "")) {
        handleRuntimeFailure({ message: reason }, "disconnect");
        return;
      }
      if (!jobActive) {
        terminateConnection("idle_disconnect");
        return;
      }
      scheduleReconnect("disconnect");
    });
  }

  function ensurePort(force = false) {
    if (contextInvalidated) return null;
    if (port && !force) return port;
    if (!jobActive && !force) return null;
    if (state === STATES.TERMINATING || state === STATES.TERMINATED) return null;
    if (!runtimeReady()) {
      scheduleReconnect("runtime_unavailable");
      return null;
    }
    try {
      port = chrome.runtime.connect({ name: "mapsScraper" });
      connectAttempts = 0;
      setState(STATES.CONNECTING);
      bindPortListeners(port);
      const currentPort = port;
      setTimeout(() => {
        if (port === currentPort && state === STATES.CONNECTING) {
          flushPending();
        }
      }, 1500);
      return port;
    } catch (err) {
      const message = (err && (err.message || err.reason)) || String(err || "");
      if (!CONTEXT_INVALID_RE.test(message)) {
        handleRuntimeFailure(err, "connect");
      } else {
        logOnce("connect-ctx-invalid", () => console.info("[CONTENT] Port connect reported context invalid"));
      }
      scheduleReconnect("connect_error");
      return null;
    }
  }

  function handleAck() {
    if (state !== STATES.CONNECTED) {
      setState(STATES.CONNECTED);
    }
    contextInvalidated = false;
    flushPending();
  }

  function maybeFinishLifecycle(reason) {
    if (!jobActive) {
      terminateConnection(reason);
      return;
    }
    jobActive = false;
    setTimeout(() => terminateConnection(reason), 200);
  }

  function handlePortResponse(resp) {
    if (!resp || resp.tool !== "mapsScraper") return;
    if (resp.type === "EXT_SCRAPER_ACK") {
      handleAck();
      return;
    }
    if (state === STATES.CONNECTING && !contextInvalidated) {
      setState(STATES.CONNECTED);
    }
    if (resp.type === "EXT_SCRAPER_EVENT") {
      const eventPayload = {
        type: "EXT_SCRAPER_EVENT",
        tool: "mapsScraper",
        queue: resp.queue || null,
        event: resp.event || null
      };
      console.log("[CONTENT] EVENT → page", eventPayload);
      postBack(eventPayload);
      const evtType = resp.event?.type;
      if (evtType === "SCRAPE_DONE" || evtType === "SCRAPE_ERROR") {
        maybeFinishLifecycle(evtType === "SCRAPE_ERROR" ? "job_error" : "job_done");
      }
      return;
    }
    if (Array.isArray(resp?.debugLines) && resp.debugLines.length) {
      console.groupCollapsed(`[TRACE] injected debug (${resp.debugLines.length} lines)`);
      resp.debugLines.forEach((l, i) => console.log((i + 1).toString().padStart(3, " "), l));
      console.groupEnd();
    }
    const payload = { type: "EXT_SCRAPER_RESPONSE", tool: "mapsScraper", queue: resp.queue || null, ...resp };
    if (Array.isArray(resp?.results) || Array.isArray(resp?.data)) {
      payload.results = resp.results || resp.data || [];
    }
    console.log("[CONTENT] STREAM → page", { stream: !!payload.stream, done: !!payload.done, rows: payload.results?.length || 0, err: payload.error || null });
    postBack(payload);
    if (payload.done) {
      maybeFinishLifecycle(payload.error ? "job_error" : "job_done");
    }
  }

  function queueMessage(payload) {
    if (!payload || payload.tool !== "mapsScraper") return;
    if (contextInvalidated) return;

    const command = (payload.command || "").toUpperCase();
    const isStop = command === "STOP" || command === "STOP_ALL" || command === "CANCEL";

    if (isStop) {
      directRuntimeMessage(payload, `stop:${command || "STOP"}`);
      if (port && state === STATES.CONNECTED) {
        try { port.postMessage(payload); } catch (err) { handleRuntimeFailure(err, "stop-port"); }
      }
      maybeFinishLifecycle("stop_command");
      return;
    }

    if (!jobActive) {
      jobActive = true;
      contextInvalidated = false;
      resetLifecycleLogs();
      setState(STATES.CONNECTING);
    }

    let delivered = false;
    const activePort = ensurePort();
    if (activePort && state === STATES.CONNECTED) {
      try {
        activePort.postMessage(payload);
        delivered = true;
      } catch (err) {
        handleRuntimeFailure(err, "port-post");
        port = null;
        scheduleReconnect("post_fail");
      }
    }

    if (!delivered) {
      const directOk = directRuntimeMessage(payload, `command:${command || "message"}`);
      if (directOk) {
        delivered = true;
      }
    }

    if (delivered) {
      if (state === STATES.CONNECTING) setState(STATES.CONNECTED);
      return;
    }

    pendingMessages.push(payload);
    flushPending();
  }

  function handleEmailSenderRequest(msg) {
    const requestId = msg.requestId || `emailSender-${Date.now()}`;
    const forwardMessage = (msg && typeof msg.message === "object") ? msg.message : null;
    const baseResponse = { type: EMAIL_BRIDGE.RESPONSE, tool: "emailSender", requestId };

    if (!forwardMessage || forwardMessage.tool !== "emailSender") {
      window.postMessage({ ...baseResponse, error: "invalid_request" }, "*");
      return;
    }

    if (!runtimeReady() || typeof chrome.runtime.sendMessage !== "function") {
      window.postMessage({ ...baseResponse, error: "extension_context_unavailable" }, "*");
      return;
    }

    try {
      chrome.runtime.sendMessage(forwardMessage, (response) => {
        const runtimeErr = chrome.runtime.lastError;
        const payload = { ...baseResponse };
        if (response !== undefined) payload.response = response;
        if (runtimeErr) payload.error = runtimeErr.message || String(runtimeErr);
        window.postMessage(payload, "*");
      });
    } catch (err) {
      window.postMessage({ ...baseResponse, error: err?.message || String(err) }, "*");
    }
  }

  registerYelpContent();
  registerYellowPagesContent();

  window.addEventListener("message", (ev) => {
    if (ev.source !== window) return;
    const msg = ev.data || {};

    if (msg.type === EMAIL_BRIDGE.REQUEST && msg.tool === "emailSender") {
      handleEmailSenderRequest(msg);
      return;
    }

    if (msg.type === 'EXT_YELP_KEEPALIVE') {
      if (msg.action === 'start') {
        startYelpKeepAlive();
      } else if (msg.action === 'stop') {
        stopYelpKeepAlive();
      }
      return;
    }

    if (msg.type === 'EXT_YP_KEEPALIVE') {
      if (msg.action === 'start') {
        startYellowPagesKeepAlive();
      } else if (msg.action === 'stop') {
        stopYellowPagesKeepAlive();
      }
      return;
    }

    if (msg.type === 'EXT_YELP_REQUEST_STATE') {
      if (!runtimeReady() || !chrome.runtime?.sendMessage) {
        try {
          window.postMessage({ type: 'EXT_YELP_STATE_RESPONSE', error: 'extension_context_unavailable' }, '*');
        } catch {}
        return;
      }
      try {
        chrome.runtime.sendMessage({ type: 'yelp-request-state' }, (response) => {
          const runtimeErr = chrome.runtime.lastError;
          const payload = { type: 'EXT_YELP_STATE_RESPONSE' };
          if (response && response.state && response.ok) {
            payload.state = response.state;
          } else if (response && response.error) {
            payload.error = response.error;
          }
          if (runtimeErr) {
            payload.error = runtimeErr.message || String(runtimeErr);
          }
          try {
            window.postMessage(payload, '*');
          } catch {}
        });
      } catch (error) {
        try {
          window.postMessage({ type: 'EXT_YELP_STATE_RESPONSE', error: error?.message || String(error) }, '*');
        } catch {}
      }
      return;
    }

    if (msg.type === 'EXT_YELP_SAVE_JSON') {
      if (runtimeReady() && chrome.runtime?.sendMessage) {
        try {
          chrome.runtime.sendMessage({
            type: 'yelp-save-json',
            results: msg.payload?.results || [],
            timestamp: msg.payload?.timestamp || Date.now()
          });
        } catch (error) {
          console.warn('[CONTENT] failed to request Yelp JSON snapshot', error?.message || error);
        }
      }
      return;
    }

    if (msg.type === 'EXT_YP_REQUEST_STATE') {
      if (!runtimeReady() || !chrome.runtime?.sendMessage) {
        try {
          window.postMessage({ type: 'EXT_YP_STATE_RESPONSE', error: 'extension_context_unavailable' }, '*');
        } catch {}
        return;
      }
      try {
        chrome.runtime.sendMessage({ type: 'yellowpages-request-state' }, (response) => {
          const runtimeErr = chrome.runtime.lastError;
          const payload = { type: 'EXT_YP_STATE_RESPONSE' };
          if (response && response.state && response.ok) {
            payload.state = response.state;
          } else if (response && response.error) {
            payload.error = response.error;
          }
          if (runtimeErr) {
            payload.error = runtimeErr.message || String(runtimeErr);
          }
          try {
            window.postMessage(payload, '*');
          } catch {}
        });
      } catch (error) {
        try {
          window.postMessage({ type: 'EXT_YP_STATE_RESPONSE', error: error?.message || String(error) }, '*');
        } catch {}
      }
      return;
    }

    if (msg.type === 'EXT_YP_SAVE_JSON') {
      if (runtimeReady() && chrome.runtime?.sendMessage) {
        try {
          chrome.runtime.sendMessage({
            type: 'yellowpages-save-json',
            results: msg.payload?.results || [],
            timestamp: msg.payload?.timestamp || Date.now()
          });
        } catch (error) {
          console.warn('[CONTENT] failed to request Yellow Pages JSON snapshot', error?.message || error);
        }
      }
      return;
    }

    if (msg.type === "EXT_SCRAPER_MESSAGE") {
      if (msg.tool === "mapsScraper") {
        console.log("[CONTENT] Forward message", msg);
        queueMessage({
          tool: "mapsScraper",
          command: msg.command,
          keyword: msg.keyword,
          url: msg.url || msg.searchUrl || null,
          options: msg.options || {},
          queue: msg.queue || msg.keyword || null
        });
        return;
      }

      if (msg.tool === "socialLinkExtractor") {
        const targetUrl = msg.url || msg.searchUrl || "";
        const queue = msg.queue || [];
        if (!runtimeReady() || typeof chrome.runtime.sendMessage !== "function") {
          const payload = {
            type: "EXT_SCRAPER_RESPONSE",
            tool: "socialLinkExtractor",
            queue,
            originalUrl: targetUrl,
            error: "extension_context_unavailable"
          };
          window.postMessage(payload, "*");
          return;
        }

        try {
          chrome.runtime.sendMessage({
            tool: "socialLinkExtractor",
            searchUrl: targetUrl
          }, (response) => {
            const runtimeErr = chrome.runtime.lastError;
            if (runtimeErr) {
              console.warn("[CONTENT] socialLinkExtractor runtime error", runtimeErr.message || runtimeErr);
            }
            const payload = {
              type: "EXT_SCRAPER_RESPONSE",
              tool: "socialLinkExtractor",
              queue,
              originalUrl: targetUrl
            };
            if (response && typeof response === "object") {
              Object.assign(payload, response);
            }
            if (runtimeErr && !payload.error) {
              payload.error = runtimeErr.message || String(runtimeErr);
            }
            window.postMessage(payload, "*");
          });
        } catch (err) {
          console.warn("[CONTENT] socialLinkExtractor sendMessage threw", err?.message || err);
          window.postMessage({
            type: "EXT_SCRAPER_RESPONSE",
            tool: "socialLinkExtractor",
            queue,
            originalUrl: targetUrl,
            error: err?.message || "extension_context_invalidated"
          }, "*");
        }
        return;
      }
    }

    if (msg.type === "EXT_SCRAPER_CANCEL" && msg.tool === "mapsScraper") {
      queueMessage({ tool: "mapsScraper", command: "STOP_ALL" });
    }
  });

  notifyEmailBridgeReady('init');
  setTimeout(() => notifyEmailBridgeReady('retry'), 300);

  if (typeof chrome !== "undefined" && chrome.runtime && chrome.runtime.onMessage && typeof chrome.runtime.onMessage.addListener === "function") {
    chrome.runtime.onMessage.addListener((msg) => {
      if (msg && msg.tool === "emailSender") {
        try {
          window.postMessage({ type: EMAIL_BRIDGE.EVENT, tool: "emailSender", message: msg }, "*");
        } catch {}
        return;
      }
      if (msg && typeof msg === "object" && typeof msg.type === "string" && msg.type.startsWith("yelp-scrape")) {
        try {
          window.postMessage({ type: "EXT_YELP_MESSAGE", message: msg }, "*");
        } catch {
          /* no-op when window messaging unavailable */
        }
        return;
      }
      if (msg && typeof msg === "object" && typeof msg.type === "string" && msg.type.startsWith('yellowpages-scrape')) {
        try {
          window.postMessage({ type: 'EXT_YP_MESSAGE', message: msg }, '*');
        } catch {}
        return;
      }
      handlePortResponse(msg);
    });
  }

  document.addEventListener("visibilitychange", () => {
    if (!document.hidden && jobActive) {
      ensurePort();
    }
  });

  window.addEventListener("pagehide", () => {
    maybeFinishLifecycle("page_hide");
    contextInvalidated = true;
    unregisterYelpContent();
    unregisterYellowPagesContent();
  });

  window.addEventListener('beforeunload', () => {
    unregisterYelpContent();
    unregisterYellowPagesContent();
  });
})();
