import { createLogger } from "../utils/logger/index.js";
import { init_logger } from "../utils/logger.js";
import { chmod, stat } from "node:fs/promises";
import { platform } from "node:os";
import { exec } from "node:child_process";
import { promisify } from "node:util";
//#region src/browser/stealth.ts
/**
* Stealth launch utilities for anti-detection browser automation.
*
* Provides argument deduplication, fingerprint seed generation, and
* macOS quarantine attribute removal. Shared by CloakBrowser provider
* and enhanced local launch paths.
*/
init_logger();
const execAsync = promisify(exec);
const log = createLogger("BrowserStealth");
/**
* Default Chromium args that reduce automation detectability for CloakBrowser.
* Does not include `--no-sandbox` — CloakBrowser rejects it with an infobar warning.
*/
const BASE_STEALTH_ARGS = [
	"--disable-blink-features=AutomationControlled",
	"--disable-infobars",
	"--disable-dev-shm-usage",
	"--disable-background-networking",
	"--disable-default-apps",
	"--disable-extensions-except=",
	"--disable-sync",
	"--metrics-recording-only",
	"--no-first-run"
];
/** Flags CloakBrowser does not support (shown as unsupported infobar if passed). */
const CLOAK_UNSUPPORTED_FLAGS = new Set(["--no-sandbox", "--disable-setuid-sandbox"]);
/** Strip sandbox flags before passing user extraArgs to CloakBrowser. */
function filterCloakBrowserExtraArgs(extraArgs = []) {
	return extraArgs.filter((arg) => !CLOAK_UNSUPPORTED_FLAGS.has(arg.split("=")[0] ?? arg));
}
/**
* Build stealth launch args with deduplication.
* User `extraArgs` override any default args with the same `--key=` prefix.
*/
function buildStealthArgs(extraArgs = [], options = {}) {
	const argsMap = /* @__PURE__ */ new Map();
	const positionalArgs = [];
	for (const arg of BASE_STEALTH_ARGS) {
		const eqIdx = arg.indexOf("=");
		if (eqIdx >= 0) argsMap.set(arg.slice(0, eqIdx), arg);
		else positionalArgs.push(arg);
	}
	const fingerprintPlatform = options.fingerprintPlatform ?? detectFingerprintPlatform();
	argsMap.set("--fingerprint", `--fingerprint=${generateFingerprintSeed()}`);
	argsMap.set("--fingerprint-platform", `--fingerprint-platform=${fingerprintPlatform}`);
	if (options.timezone) argsMap.set("--fingerprint-timezone", `--fingerprint-timezone=${options.timezone}`);
	if (options.locale) {
		argsMap.set("--lang", `--lang=${options.locale}`);
		argsMap.set("--fingerprint-locale", `--fingerprint-locale=${options.locale}`);
	}
	if (options.webrtcIp) argsMap.set("--fingerprint-webrtc-ip", `--fingerprint-webrtc-ip=${options.webrtcIp}`);
	for (const arg of extraArgs) {
		const eqIdx = arg.indexOf("=");
		if (eqIdx >= 0) argsMap.set(arg.slice(0, eqIdx), arg);
		else positionalArgs.push(arg);
	}
	const kvArgs = [...argsMap.values()].sort();
	return [...positionalArgs, ...kvArgs];
}
/**
* Basic stealth args for the local Playwright launcher (less aggressive than CloakBrowser).
* Does not include fingerprint or geo args — just reduces automation signals.
*/
function buildLocalStealthArgs(extraArgs = []) {
	const baseArgs = [
		"--disable-blink-features=AutomationControlled",
		"--no-sandbox",
		"--disable-setuid-sandbox"
	];
	const seen = /* @__PURE__ */ new Set();
	const result = [];
	for (const arg of extraArgs) {
		const key = arg.split("=")[0];
		if (!seen.has(key)) {
			seen.add(key);
			result.push(arg);
		}
	}
	for (const arg of baseArgs) {
		const key = arg.split("=")[0];
		if (!seen.has(key)) {
			seen.add(key);
			result.push(arg);
		}
	}
	return result;
}
/** Generate a timestamp-based fingerprint seed for CloakBrowser. */
function generateFingerprintSeed() {
	return Date.now();
}
/** Detect the fingerprint platform based on the current OS. */
function detectFingerprintPlatform() {
	switch (platform()) {
		case "darwin": return "macos";
		case "win32": return "windows";
		default: return "windows";
	}
}
/**
* Remove the `com.apple.quarantine` extended attribute from a file or app bundle on macOS.
* Files downloaded from the internet are tagged with this attribute, causing Gatekeeper
* to block unsigned binaries. Without this, CloakBrowser silently fails to launch.
*
* Non-fatal — logs and returns on any error.
*/
async function removeQuarantineAttr(path) {
	if (platform() !== "darwin") return;
	const target = findAppBundle(path) ?? path;
	log.debug({ target }, "Removing com.apple.quarantine");
	try {
		const { stderr } = await execAsync(`xattr -rd com.apple.quarantine "${target}"`);
		if (stderr?.trim()) log.debug({ stderr: stderr.trim() }, "xattr stderr (non-fatal)");
		log.debug("Quarantine attribute removed");
	} catch {
		log.debug("xattr command failed or attribute not set (non-fatal)");
	}
}
/** Find the .app bundle root by walking up from an executable path. */
function findAppBundle(executablePath) {
	const parts = executablePath.split("/");
	for (let i = parts.length - 1; i >= 0; i--) if (parts[i].endsWith(".app")) return parts.slice(0, i + 1).join("/");
}
/**
* JavaScript snippet to inject into every new page to hide automation signals.
* Removes `navigator.webdriver` and patches other detectable properties.
*/
const WEBDRIVER_OVERRIDE_SCRIPT = `
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
if (navigator.plugins.length === 0) {
  Object.defineProperty(navigator, 'plugins', {
    get: () => [1, 2, 3, 4, 5],
  });
}
Object.defineProperty(navigator, 'languages', {
  get: () => ['en-US', 'en'],
});
window.chrome = window.chrome || {};
window.chrome.runtime = window.chrome.runtime || {};
`;
/** Ensure a binary file has executable permissions (Unix only, no-op on Windows). */
async function makeExecutable(path) {
	if (platform() === "win32") return;
	try {
		await chmod(path, (await stat(path)).mode | 73);
	} catch (e) {
		const msg = e instanceof Error ? e.message : String(e);
		log.warn({
			path,
			errorMessage: msg
		}, `Failed to chmod binary: ${msg}`);
	}
}
//#endregion
export { WEBDRIVER_OVERRIDE_SCRIPT, buildLocalStealthArgs, buildStealthArgs, filterCloakBrowserExtraArgs, generateFingerprintSeed, makeExecutable, removeQuarantineAttr };

//# sourceMappingURL=stealth.js.map