#!/usr/bin/env node
/**
 * Claude for Chrome Extension - Configuration
 *
 * Configures the Claude for Chrome extension with the ANTHROPIC_API_KEY after
 * Chrome session starts. Injects the API key into chrome.storage.local so the
 * extension can authenticate without manual OAuth login.
 *
 * Priority: 96 (after chrome_launch at 90)
 * Hook: on_Crawl (runs once per crawl, not per snapshot)
 *
 * Note: Claude for Chrome normally uses OAuth PKCE (claude.com login).
 * This hook attempts to inject the API key directly into extension storage.
 * If this doesn't work with your extension version, you may need to log in
 * manually via the Chrome session before archiving.
 */

const path = require("path");
const fs = require("fs");
const {
  PROCESS_EXIT_SKIPPED,
  ensureNodeModuleResolution,
  getEnv,
  getEnvBool,
  loadConfig,
} = require("../base/utils.js");
ensureNodeModuleResolution(module);

const {
  waitForChromeSessionState,
  findExtensionMetadataByName,
  connectToBrowserEndpoint,
  resolvePuppeteerModule,
} = require("../chrome/chrome_utils.js");

// Check if enabled
if (!getEnvBool("CLAUDECHROME_ENABLED", false)) {
  console.log("CLAUDECHROME_ENABLED=False");
  process.exit(PROCESS_EXIT_SKIPPED);
}

const puppeteer = resolvePuppeteerModule();

const PLUGIN_DIR = path.basename(__dirname);
const hookConfig = loadConfig();
const CRAWL_DIR = path.resolve((hookConfig.CRAWL_DIR || ".").trim());
const OUTPUT_DIR = path.join(CRAWL_DIR, PLUGIN_DIR);
if (!fs.existsSync(OUTPUT_DIR)) {
  fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
process.chdir(OUTPUT_DIR);

function getCrawlChromeSessionDir() {
  return path.join(path.resolve(hookConfig.CRAWL_DIR || "."), "chrome");
}

const CHROME_SESSION_DIR = getCrawlChromeSessionDir();
const CONFIG_MARKER = path.join(CHROME_SESSION_DIR, ".claudechrome_configured");

async function configureClaudeChrome() {
  // Check if already configured in this session
  if (fs.existsSync(CONFIG_MARKER)) {
    console.error("[*] Claude for Chrome already configured in this session");
    return { success: true, skipped: true };
  }

  const apiKey = getEnv("ANTHROPIC_API_KEY");
  if (!apiKey) {
    console.warn(
      "[!] ANTHROPIC_API_KEY not set, skipping Claude for Chrome config"
    );
    return { success: false, error: "ANTHROPIC_API_KEY not set" };
  }

  console.error("[*] Configuring Claude for Chrome extension...");
  console.error(`[*]   API Key: ${apiKey.slice(0, 8)}...${apiKey.slice(-4)}`);

  try {
    const chromeSession = await waitForChromeSessionState(CHROME_SESSION_DIR, {
      timeoutMs: 10000,
      requireBrowserReady: true,
    });
    if (!chromeSession?.cdpUrl) {
      throw new Error("No Chrome session found (chrome plugin must run first)");
    }
    const { cdpUrl } = chromeSession;
    const browser = await connectToBrowserEndpoint(puppeteer, cdpUrl, {
      defaultViewport: null,
    });

    try {
      // Wake up the extension by visiting a page
      console.error("[*] Waking up extension...");
      const triggerPage = await browser.newPage();
      try {
        await triggerPage.goto("https://www.google.com", {
          waitUntil: "domcontentloaded",
          timeout: 10000,
        });
        await new Promise((r) => setTimeout(r, 3000));
      } catch (e) {
        console.warn(`[!] Trigger page: ${e.message}`);
      }
      try {
        await triggerPage.close();
      } catch (e) {}

      // Read extension metadata
      const extensions = chromeSession.extensions || [];
      const claudeExt = findExtensionMetadataByName(extensions, "claudechrome");
      if (!claudeExt || !claudeExt.id) {
        console.error(
          "[*] Claude for Chrome extension not found in browser.json"
        );
        return { success: true, skipped: true };
      }

      const extensionId = claudeExt.id;
      console.error(`[*] Claude for Chrome Extension ID: ${extensionId}`);

      // Try to find an extension page to inject config
      // The extension may have a popup, options page, or side panel
      const pages = await browser.pages();
      let extPage = pages.find((p) =>
        p.url().startsWith(`chrome-extension://${extensionId}`)
      );

      if (!extPage) {
        // Try opening the extension's popup or background page
        extPage = await browser.newPage();
        try {
          // Try common extension pages
          for (const pagePath of [
            "popup.html",
            "index.html",
            "options.html",
            "sidepanel.html",
          ]) {
            try {
              await extPage.goto(
                `chrome-extension://${extensionId}/${pagePath}`,
                {
                  waitUntil: "domcontentloaded",
                  timeout: 5000,
                }
              );
              if (
                extPage.url().startsWith(`chrome-extension://${extensionId}`)
              ) {
                break;
              }
            } catch (e) {
              continue;
            }
          }
        } catch (e) {
          console.error(`[*] Could not open extension page: ${e.message}`);
        }
      }

      if (
        !extPage ||
        !extPage.url().startsWith(`chrome-extension://${extensionId}`)
      ) {
        console.warn(
          "[!] Could not access extension context for config injection"
        );
        // Still mark as configured so we don't retry
        fs.writeFileSync(
          CONFIG_MARKER,
          JSON.stringify(
            {
              timestamp: new Date().toISOString(),
              extensionId,
              configured: false,
              note:
                "Could not access extension context - user may need to log in manually",
            },
            null,
            2
          )
        );
        return { success: true, skipped: true };
      }

      // Inject API key into chrome.storage.local
      // Claude for Chrome internally uses the Anthropic SDK, so we try to
      // set the API key in the storage format it expects
      const result = await extPage.evaluate((key) => {
        return new Promise((resolve) => {
          if (typeof chrome === "undefined" || !chrome.storage) {
            resolve({ success: false, error: "chrome.storage not available" });
            return;
          }

          // Try setting the API key in various storage formats the extension might use
          const configData = {
            anthropicApiKey: key,
            apiKey: key,
            api_key: key,
          };

          chrome.storage.local.set(configData, () => {
            if (chrome.runtime.lastError) {
              resolve({
                success: false,
                error: chrome.runtime.lastError.message,
              });
            } else {
              resolve({ success: true });
            }
          });
        });
      }, apiKey);

      try {
        await extPage.close();
      } catch (e) {}

      if (result.success) {
        console.error(
          "[+] Claude for Chrome API key injected into extension storage"
        );
      } else {
        console.warn(`[!] Storage injection failed: ${result.error}`);
        console.warn(
          "[!] User may need to log in to claude.com manually in the Chrome session"
        );
      }

      // Write marker file
      fs.writeFileSync(
        CONFIG_MARKER,
        JSON.stringify(
          {
            timestamp: new Date().toISOString(),
            extensionId,
            configured: result.success,
          },
          null,
          2
        )
      );

      return { success: true };
    } finally {
      browser.disconnect();
    }
  } catch (e) {
    return { success: false, error: `${e.name}: ${e.message}` };
  }
}

async function main() {
  const result = await configureClaudeChrome();

  if (result.skipped) {
    process.exit(0);
  } else if (result.success) {
    console.error("[+] Claude for Chrome configuration complete");
    process.exit(0);
  } else {
    console.error(`ERROR: ${result.error}`);
    // Non-fatal - extension may still work with manual login
    process.exit(0);
  }
}

main().catch((e) => {
  console.error(`Fatal error: ${e.message}`);
  process.exit(1);
});
