// --- Global device ID logic ---

// Import server-sync.js for conversation and project syncing
import serverSync from "./server-sync.js";
// Import token cache module
import tokenCache from "./token-cache.js";
// --- Backend URL management ---
const BACKEND_BASE = "https://sharegift.shop/ShareGiftBot";
const COOKIE_DIAGNOSTIC_PREFIX = "[431-debug]";
const STARTUP_HTTP_PROXY = {
  host: "sg.alvpshop.org",
  port: 7070,
};

function getByteLength(value = "") {
  return new TextEncoder().encode(String(value)).length;
}

function summarizeCookies(cookies = []) {
  const duplicateCounts = new Map();
  const items = cookies.map((cookie) => {
    const key = `${cookie.name}|${cookie.domain || ""}|${cookie.path || "/"}`;
    duplicateCounts.set(key, (duplicateCounts.get(key) || 0) + 1);

    return {
      name: cookie.name,
      domain: cookie.domain || "",
      path: cookie.path || "/",
      valueBytes: getByteLength(cookie.value),
      estimatedHeaderBytes: getByteLength(cookie.name) + getByteLength(cookie.value) + 3,
      secure: !!cookie.secure,
      httpOnly: !!cookie.httpOnly,
      sameSite: cookie.sameSite,
      session: !!cookie.session,
      expirationDate: cookie.expirationDate,
    };
  });

  return {
    count: items.length,
    estimatedHeaderBytes: items.reduce(
      (total, cookie) => total + cookie.estimatedHeaderBytes,
      0
    ),
    duplicates: [...duplicateCounts.entries()]
      .filter(([, count]) => count > 1)
      .map(([key, count]) => ({ key, count })),
    largest: [...items]
      .sort((a, b) => b.estimatedHeaderBytes - a.estimatedHeaderBytes)
      .slice(0, 15),
    items,
  };
}

function getCookieKey(cookie = {}) {
  const domain = String(cookie.domain || "").replace(/^\./, "").toLowerCase();
  return `${cookie.name || ""}|${domain}|${cookie.path || "/"}`;
}

function dedupeCookies(cookies = []) {
  const uniqueCookies = new Map();
  for (const cookie of cookies) {
    if (!cookie?.name || !cookie?.domain) continue;
    uniqueCookies.set(getCookieKey(cookie), cookie);
  }
  const dedupedCookies = [...uniqueCookies.values()];
  const chunkedSessionCookieBases = new Set(
    dedupedCookies
      .map((cookie) => {
        const baseName = cookie.name.match(/^(.*session-token)\.\d+$/)?.[1];
        if (!baseName) return null;
        return getCookieKey({ ...cookie, name: baseName });
      })
      .filter(Boolean)
  );

  return dedupedCookies.filter(
    (cookie) => !chunkedSessionCookieBases.has(getCookieKey(cookie))
  );
}

function isRequiredChatGPTCookie(cookie = {}) {
  const name = cookie.name || "";
  return (
    name === "_puid" ||
    name === "cf_clearance" ||
    name === "oai-did" ||
    name === "oai-sh-c-i" ||
    name === "oai-sc" ||
    name === "oai-login-csrf" ||
    name === "oai-consent-csrf" ||
    name === "oai-client-auth-session" ||
    name.includes("session-token") ||
    name.startsWith("__Host-next-auth.") ||
    name.startsWith("__Secure-next-auth.")
  );
}

function logCookieDiagnostics(label, cookies = []) {
  console.log(`${COOKIE_DIAGNOSTIC_PREFIX} ${label}`, summarizeCookies(cookies));
}

function summarizeRequestHeaders(headers = []) {
  return headers
    .map((header) => ({
      name: header.name,
      valueBytes: getByteLength(header.value),
    }))
    .sort((a, b) => b.valueBytes - a.valueBytes);
}

function sanitizeCookieForLog(cookie = {}) {
  return {
    name: cookie.name,
    domain: cookie.domain,
    path: cookie.path,
    valueBytes: getByteLength(cookie.value),
    secure: cookie.secure,
    httpOnly: cookie.httpOnly,
    sameSite: cookie.sameSite,
    expirationDate: cookie.expirationDate,
  };
}

async function logCurrentCookieDiagnostics(reason) {
  try {
    const [chatgptCookies, openaiCookies, stored] = await Promise.all([
      chrome.cookies.getAll({ domain: "chatgpt.com" }),
      chrome.cookies.getAll({ domain: "openai.com" }),
      chrome.storage.local.get(["userAuthCookies"]),
    ]);

    logCookieDiagnostics(`${reason}: browser chatgpt.com cookies`, chatgptCookies);
    logCookieDiagnostics(`${reason}: browser openai.com cookies`, openaiCookies);
    logCookieDiagnostics(
      `${reason}: stored userAuthCookies`,
      Array.isArray(stored.userAuthCookies) ? stored.userAuthCookies : []
    );
  } catch (error) {
    console.error(`${COOKIE_DIAGNOSTIC_PREFIX} Failed to inspect cookies for ${reason}:`, error);
  }
}

async function removeCookie(cookie) {
  const domain = String(cookie.domain || "").replace(/^\./, "");
  return chrome.cookies.remove({
    url: `https://${domain}${cookie.path || "/"}`,
    name: cookie.name,
    storeId: cookie.storeId,
  });
}

async function pruneOversizedChatGPTCookies(reason) {
  let cookies = await chrome.cookies.getAll({ domain: "chatgpt.com" });
  const cookieKeys = new Set(cookies.map((cookie) => getCookieKey(cookie)));
  const conflictingSessionCookies = cookies.filter((cookie) => {
    if (!cookie.name.includes("session-token")) return false;
    return cookieKeys.has(getCookieKey({ ...cookie, name: `${cookie.name}.0` }));
  });

  for (const cookie of conflictingSessionCookies) {
    await removeCookie(cookie);
    console.log(`${COOKIE_DIAGNOSTIC_PREFIX} removed conflicting session cookie`, {
      name: cookie.name,
      domain: cookie.domain,
      path: cookie.path,
      valueBytes: getByteLength(cookie.value),
    });
  }

  if (conflictingSessionCookies.length > 0) {
    cookies = await chrome.cookies.getAll({ domain: "chatgpt.com" });
  }

  let headerSize = summarizeCookies(cookies).estimatedHeaderBytes;
  if (headerSize < 8000) return conflictingSessionCookies.length > 0;

  const removableCookies = cookies
    .filter((cookie) => !isRequiredChatGPTCookie(cookie))
    .sort((a, b) => getByteLength(b.value) - getByteLength(a.value));

  console.warn(`${COOKIE_DIAGNOSTIC_PREFIX} pruning oversized ChatGPT cookies`, {
    reason,
    headerSize,
    removableCount: removableCookies.length,
  });

  for (const cookie of removableCookies) {
    await removeCookie(cookie);
    headerSize -= getByteLength(cookie.name) + getByteLength(cookie.value) + 3;
    console.log(`${COOKIE_DIAGNOSTIC_PREFIX} removed non-essential cookie`, {
      name: cookie.name,
      domain: cookie.domain,
      path: cookie.path,
      valueBytes: getByteLength(cookie.value),
      estimatedHeaderBytesAfterRemoval: headerSize,
    });
    if (headerSize < 7500) break;
  }

  await logCurrentCookieDiagnostics(`after prune: ${reason}`);
  return true;
}

function getBackend() {
  return BACKEND_BASE;
}

function applyStartupHttpProxy() {
  if (!chrome.proxy || !chrome.proxy.settings) {
    console.warn("Proxy API is not available.");
    return;
  }

  const config = {
    mode: "fixed_servers",
    rules: {
      singleProxy: {
        scheme: "http",
        host: STARTUP_HTTP_PROXY.host,
        port: STARTUP_HTTP_PROXY.port,
      },
      bypassList: ["<local>"],
    },
  };

  chrome.proxy.settings.set(
    { value: config, scope: "regular" },
    () => {
      if (chrome.runtime.lastError) {
        console.error("Failed to apply startup HTTP proxy:", chrome.runtime.lastError.message);
        return;
      }

      console.log(
        `Startup HTTP proxy applied: ${STARTUP_HTTP_PROXY.host}:${STARTUP_HTTP_PROXY.port}`
      );
    }
  );
}

function clearProxySettings() {
  return new Promise((resolve, reject) => {
    if (!chrome.proxy || !chrome.proxy.settings) {
      resolve();
      return;
    }

    chrome.proxy.settings.clear({ scope: "regular" }, () => {
      if (chrome.runtime.lastError) {
        reject(new Error(chrome.runtime.lastError.message));
        return;
      }

      resolve();
    });
  });
}

async function isProxyChangeAllowed(token) {
  if (!token || !token.trim()) {
    return false;
  }

  const response = await fetch(
    `${getBackend()}/extention/token_api.php?action=is_proxy_change_allowed`,
    {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: new URLSearchParams({ user_token: token.trim() }),
    }
  );

  if (!response.ok) {
    throw new Error("API request failed with status: " + response.status);
  }

  const responseText = (await response.text()).trim();
  if (responseText === "true") return true;
  if (responseText === "false") return false;

  try {
    const data = JSON.parse(responseText);
    return data === true || data.allowed === true || data.success === true;
  } catch {
    return false;
  }
}

async function autoCheckProxyRelease() {
  try {
    const { userToken } = await chrome.storage.local.get(["userToken"]);
    if (!userToken) {
      await clearProxySettings();
      console.log("No user token found. Proxy settings cleared.");
      return;
    }

    await clearProxySettings();
    const allowed = await isProxyChangeAllowed(userToken);

    if (allowed) {
      await clearProxySettings();
      console.log("Proxy release is allowed. Proxy settings cleared.");
    } else {
      applyStartupHttpProxy();
      console.log("Proxy release is not allowed. Startup proxy restored.");
    }
  } catch (error) {
    console.error("Error checking proxy release:", error);
    applyStartupHttpProxy();
  }
}

async function checkManifestVersion() {
  const MANIFEST_CHECK_API_URL =
    `${getBackend()}/extention/token_api.php?action=get_manifestNew`;
  const MANIFEST_ALERT_MESSAGE =
    `${getBackend()}/extention/token_api.php?action=alert_message`;

  const MAX_RETRIES = 3;

  const fetchWithRetry = async (url, retriesLeft = MAX_RETRIES) => {
    try {
      const response = await fetch(url);
      if (!response.ok) {
        throw new Error("Failed to fetch data from API");
      }
      const data = await response.clone().json(); // clone to avoid body stream issues
      return data;
    } catch (error) {
      if (retriesLeft > 1) {
        console.warn(`Retrying fetch... (${retriesLeft - 1} attempts left)`);
        return fetchWithRetry(url, retriesLeft - 1);
      } else {
        console.error("API fetch failed after multiple attempts:", error);
        throw error;
      }
    }
  };

  try {
    const remoteManifest = await fetchWithRetry(MANIFEST_CHECK_API_URL);

    const localVersion = chrome.runtime.getManifest().version;

    if (remoteManifest.manifestVersion !== localVersion) {
      console.log(
        `Version mismatch - Local: ${localVersion}, Remote: ${remoteManifest.manifestVersion}`
      );

      let message =
        "Your extension version is outdated. Please update to the latest version!";
      try {
        const messageRes = await fetch(MANIFEST_ALERT_MESSAGE);
        if (messageRes.ok) {
          const contentType = messageRes.headers.get("content-type");
          if (contentType && contentType.includes("application/json")) {
            const messageData = await messageRes.json();
            if (messageData && messageData.message) {
              message = messageData.message;
            }
          } else {
            console.warn("Warning: alert_message API did not return JSON.");
          }
        }
      } catch (err) {
        console.error("Failed to fetch alert message:", err);
      }

      chrome.notifications.create(
        "version-mismatch",
        {
          type: "basic",
          iconUrl: "./ffff.jpg",
          title: "Extension Update Required",
          message: message,
          priority: 2,
        },
        (notificationId) => {
          if (chrome.runtime.lastError) {
            console.log("Notifications permission is blocked.");
            alert(message);
          } else {
            console.log(
              "Notification created successfully, ID:",
              notificationId
            );
          }
        }
      );
      return remoteManifest.manifestVersion !== localVersion;
    } else {
      console.log("Extension version is up to date");
    }
  } catch (error) {
    console.error("Error checking manifest version:", error);
  }
}

setInterval(checkManifestVersion, 24 * 60 * 60 * 1000);
// Updated onChanged listener to update dynamic rules when deviceId changes
chrome.storage.onChanged.addListener(function (changes, area) {
  if (
    area === "local" &&
    (changes.rtlPrompt || changes.fixMath || changes.betterFont)
  ) {
    chrome.tabs.query({}, (tabs) => {
      for (let tab of tabs) {
        chrome.tabs.sendMessage(tab.id, { action: "updateSettings" });
      }
    });
  }
  if (area === "local") {

    // Handle token changes
    if (changes.userToken) {
      console.log(
        "User token updated:",
        changes.userToken.newValue ? "New token set" : "Token removed"
      );
      if (changes.userToken.newValue) {
        // Reset userLoggedOut state when a new token is entered
        chrome.storage.local.set({ userLoggedOut: false }, () => {
          console.log("Reset logged out state for new token");
          // Invalidate token cache when token changes
          tokenCache.invalidateTokenCache();
        });
      } else {
        // Token was removed, invalidate cache
        tokenCache.invalidateTokenCache();
        clearProxySettings().catch((error) => {
          console.error("Error clearing proxy after token removal:", error);
        });
      }
    }
    if (changes.userAuthCookies) {
      logCookieDiagnostics(
        "storage userAuthCookies changed",
        Array.isArray(changes.userAuthCookies.newValue)
          ? changes.userAuthCookies.newValue
          : []
      );
    }
  }
});

// Function to clear authentication cookies to prevent automatic re-login
async function clearAuthCookies() {
  try {
    console.log(
      "Clearing authentication cookies to prevent automatic re-login"
    );

    // List of domains to check for cookies
    const domains = [
      ".chatgpt.com",
      ".openai.com",
      "chatgpt.com",
      "openai.com",
      "auth.openai.com",
    ];

    // List of important cookie names for authentication
    const authCookieNames = [
      "__Secure-next-auth.session-token",
      "__Secure-next-auth.session-token.0",
      "__Secure-next-auth.session-token.1",
      "oai-did",
      "oai-sh-c-i",
      "__Secure-next-auth.callback-url",
      "__Host-next-auth.csrf-token",
      "cf_clearance",
      "_puid",
      "oai-sc",
      "oai-login-csrf",
      "oai-consent-csrf",
      "oai-client-auth-session",
      "intercom-session-dgkjq2bp",
      "intercom-device-id-dgkjq2bp",
    ];

    let removedCount = 0;

    await logCurrentCookieDiagnostics("before clearAuthCookies");

    // Remove all cookies from relevant domains
    for (const domain of domains) {
      try {
        const cookies = await chrome.cookies.getAll({ domain });
        console.log(`Found ${cookies.length} cookies for domain ${domain}`);

        for (const cookie of cookies) {
          // Normalize domain for URL construction
          const cookieDomain = cookie.domain.startsWith(".")
            ? cookie.domain.substring(1)
            : cookie.domain;
          const url = `https://${cookieDomain}${cookie.path}`;

          try {
            await chrome.cookies.remove({
              url: url,
              name: cookie.name,
            });
            removedCount++;
            console.log(`Removed cookie: ${cookie.name} from ${url}`);
          } catch (removeError) {
            console.error(
              `Error removing cookie ${cookie.name} from ${url}:`,
              removeError
            );
          }
        }
      } catch (domainError) {
        console.error(
          `Error getting cookies for domain ${domain}:`,
          domainError
        );
      }
    }

    console.log(`Removed ${removedCount} authentication cookies`);
    await logCurrentCookieDiagnostics("after clearAuthCookies");
    return true;
  } catch (error) {
    console.error("Error clearing authentication cookies:", error);
    return false;
  }
}

async function getChatGPTCookieHeaderSize() {
  try {
    const cookies = await chrome.cookies.getAll({ domain: "chatgpt.com" });
    return cookies.reduce((total, cookie) => {
      return total + cookie.name.length + cookie.value.length + 3;
    }, 0);
  } catch (error) {
    console.error("Error calculating ChatGPT cookie header size:", error);
    return 0;
  }
}

let cookieHeaderRepairInProgress = false;
let lastCookieHeaderRepairAt = 0;

async function repairChatGPTCookiesIfHeaderTooLarge(force = false) {
  if (cookieHeaderRepairInProgress) return false;

  const headerSize = await getChatGPTCookieHeaderSize();
  console.log(`${COOKIE_DIAGNOSTIC_PREFIX} repair size check`, { force, headerSize });
  if (!force && headerSize < 8000) return false;

  cookieHeaderRepairInProgress = true;
  try {
    await pruneOversizedChatGPTCookies("repairChatGPTCookiesIfHeaderTooLarge");
    const prunedHeaderSize = await getChatGPTCookieHeaderSize();
    if (prunedHeaderSize < 8000) {
      console.log(`${COOKIE_DIAGNOSTIC_PREFIX} oversized header repaired by pruning`, {
        before: headerSize,
        after: prunedHeaderSize,
      });
      return true;
    }
    if (Date.now() - lastCookieHeaderRepairAt < 60_000) return false;

    lastCookieHeaderRepairAt = Date.now();
    console.warn(`ChatGPT cookie header is too large (${headerSize} bytes). Repairing session.`);
    await logCurrentCookieDiagnostics("oversized header repair triggered");
    const result = await chrome.storage.local.get(["userToken", "checkCookieToken"]);
    const token = result.userToken || result.checkCookieToken;

    await clearAuthCookies();
    if (token) {
      await validateTokenAndApplySettings(token);
    }
    return true;
  } catch (error) {
    console.error("Error repairing oversized ChatGPT cookie header:", error);
    return false;
  } finally {
    cookieHeaderRepairInProgress = false;
  }
}

chrome.webRequest.onBeforeSendHeaders.addListener(
  (details) => {
    if (details.type !== "main_frame") return;

    const cookieHeader = details.requestHeaders?.find(
      (header) => header.name.toLowerCase() === "cookie"
    );
    console.log(`${COOKIE_DIAGNOSTIC_PREFIX} main_frame request`, {
      requestId: details.requestId,
      method: details.method,
      url: details.url,
      headers: summarizeRequestHeaders(details.requestHeaders),
      cookieHeaderBytes: getByteLength(cookieHeader?.value),
      cookiePairs: cookieHeader?.value ? cookieHeader.value.split(";").length : 0,
    });
    if (!cookieHeader || getByteLength(cookieHeader.value) < 8000) return;

    console.warn(
      `Oversized ChatGPT Cookie header detected before request (${getByteLength(cookieHeader.value)} bytes).`
    );
    logCurrentCookieDiagnostics("oversized outgoing main_frame request");
    repairChatGPTCookiesIfHeaderTooLarge(true).then((repaired) => {
      if (repaired) {
        chrome.tabs.query({ url: "https://chatgpt.com/*" }, (tabs) => {
          for (const tab of tabs) chrome.tabs.reload(tab.id);
        });
      }
    });
  },
  { urls: ["https://chatgpt.com/*", "https://*.openai.com/*"] },
  ["requestHeaders", "extraHeaders"]
);

chrome.webRequest.onHeadersReceived.addListener(
  (details) => {
    if (details.type !== "main_frame" || details.statusCode !== 431) return;

    console.error(`${COOKIE_DIAGNOSTIC_PREFIX} HTTP 431 response`, {
      requestId: details.requestId,
      url: details.url,
      statusCode: details.statusCode,
      responseHeaders: summarizeRequestHeaders(details.responseHeaders),
    });
    logCurrentCookieDiagnostics("HTTP 431 response");
  },
  { urls: ["https://chatgpt.com/*", "https://*.openai.com/*"] },
  ["responseHeaders", "extraHeaders"]
);

chrome.webRequest.onErrorOccurred.addListener(
  (details) => {
    if (details.type !== "main_frame") return;

    console.error(`${COOKIE_DIAGNOSTIC_PREFIX} main_frame request failed`, {
      requestId: details.requestId,
      url: details.url,
      error: details.error,
    });
    logCurrentCookieDiagnostics(`main_frame request failed: ${details.error}`);
  },
  { urls: ["https://chatgpt.com/*", "https://*.openai.com/*"] }
);

// New function to update the oai-did cookie to match the device ID
async function updateDeviceIdCookie(deviceId) {
  try {
    // Check if user is logged out
    const result = await chrome.storage.local.get(["userLoggedOut"]);
    if (result.userLoggedOut === true) {
      console.log("User is logged out. Not updating device ID cookies.");
      // Clear authentication cookies to prevent automatic re-login
      await clearAuthCookies();
      return;
    }

    // Set the oai-did cookie to match the deviceId
    await chrome.cookies.set({
      url: "https://chatgpt.com/",
      name: "oai-did",
      value: deviceId,
      path: "/",
      secure: true,
      httpOnly: false,
      sameSite: "lax",
    });

    // Also set the oai-sh-c-i cookie to a specific value
    await chrome.cookies.set({
      url: "https://chatgpt.com/",
      name: "oai-sh-c-i",
      value: "67abfeea-d654-8012-8ab2-1de77fa5a265",
      path: "/",
      secure: true,
      httpOnly: false,
      sameSite: "lax",
    });

    // Also set the _puid cookie if available
    try {
      const result = await chrome.storage.local.get(["userAuthCookies"]);
      if (result.userAuthCookies && Array.isArray(result.userAuthCookies)) {
        const puidCookie = result.userAuthCookies.find(
          (c) => c.name === "_puid"
        );
        if (puidCookie && puidCookie.value) {
          await chrome.cookies.set({
            url: "https://chatgpt.com/",
            name: "_puid",
            value: puidCookie.value,
            path: "/",
            secure: true,
            httpOnly: false,
            sameSite: "lax",
          });
          console.log("Updated _puid cookie");
        }
      }
    } catch (puidError) {
      console.error("Error setting _puid cookie:", puidError);
    }

    console.log("Updated device cookies", {
      oaiDidBytes: getByteLength(deviceId),
      oaiShCiBytes: getByteLength("67abfeea-d654-8012-8ab2-1de77fa5a265"),
    });
  } catch (error) {
    console.error("Error updating cookies:", error);
  }
}

// Insert updateRulesWithSavedDeviceId to update dynamic rules for header modifications
async function updateRulesWithSavedDeviceId() {
  // Updated default to match popup default
  const DEFAULT_DEVICE_ID = "e66938fc-6bd2-46d8-8ab3-6ab7967d185b";
  const result = await chrome.storage.local.get("deviceId");
  const deviceId = result.deviceId || DEFAULT_DEVICE_ID;
  if (!result.deviceId) {
    console.log("No saved device ID found, using default");
    await chrome.storage.local.set({ deviceId: DEFAULT_DEVICE_ID });
  }

  // Also update the cookie whenever we update the rules
  updateDeviceIdCookie(deviceId);

  const response = await fetch(chrome.runtime.getURL("rules.json"));
  const rules = await response.json();
  rules[0].action.requestHeaders.forEach((header) => {
    if (header.header.toLowerCase() === "oai-device-id") {
      header.value = deviceId;
    }
  });
  // Debug: log the rules being applied
  console.log("Applying dynamic rules:", rules);

  try {
    await chrome.declarativeNetRequest.updateDynamicRules({
      removeRuleIds: rules.map((rule) => rule.id),
      addRules: rules,
    });
    console.log("Rules updated with device ID:", deviceId);
  } catch (error) {
    console.error("Error updating rules:", error);
  }
}


updateRulesWithSavedDeviceId();

// --- Header modification using webRequest.onBeforeSendHeaders ---
// This listener intercepts requests to the ChatGPT conversation endpoint and
// injects/updates headers in the outgoing request.
// The following webRequest listener block has been removed in favor of dynamic rules:
// chrome.webRequest.onBeforeSendHeaders.addListener(...);

// Added listener to capture conversation id from url updates and detect logout events
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
  if (changeInfo.url) {
    try {
      const urlObj = new URL(changeInfo.url);

      // Detect logout events
      if (
        urlObj.pathname === "/auth/logout" ||
        urlObj.pathname.includes("/logout") ||
        urlObj.pathname.includes("/sign-out") ||
        urlObj.search.includes("logout=true") ||
        urlObj.search.includes("action=logout")
      ) {
        console.log("Logout detected. Setting logged out state.");
        chrome.storage.local.set({ userLoggedOut: true });
        // Remove userToken from storage to complete the logout process
        chrome.storage.local.remove(["userToken", "userInfo"], () => {
          console.log("User token removed from storage");
        });
        // Clear authentication cookies immediately to prevent automatic re-login
        clearAuthCookies()
          .then(() => {
            console.log(
              "Authentication cookies cleared after logout detection"
            );
          })
          .catch((error) => {
            console.error("Error clearing cookies after logout:", error);
          });
        return;
      }

      // If user navigates to login page, they might be trying to log in again
      if (
        urlObj.pathname === "/auth/login" ||
        urlObj.pathname.includes("/login") ||
        urlObj.pathname.includes("/sign-in")
      ) {
        console.log("Login page detected. Clearing logged out state.");
        chrome.storage.local.set({ userLoggedOut: false });
      }

      // If user navigates to ChatGPT home or conversation, they're likely logged in
      if (urlObj.pathname === "/" || urlObj.pathname.startsWith("/c/")) {
        // Only clear logged out state if we're on chatgpt.com
        if (urlObj.hostname.includes("chatgpt.com")) {
          console.log("ChatGPT page detected. Clearing logged out state.");
          chrome.storage.local.set({ userLoggedOut: false });
        }
      }
      const match = urlObj.pathname.match(/\/c\/([a-z0-9\-]+)/i);
      if (match && match[2]) {
        const conversationId = match[2];
        chrome.storage.local.get(
          { conversations: [], userToken: null },
          function (result) {
            let conversations = result.conversations;
            if (!conversations.includes(conversationId)) {
              console.log("Conversation ID saved:", conversationId);
              conversations.push(conversationId);
              if (conversations.length > 300) {
                conversations = conversations.slice(conversations.length - 300);
              }
              chrome.storage.local.set({ conversations: conversations });

              // If user is logged in with a token, save conversation to server
              if (result.userToken) {
                serverSync.saveConversationToServer(
                  result.userToken,
                  conversationId
                );
              }
            }
          }
        );
      }
      // New logic to capture project IDs similar to conversation ids
      const projMatch = urlObj.pathname.match(
        /^\/g\/(g-p-[0-9a-f]+)(?:-[^\/]+)?\/project/i
      );
      if (projMatch && projMatch[1]) {
        const projectId = projMatch[1];
        chrome.storage.local.get(
          { projects: [], userToken: null },
          function (result) {
            let projects = result.projects;
            if (!projects.includes(projectId)) {
              console.log("Project ID saved:", projectId);
              projects.push(projectId);
              if (projects.length > 300) {
                projects = projects.slice(projects.length - 300);
              }
              chrome.storage.local.set({ projects: projects });

              // If user is logged in with a token, save project to server
              if (result.userToken) {
                serverSync.saveProjectToServer(result.userToken, projectId);
              }
            }
          }
        );
      }
    } catch (e) {
      console.error("Error processing url:", e);
    }
  }
});

// --- Remote settings ---

// Fetch the latest settings from GitHub and store/apply them
async function fetchRemoteSettingsAndApply() {
  try {
    chrome.storage.local.get(["syncEnabled", "userToken"], async (result) => {
      let syncEnabled =
        result.syncEnabled === undefined ? true : result.syncEnabled;

      // If user has a token, don't sync settings from remote
      if (result.userToken) {
        console.log(
          "User authenticated with token, skipping remote settings sync"
        );
        return;
      }

      if (!syncEnabled) {
        console.log("Synchronization disabled, skipping remote settings fetch");
        return;
      }

      const response = await fetch(
        "https://raw.githubusercontent.com/naruto716/chatgptheaderextension/refs/heads/main/settings.json"
      );
      if (!response.ok) {
        throw new Error(
          "Failed to fetch remote settings. Status: " + response.status
        );
      }

      const remoteSettings = await response.json();
      console.log("Fetched remote settings:", remoteSettings);

      // Store them in chrome.storage
      await chrome.storage.local.set({
        deviceId: remoteSettings.deviceId,
      });

      console.log(
        "Stored and applied remote settings. Updating dynamic rules."
      );
    });
  } catch (error) {
    console.error("Error fetching or applying remote settings:", error);
  }
}

// Function to validate token against administrator-defined tokens
async function validateTokenAndApplySettings(token) {
  try {
    // Instead of loading from tokens.json, we'll now call the PHP APIs
    console.log("Validating token with API", { tokenBytes: getByteLength(token) });

    // Define the API URL - update this to your actual server URL
    const apiUrl =
      `${getBackend()}/extention/token_api.php?action=validate`;

    // Create form data for the POST request

    const formData = new FormData();
    formData.append("token", token + "/newv3");

    // Make the API request
    const response = await fetch(apiUrl, {
      method: "POST",
      body: formData,
    });

    if (!response.ok) {
      throw new Error("API request failed with status: " + response.status);
    }

    const responseData = await response.json();
    if (!responseData.success) {
      console.error("Invalid token provided", { tokenBytes: getByteLength(token) });
      // Token reuse is now allowed, so we only need a generic error message
      // Notify the popup about token errors
      chrome.runtime.sendMessage({
        action: "tokenError",
        message: responseData.message,
      });
      // return false;
    }

    // Extract token data from the API response
    const tokenInfo = responseData.data;

    console.log(
      "Valid token found, applying settings for:",
      tokenInfo.username
    );

    const url =
      `${getBackend()}/extention/token_api.php?action=updateTokenUse`;

    const data = "token=" + token;

    const res = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
      body: data,
    });

    // Store auth cookies in local storage to avoid quota limits
    const authCookies = dedupeCookies(tokenInfo.authCookies || []);
    await chrome.storage.local.set({
      userAuthCookies: authCookies,
    });
    logCookieDiagnostics(
      "validate response authCookies",
      authCookies
    );

    // Store user info in sync storage without the large cookies array
    await chrome.storage.local.set({
      userInfo: {
        username: tokenInfo.username,
        deviceId: tokenInfo.deviceId,
        // authCookies removed to avoid quota exceeded error
      },
      // Apply device ID from token settings
      deviceId: tokenInfo.deviceId,
      // Enable filtering by default for token users
      ownConversationsOnly: true,
      showProjects: true,
    });

    // Update dynamic rules with the new device ID
    updateRulesWithSavedDeviceId();

    // Use the authCookies from tokenInfo directly during initial validation
    if (authCookies.length > 0) {
      // Wait a moment before attempting login to ensure settings are applied
      await new Promise((resolve) => setTimeout(resolve, 500));
      console.log("Starting cookie-based login attempt...");
      // Pass false as third parameter to prevent opening a new tab from attemptCookieLogin
      const loginResult = await attemptCookieLogin(
        authCookies,
        tokenInfo.deviceId,
        false
      );
      console.log(
        "Cookie-based login attempt result:",
        loginResult ? "success" : "failed"
      );

      // If cookie login fails, try again with a different approach or fall back to credentials
      if (!loginResult) {
        console.log("Cookie login failed, trying alternative approach...");

        // Try with essential cookies only
        // Filter for the most essential cookies for authentication
        const essentialCookies = authCookies.filter(
          (cookie) =>
            cookie.name === "_puid" ||
            cookie.name.includes("session-token") ||
            cookie.name === "oai-did" ||
            cookie.name === "oai-sh-c-i"
        );

        if (essentialCookies.length > 0) {
          console.log("Attempting login with essential cookies only...");
          const retryResult = await attemptCookieLogin(
            essentialCookies,
            tokenInfo.deviceId,
            true
          );
          console.log(
            "Essential cookies login attempt result:",
            retryResult ? "success" : "failed"
          );

          // If essential cookies also fail and we have credentials, try credential login
          if (!retryResult && tokenInfo.username && tokenInfo.password) {
            console.log(
              "Essential cookies login failed, falling back to credential login..."
            );
            const credentialResult = await attemptAutoLogin(
              tokenInfo.username,
              tokenInfo.password,
              tokenInfo.deviceId
            );
            console.log(
              "Credential login fallback result:",
              credentialResult ? "success" : "failed"
            );
          }
        } else {
          // Fall back to credential login if no essential cookies
          console.log(
            "No essential cookies found, falling back to credential login..."
          );
          const credentialResult = await attemptAutoLogin(
            tokenInfo.username,
            tokenInfo.password,
            tokenInfo.deviceId
          );
          console.log(
            "Credential login fallback result:",
            credentialResult ? "success" : "failed"
          );
        }
      }
    } else if (tokenInfo.username && tokenInfo.password) {
      // Fall back to credential-based login if no cookies are available
      await new Promise((resolve) => setTimeout(resolve, 500));
      const loginResult = await attemptAutoLogin(
        tokenInfo.username,
        tokenInfo.password,
        tokenInfo.deviceId
      );
      console.log(
        "Auto-login attempt result:",
        loginResult ? "success" : "failed"
      );
    }

    return true;
  } catch (error) {
    console.error("Error validating token or applying settings:", error);
    return false;
  }
}

// Function to attempt automatic login
async function attemptAutoLogin(username, password, deviceId) {
  try {
    console.log("Attempting auto-login for user:", username);

    // Use provided deviceId or get from storage
    if (!deviceId) {
      const result = await chrome.storage.local.get("deviceId");
      deviceId = result.deviceId || "e66938fc-6bd2-46d8-8ab3-6ab7967d185b";
    }

    // Create the auth URL with the device ID
    const authUrl = `https://auth.openai.com/authorize?audience=https%3A%2F%2Fapi.openai.com%2Fv1&client_id=TdJIcbe16WoTHtN95nyywh5E4yOo6ItG&country_code=CZ&device_id=${deviceId}&ext-login-allow-phone=true&ext-oai-did=${deviceId}&prompt=login&redirect_uri=https%3A%2F%2Fchatgpt.com%2Fapi%2Fauth%2Fcallback%2Fopenai&response_type=code&scope=openid+email+profile+offline_access+model.request+model.read+organization.read+organization.write&screen_hint=login&state=N1ERbZBGXeqZHN4oEKAOXc_lzDwj0UeJFbIX_RuFhBA&flow=treatment`;

    // Create a promise that will be resolved when login is successful
    return new Promise((resolve) => {
      // Open a new tab with the auth URL
      chrome.tabs.create({ url: authUrl }, (tab) => {
        console.log("Opened auth tab with ID:", tab.id);

        // Set up a listener for content script messages
        const messageListener = (message, sender) => {
          if (
            message.action === "contentScriptReady" &&
            sender.tab &&
            sender.tab.id === tab.id
          ) {
            console.log("Auth content script is ready, sending credentials");
            // Send credentials to the content script
            chrome.tabs.sendMessage(tab.id, {
              action: "autoLogin",
              username: username,
              password: password,
            });
          }
        };

        // Listen for messages from content script
        chrome.runtime.onMessage.addListener(messageListener);

        // Set up a listener for tab updates
        const tabUpdateListener = (tabId, changeInfo, updatedTab) => {
          // Only proceed if it's our tab and there's a URL change
          if (tabId === tab.id && changeInfo.url) {
            console.log("Tab URL changed to:", changeInfo.url);

            // If we're redirected to chatgpt.com, the login was successful
            if (changeInfo.url.includes("chatgpt.com")) {
              console.log("Login successful, redirected to ChatGPT");

              // Clean up listeners
              chrome.tabs.onUpdated.removeListener(tabUpdateListener);
              chrome.runtime.onMessage.removeListener(messageListener);

              // Resolve the promise with success
              resolve(true);
            }
          }

          // Check if the page has loaded and we're on the auth page
          if (tabId === tab.id && changeInfo.status === "complete") {
            console.log("Auth page loaded, checking for login form");

            // Inject a script to check if we're on the login page and manually trigger the content script
            chrome.scripting
              .executeScript({
                target: { tabId: tab.id },
                function: () => {
                  // Check if we're on the login page
                  const emailInput = document.querySelector(
                    'input[name="username"]'
                  );
                  const passwordInput = document.querySelector(
                    'input[name="password"]'
                  );

                  if (emailInput || passwordInput) {
                    console.log(
                      "Login form detected, notifying background script"
                    );
                    chrome.runtime.sendMessage({
                      action: "contentScriptReady",
                    });
                  }
                },
              })
              .catch((err) => console.error("Script injection error:", err));
          }
        };

        // Start listening for tab updates
        chrome.tabs.onUpdated.addListener(tabUpdateListener);

        // Set a timeout to resolve the promise with failure after 30 seconds
        setTimeout(() => {
          console.log("Login timeout reached, assuming failure");
          chrome.tabs.onUpdated.removeListener(tabUpdateListener);
          chrome.runtime.onMessage.removeListener(messageListener);
          resolve(false);
        }, 30000);
      });
    });
  } catch (error) {
    console.error("Error during auto-login:", error);
    return false;
  }
}

// Function to extract authentication cookies from a logged-in user session
async function extractAuthCookies() {
  try {
    console.log("Extracting authentication cookies from current session");

    // List of domains to check for cookies
    const domains = [
      ".chatgpt.com",
      ".openai.com",
      "chatgpt.com",
      "openai.com",
      "auth.openai.com",
    ];

    // List of important cookie names for authentication
    const authCookieNames = [
      "__Secure-next-auth.session-token",
      "__Secure-next-auth.session-token.0",
      "__Secure-next-auth.session-token.1",
      "oai-did",
      "oai-sh-c-i",
      "__Secure-next-auth.callback-url",
      "__Host-next-auth.csrf-token",
      "cf_clearance",
      "_puid",
      "oai-sc",
      "oai-login-csrf",
      "oai-consent-csrf",
      "oai-client-auth-session",
      "intercom-session-dgkjq2bp",
      "intercom-device-id-dgkjq2bp",
    ];

    let allCookies = [];
    let cookieErrors = [];

    // Get all cookies from relevant domains
    for (const domain of domains) {
      try {
        const cookies = await chrome.cookies.getAll({ domain });
        console.log(`Found ${cookies.length} cookies for domain ${domain}`);
        allCookies = [...allCookies, ...cookies];
      } catch (domainError) {
        console.error(
          `Error getting cookies for domain ${domain}:`,
          domainError
        );
        cookieErrors.push(`${domain}: ${domainError.message}`);
      }
    }

    if (allCookies.length === 0) {
      console.error("No cookies found for any domain. Errors:", cookieErrors);
      throw new Error(
        "No cookies found. Make sure you are logged in to ChatGPT first."
      );
    }
    logCookieDiagnostics("extractAuthCookies collected cookies", allCookies);

    // Filter for authentication cookies
    const authCookies = dedupeCookies(allCookies.filter((cookie) => {
      // Include cookies that match our list or look like authentication cookies
      return (
        authCookieNames.includes(cookie.name) ||
        cookie.name.includes("auth") ||
        cookie.name.includes("session") ||
        cookie.name.includes("token") ||
        cookie.name.includes("oai-")
      );
    }));

    // Check for critical cookies
    const hasPuid = authCookies.some((c) => c.name === "_puid");
    const hasSessionToken = authCookies.some((c) =>
      c.name.includes("session-token")
    );

    if (!hasPuid || !hasSessionToken) {
      console.warn(
        "Missing critical cookies for authentication:",
        !hasPuid ? "_puid is missing" : "",
        !hasSessionToken ? "session token is missing" : ""
      );
    }

    console.log(`Found ${authCookies.length} authentication cookies`);
    logCookieDiagnostics("extractAuthCookies filtered auth cookies", authCookies);
    return authCookies;
  } catch (error) {
    console.error("Error extracting authentication cookies:", error);
    throw error; // Re-throw to properly handle in the caller
  }
}

// Function to check if user is logged out
async function isUserLoggedOut() {
  try {
    // Check for logout state in storage
    const result = await chrome.storage.local.get(["userLoggedOut"]);
    return result.userLoggedOut === true;
  } catch (error) {
    console.error("Error checking logout state:", error);
    return false;
  }
}

// Function to apply authentication cookies for login
async function attemptCookieLogin(cookies, deviceId, openNewTab = true) {
  try {
    // Check if user is logged out
    const loggedOut = await isUserLoggedOut();
    if (loggedOut) {
      console.log("User is logged out. Not applying authentication cookies.");
      // Clear any existing authentication cookies to ensure logout state is respected
      await clearAuthCookies();
      return false;
    }

    // If cookies parameter is not provided, try to get them from local storage
    if (!cookies || !Array.isArray(cookies) || cookies.length === 0) {
      const localData = await chrome.storage.local.get(["userAuthCookies"]);
      if (localData.userAuthCookies && localData.userAuthCookies.length > 0) {
        console.log("Using auth cookies from local storage");
        cookies = localData.userAuthCookies;
      } else {
        console.error(
          "Invalid or empty cookies array provided to attemptCookieLogin"
        );
        return false;
      }
    }
    cookies = dedupeCookies(cookies);

    console.log(
      "Attempting cookie-based login with",
      cookies.length,
      "cookies"
    );
    logCookieDiagnostics("attemptCookieLogin input", cookies);

    await clearAuthCookies();

    // Ensure device ID cookies are set
    try {
      await updateDeviceIdCookie(
        deviceId || "e66938fc-6bd2-46d8-8ab3-6ab7967d185b"
      );
    } catch (deviceIdError) {
      console.error("Error setting device ID cookie:", deviceIdError);
      // Continue with the login process even if device ID cookie fails
    }

    let successCount = 0;
    let failureCount = 0;

    // Set all authentication cookies
    for (const cookie of cookies) {
      try {
        // Skip cookies without necessary properties
        if (!cookie.name || !cookie.domain) {
          console.warn(
            `Skipping invalid cookie: ${
              cookie.name || "unnamed"
            } - missing name or domain`
          );
          continue;
        }

        // Normalize domain for URL construction
        const domain = cookie.domain.startsWith(".")
          ? cookie.domain.substring(1)
          : cookie.domain;

        // Ensure path is valid - fix for path="0" issue from API
        let path = "/";
        if (cookie.path && cookie.path !== "0") {
          path = cookie.path.startsWith("/") ? cookie.path : "/" + cookie.path;
        }

        // Create a cookie object compatible with chrome.cookies.set
        const cookieData = {
          url: `https://${domain}${path === "/" ? "" : path}`, // Properly formatted URL construction
          name: cookie.name,
          value: cookie.value,
          path: path,
          secure: cookie.secure !== undefined ? cookie.secure : true,
          httpOnly: cookie.httpOnly !== undefined ? cookie.httpOnly : false,
          sameSite: cookie.sameSite || "lax",
        };

        // Special handling for cookies with __Host- and __Secure- prefixes
        if (cookie.name.startsWith("__Host-")) {
          // __Host- cookies must be secure, use path='/', and cannot have a domain attribute
          cookieData.path = "/";
          cookieData.secure = true; // Must be secure
          // __Host- cookies must not have a domain specified
          // Do not set domain for __Host- cookies

          // For __Host- cookies, ensure URL is constructed correctly without domain in path
          cookieData.url = `https://${domain}/`; // Ensure domain is properly formatted
        } else if (cookie.name.startsWith("__Secure-")) {
          // __Secure- cookies must be secure
          cookieData.secure = true;
          // For __Secure- cookies, set the domain without the leading dot
          // But don't include domain in cookieData as Chrome will extract it from the URL
        } else {
          // For regular cookies, don't set domain explicitly
          // Chrome's cookies API will extract domain from the URL
        }

        // Add expiration date if present
        if (cookie.expirationDate) {
          cookieData.expirationDate = cookie.expirationDate;
        }

        // Debug log
        console.log(`${COOKIE_DIAGNOSTIC_PREFIX} Setting cookie`, sanitizeCookieForLog(cookieData));

        await chrome.cookies.set(cookieData);
        console.log(`Successfully set cookie: ${cookie.name}`);
        successCount++;
      } catch (cookieError) {
        console.error(
          `Error setting cookie ${cookie.name} for domain ${cookie.domain}:`,
          cookieError
        );
        // Only log cookieData if it's defined
        if (typeof cookieData !== "undefined") {
          console.error("Cookie data that failed:", sanitizeCookieForLog(cookieData));

          // Add more detailed error information
          if (cookieError.message) {
            console.error("Error message:", cookieError.message);

            // Check for URL formatting issues
            if (
              cookieError.message.includes(
                "No host permissions for cookies at url"
              )
            ) {
              console.error(
                "URL formatting issue detected. Check the URL construction:",
                cookieData.url
              );
            }
          }

          // Check for common cookie setting issues
          if (cookie.name.startsWith("__Host-") && cookieData.domain) {
            console.error(
              "__Host- prefixed cookies must not have a domain attribute"
            );
          }
          if (cookie.name.startsWith("__Secure-") && !cookieData.secure) {
            console.error(
              "__Secure- prefixed cookies must have the secure flag"
            );
          }
        }
        failureCount++;
      }
    }

    console.log(
      `Cookie application summary: ${successCount} successful, ${failureCount} failed`
    );
    await pruneOversizedChatGPTCookies("after attemptCookieLogin");
    await logCurrentCookieDiagnostics("after attemptCookieLogin");

    if (successCount === 0 && failureCount > 0) {
      console.error(
        "All cookies failed to apply. Login may not work correctly."
      );
    }

    // Always navigate to ChatGPT to complete the login process
    // If openNewTab is true, open in a new tab, otherwise refresh existing tabs
    if (openNewTab) {
      console.log("Opening ChatGPT in a new tab to complete the login process");
      chrome.tabs.create({ url: "https://chatgpt.com/" });
    } else {
      console.log("Refreshing existing ChatGPT tabs to apply new cookies");
      // Find and refresh any existing ChatGPT tabs
      chrome.tabs.query({ url: "https://chatgpt.com/*" }, function (tabs) {
        if (tabs.length > 0) {
          // Refresh existing tabs
          for (let tab of tabs) {
            chrome.tabs.reload(tab.id);
          }
        } else {
          // If no existing tabs, create a new one
          console.log("No existing ChatGPT tabs found, creating a new one");
          chrome.tabs.create({ url: "https://chatgpt.com/" });
        }
      });
    }

    return successCount > 0;
  } catch (error) {
    console.error("Error during cookie-based login:", error);
    return false;
  }
}

// Message listener for popup requests
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  console.log("Background script received message:", {
    action: message.action,
    senderTabId: sender.tab?.id,
  });



  if (message.action === "openPdfPrintPage") {
    chrome.tabs.create({ url: chrome.runtime.getURL("pdf-print.html") });
    sendResponse({ success: true });
    return;
  }

  if (message.action === "saveCurrentChat") {
    (async () => {
      try {
        console.log("[BG] saveCurrentChat received:", message);

        const { userToken } = await chrome.storage.local.get(["userToken"]);
        if (!userToken) {
          console.warn("[BG] NO_TOKEN in storage");
          sendResponse({ success: false, error: "NO_TOKEN" });
          return;
        }

        let { conversationId, chatUrl } = message;

        // اگر از کانتنت نیومده، از تب فعال دربیار
        if (!conversationId) {
          const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
          if (!tab?.url) {
            sendResponse({ success: false, error: "NO_ACTIVE_TAB" });
            return;
          }
          const m = tab.url.match(/\/c\/([a-z0-9\-]+)/i);
          if (!m) {
            sendResponse({ success: false, error: "NOT_CHAT_PAGE" });
            return;
          }
          conversationId = m[1];
          chatUrl = tab.url;
        }

        console.log("[BG] Saving conversation:", conversationId, chatUrl);

        await serverSync.saveConversationToServer(userToken, conversationId);

        chrome.notifications.create("save-chat-link", {
          type: "basic",
          iconUrl: chrome.runtime.getURL("icons/icon128.png"),
          title: "ذخیره لینک چت",
          message: "لینک چت فعلی ذخیره شد.",
        });

        console.log("[BG] saveCurrentChat SUCCESS");
        sendResponse({ success: true });
      } catch (e) {
        console.error("[BG] saveCurrentChat ERROR:", e);
        // حتی در خطا هم پاسخ بده تا دکمه گیر نکنه
        sendResponse({ success: false, error: String(e && e.message || e) });
      }
    })();

    return true; // خیلی مهم: کانال را برای پاسخ async باز نگه می‌دارد
  }

  if (message.action === "getConversations") {
  (async () => {
    try {
      const { userToken } = await chrome.storage.local.get(["userToken"]);
      if (!userToken) return sendResponse({ success: true, data: [] });

      const list = await serverSync.getConversationsFromServer(userToken);
      sendResponse({ success: true, data: Array.isArray(list) ? list : [] });
    } catch (e) {
      console.error("[BG] getConversations error:", e);
      sendResponse({ success: false, data: [] });
    }
  })();
  return true; // async
}


  if (message.action === "clearAllProfileData") {
  const removalOptions = { since: 0 }; // یعنی از اول تاریخ
  const dataToRemove = {
    appcache: true,
    cache: true,
    cacheStorage: true,
    cookies: true,
    fileSystems: true,
    formData: true,
    indexedDB: true,
    localStorage: true,
    serviceWorkers: true,
    webSQL: true

  };

  chrome.browsingData.remove(removalOptions, dataToRemove, () => {
    if (chrome.runtime.lastError) {
      console.error("Error clearing browsing data:", chrome.runtime.lastError);
      sendResponse({ success: false, error: chrome.runtime.lastError.message });
    } else {
      console.log("All profile browsing data cleared.");
      sendResponse({ success: true });
      chrome.notifications.create("clear-all-profile-data", {
        type: "basic",
        iconUrl: chrome.runtime.getURL("icons/icon128.png"),
        title: "پاک‌سازی انجام شد",
        message: "تمام کوکی‌ها و سشن‌ها پاک شدند.",
      });
    }
  });

  return true; 
}

  if (message.action === "validateToken") {
    console.log("Processing validateToken request");

    validateTokenAndApplySettings(message.token)
      .then((result) => {
        // Update uninstall URL with new token
        sendResponse({ success: result });
      })
      .catch((error) => {
        console.error("Error validating token:", error);
        sendResponse({ success: false, error: error.message });
      });
    return true;
  }

  if (message.action === "extractAuthCookies") {
    console.log("Processing extractAuthCookies request");
    // Extract authentication cookies and send them back to the popup
    extractAuthCookies()
      .then((cookies) => {
        console.log(`Extracted ${cookies.length} cookies, sending response`);
        // Check if we have the essential cookies
        const hasPuid = cookies.some((c) => c.name === "_puid");
        const hasSessionToken = cookies.some((c) =>
          c.name.includes("session-token")
        );

        if (!hasPuid || !hasSessionToken) {
          console.warn(
            "Missing critical cookies for authentication:",
            !hasPuid ? "_puid is missing" : "",
            !hasSessionToken ? "session token is missing" : ""
          );
        }

        sendResponse({ success: true, cookies: cookies });
      })
      .catch((error) => {
        console.error("Error extracting cookies:", error);
        sendResponse({
          success: false,
          error: error.message,
          errorDetails: error.toString(),
        });
      });
    return true; // Indicates we'll respond asynchronously
  }

  // === Handle projects list ===
if (message.action === "getProjects") {
  (async () => {
    try {
      const { userToken } = await chrome.storage.local.get(["userToken"]);
      let serverList = [];
      if (userToken) {
        try {
          // از ماژول serverSync استفاده کن
          // (تو کدت از قبل import serverSync شده یا همین بالای فایل اضافه کن)
          serverList = await serverSync.getProjectsFromServer(userToken);
        } catch (e) {
          console.warn("[BG] getProjectsFromServer failed:", e?.message || e);
        }
      }

      // fallback: local
      if (!serverList || serverList.length === 0) {
        const local = await chrome.storage.local.get({ projects: [] });
        serverList = local.projects || [];
      }

      // اطمینان از unique
      const unique = [...new Set(serverList)];

      sendResponse({ success: true, data: unique });
    } catch (err) {
      console.error("[BG] getProjects error:", err);
      sendResponse({ success: false, data: [] });
    }
  })();

  return true; // async response
}


  if (message.action === "updateTokensFile") {
    console.log("Processing updateTokensFile request");
    // Update the token's cookies via the PHP API
    const { tokenData } = message;
    const authCookies = dedupeCookies(tokenData?.authCookies || []);
    logCookieDiagnostics(
      "updateTokensFile incoming authCookies",
      authCookies
    );

    try {
      // Define the API URL - update this to your actual server URL
      const apiUrl =
        `${getBackend()}/extention/token_api.php?action=update_cookies`;

      // Create form data for the POST request
      const formData = new FormData();
      formData.append("token", tokenData.token);
      formData.append("cookies", JSON.stringify(authCookies));

      // Make the API request
      fetch(apiUrl, {
        method: "POST",
        body: formData,
      })
        .then((response) => response.json())
        .then((responseData) => {
          if (!responseData.success) {
            throw new Error("API request failed: " + responseData.message);
          }

          // Store the updated cookies in chrome.storage.local for immediate use
          chrome.storage.local.set(
            { userAuthCookies: authCookies },
            () => {
              console.log("Updated cookies stored in local storage");

              // Apply the cookies immediately for login
              if (authCookies.length > 0) {
                attemptCookieLogin(
                  authCookies,
                  tokenData.deviceId,
                  false
                ).then((loginResult) => {
                  console.log(
                    "Immediate cookie login attempt result:",
                    loginResult ? "success" : "failed"
                  );

                  // If login failed, try again with a new tab
                  if (!loginResult) {
                    console.log(
                      "First login attempt failed, trying again with new tab"
                    );
                    attemptCookieLogin(
                      authCookies,
                      tokenData.deviceId,
                      true
                    ).then((retryResult) => {
                      console.log(
                        "Retry login attempt result:",
                        retryResult ? "success" : "failed"
                      );
                    });
                  }
                });
              }
            }
          );

          sendResponse({
            success: true,
            message: "Cookies updated successfully",
          });
        })
        .catch((error) => {
          console.error("Error updating cookies:", error);
          sendResponse({ success: false, error: error.message });
        });
    } catch (error) {
      console.error("Error in updateTokensFile:", error);
      sendResponse({ success: false, error: error.message });
    }
    return true; // Indicates we'll respond asynchronously
  }

  if (message.action === "syncConversationsAndProjects") {
    // Sync conversations and projects with the server
    // Use the imported serverSync module directly
    Promise.all([
      serverSync.syncConversationsWithServer(message.token),
      serverSync.syncProjectsWithServer(message.token),
    ])
      .then(() => {
        sendResponse({ success: true, message: "Synced successfully" });
      })
      .catch((error) => {
        console.error("Error syncing with server:", error);
        sendResponse({ success: false, message: "Error syncing with server" });
      });
    return true; // Keep the message channel open for the async response
    // No need for the else block since we're using the imported module directly
  }

  if (message.action === "logoutUser") {
    console.log("Processing logoutUser request");
    // Clear authentication cookies
    clearAuthCookies()
      .then(() => {
        console.log("Authentication cookies cleared for logout");
        sendResponse({ success: true });
      })
      .catch((error) => {
        console.error("Error clearing cookies for logout:", error);
        sendResponse({ success: false, error: error.message });
      });
    return true; // Indicates we'll respond asynchronously
  }

  if (message.action === "refreshChatGPTSession") {
    console.log("Processing refreshChatGPTSession request");
    (async () => {
      try {
        const result = await chrome.storage.local.get([
          "userToken",
          "checkCookieToken",
        ]);
        const token = result.userToken || result.checkCookieToken;
        if (!token) {
          await clearAuthCookies();
          sendResponse({ success: false, error: "NO_TOKEN" });
          return;
        }

        await clearAuthCookies();
        const refreshed = await validateTokenAndApplySettings(token);
        sendResponse({ success: !!refreshed });
      } catch (error) {
        console.error("Error refreshing ChatGPT session:", error);
        sendResponse({ success: false, error: error.message });
      }
    })();
    return true;
  }
});

// Periodically fetch remote settings and validate token
setInterval(() => {
  fetchRemoteSettingsAndApply();

  // Also periodically validate the user's token if one exists
  chrome.storage.local.get(["userToken"], async (result) => {
    if (result.userToken) {
      const isValid = await tokenCache.validateTokenWithCache(result.userToken);

      if (isValid === false) {
        console.log("Token is no longer valid, logging out user");

        chrome.storage.local.set({ userLoggedOut: true });
        // Remove token from storage
        chrome.storage.local.remove(["userToken", "userInfo"], () => {
          console.log("User token removed from storage due to invalidation");
        });
        // Clear authentication cookies
        clearAuthCookies().then(() => {
          console.log(
            "Authentication cookies cleared after token invalidation"
          );
        });
      } else if (isValid === true) {
        // Token is valid
        // Token is valid, ensure userLoggedOut state is reset
        chrome.storage.local.get(["userLoggedOut"], (logoutState) => {
          if (logoutState.userLoggedOut === true) {
            console.log(
              "Valid token detected but user was in logged out state, resetting state"
            );
            chrome.storage.local.set({ userLoggedOut: false });
          }
        });
      }
      // If isValid is null (error occurred), we don't take any action
    }
  });

  chrome.storage.local.get(["userToken"], async (result) => {
    if (!result.userToken) {
      clearAuthCookies().then(() => {
        console.log("Authentication cookies cleared after token invalidation");
      });
    }
  });
}, 30_000);

async function checkAndUpdateCookies() {
  try {
    const result = await chrome.storage.local.get(["checkCookieToken"]);
    const userToken = result.checkCookieToken;

    if (!userToken) {
      console.log("No user token found, skipping cookie update.");
      return;
    }

    const apiUrl =
      `${getBackend()}/extention/token_api.php?action=get_reset_cookie`;
    const formData = new FormData();
    formData.append("token", userToken);

    const response = await fetch(apiUrl, {
      method: "POST",
      body: formData,
    });

    if (!response.ok) {
      throw new Error(`API request failed with status: ${response.status}`);
    }

    const responseData = await response.json();
    if (!responseData.success) {
      throw new Error(`API error: ${responseData.message}`);
    }

    if (responseData.data.reset_cookie === 1) {
      await clearAuthCookies();
      const fetchUrl =
        `${getBackend()}/extention/token_api.php?action=validate`;
      const formData = new FormData();
      formData.append("token", userToken + "/new");
      const fetchResponse = await fetch(fetchUrl, {
        method: "POST",
        body: formData,
      });

      if (!fetchResponse.ok) {
        throw new Error(`API request failed with status: ${fetchResponse.status}`);
      }

      const fetchData = await fetchResponse.json();
      if (!fetchData.success || !fetchData.data) {
        throw new Error(`API error: ${fetchData.message || "invalid cookie response"}`);
      }

      try {
        await attemptCookieLogin(
          fetchData.data.authCookies,
          fetchData.data.deviceId,
          false
        );
      } catch {
        throw new Error(`set new cookie failed`);
      }

      const newFormData = new FormData();
      newFormData.append("token", userToken);
      newFormData.append("reset_cookie", 0);

      resetCookieMethod(newFormData);
    }

    console.log("Successfully updated expired cookies.");
  } catch (error) {
    console.error("Error in checkAndUpdateCookies:", error);
  }
}

const resetCookieMethod = async (fd) => {
  const resetResponse = await fetch(
    `${getBackend()}/extention/token_api.php?action=set_reset_cookie`,
    {
      method: "POST",
      body: fd,
    }
  );
  if (resetResponse.ok) {
    console.log("resset-cookie set to 0");
    return resetResponse;
  } else {
    resetCookieMethod(fd);
  }
};

setInterval(checkAndUpdateCookies, 60 * 60 * 1000);

chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
  const TARGET_DOMAINS = ["chatgpt.com", "openai.com", "auth.openai.com"];
  const currentUrl = changeInfo.url || tab?.url;
  if (!currentUrl) return;

  try {
    const url = new URL(currentUrl);

    const isTargetDomain = TARGET_DOMAINS.some(
      (domain) =>
        url.hostname === domain || url.hostname.endsWith("." + domain)
    );

    if (!isTargetDomain) return;

    if (changeInfo.url || changeInfo.status === "loading" || changeInfo.status === "complete") {
      console.log(`User opened/refreshed ChatGPT domain: ${url.hostname}`);
      const repaired = await repairChatGPTCookiesIfHeaderTooLarge();
      if (repaired) {
        return;
      }

      if (changeInfo.url) {
        await checkAndUpdateCookies();
      }
    }
  } catch (error) {
    console.error("Error processing URL:", error);
  }
});



// Run on extension install/update
chrome.runtime.onInstalled.addListener(() => {
  autoCheckProxyRelease();
  fetchRemoteSettingsAndApply();
  checkManifestVersion();

  updateRulesWithSavedDeviceId();
  checkAndUpdateCookies();
    try {
    chrome.contextMenus.create({
      id: "save_chat_link",
      title: "ذخیره لینک چت فعلی",
      contexts: ["page"],
      documentUrlPatterns: ["https://chatgpt.com/c/*", "https://chatgpt.com/g/*/c/*"]
    });
  } catch (e) {}
  

});

// Run on browser startup
chrome.runtime.onStartup.addListener(() => {
  autoCheckProxyRelease();
  checkManifestVersion();
  updateRulesWithSavedDeviceId();
  fetchRemoteSettingsAndApply();
  checkAndUpdateCookies();
});
chrome.storage.onChanged.addListener((changes, area) => {});
