//! Enhanced JavaScript injections for bot detection bypass
//!
//! Provides comprehensive JavaScript code to inject into browser contexts
//! to hide automation markers and mock browser APIs.

/// Comprehensive bootstrap script for bot detection bypass
///
/// This script:
/// - Removes all CDP markers ($cdc_, __webdriver, etc.)
/// - Overrides navigator.webdriver
/// - Mocks Chrome runtime objects with realistic data
/// - Patches permissions API
/// - Adds realistic hardware/platform properties
/// - Hides Function.prototype.toString modifications
pub const COMPREHENSIVE_BOOTSTRAP: &str = r#"
(function() {
    'use strict';

    // Debug: Confirm script is running
    console.log('[ORB-BROWSE] Script loaded at', Date.now());

    // ============================================================
    // PART 1: Remove CDP Markers
    // ============================================================

    // Remove all $cdc_ and __webdriver properties from window
    let objectToInspect = window;
    const propsRemoved = [];

    while (objectToInspect !== null) {
        Object.getOwnPropertyNames(objectToInspect)
            .filter(prop =>
                prop.match(/^(cdc_|[\$]cdc_|__webdriver|_selenium|callSelenium|_Selenium_IDE_Recorder)/) ||
                prop.startsWith('webdriver') ||
                prop.startsWith('driver') ||
                prop.startsWith('selenium')
            )
            .forEach(prop => {
                try {
                    delete window[prop];
                    propsRemoved.push(prop);
                } catch(e) {}
            });
        objectToInspect = Object.getPrototypeOf(objectToInspect);
    }

    // ============================================================
    // PART 2: Override navigator.webdriver (ULTRA AGGRESSIVE)
    // ============================================================

    // Step 1: Delete existing webdriver property from all levels
    try {
        delete Object.getPrototypeOf(navigator).webdriver;
    } catch(e) {}
    try {
        delete navigator.webdriver;
    } catch(e) {}
    if (navigator.__proto__) {
        try {
            delete navigator.__proto__.webdriver;
        } catch(e) {}
    }

    // Step 2: Define our override with getter that always returns undefined
    Object.defineProperty(navigator, 'webdriver', {
        get: () => undefined,
        set: () => {},
        configurable: true,
        enumerable: false  // Hide from enumeration
    });

    // Step 3: Patch Object.getOwnPropertyDescriptor to hide modifications
    const originalGetOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
    Object.getOwnPropertyDescriptor = function(obj, prop) {
        if (obj === navigator && prop === 'webdriver') {
            return undefined;
        }
        return Reflect.apply(originalGetOwnPropertyDescriptor, this, arguments);
    };

    // Debug: Verify webdriver is set correctly
    console.log('[ORB-BROWSE] navigator.webdriver =', navigator.webdriver);

    // ============================================================
    // PART 2.5: Override Navigator Properties to Match Real Chrome
    // ============================================================

    // Override userAgent to ensure it matches HTTP header
    Object.defineProperty(navigator, 'userAgent', {
        get: () => 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
        configurable: true,
        enumerable: true
    });

    // Override appVersion
    Object.defineProperty(navigator, 'appVersion', {
        get: () => '5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',
        configurable: true,
        enumerable: true
    });

    // Override platform
    Object.defineProperty(navigator, 'platform', {
        get: () => 'Linux x86_64',
        configurable: true,
        enumerable: true
    });

    // Override vendor
    Object.defineProperty(navigator, 'vendor', {
        get: () => 'Google Inc.',
        configurable: true,
        enumerable: true
    });

    // Override languages
    Object.defineProperty(navigator, 'languages', {
        get: () => ['en-US', 'en'],
        configurable: true,
        enumerable: true
    });

    // Override hardwareConcurrency
    Object.defineProperty(navigator, 'hardwareConcurrency', {
        get: () => 8,
        configurable: true,
        enumerable: true
    });

    // Override deviceMemory
    Object.defineProperty(navigator, 'deviceMemory', {
        get: () => 8,
        configurable: true,
        enumerable: true
    });

    // ============================================================
    // PART 3: Mock Chrome Runtime with Realistic Data
    // ============================================================

    if (!window.chrome) {
        window.chrome = {};
    }

    // Add loadTimes function (deprecated but still checked)
    window.chrome.loadTimes = function() {
        const now = Date.now() / 1000;
        return {
            requestTime: now - 1.5,
            startLoadTime: now - 1.2,
            commitLoadTime: now - 0.8,
            finishDocumentLoadTime: now - 0.4,
            finishLoadTime: now,
            firstPaintTime: now - 0.3,
            firstPaintAfterLoadTime: 0,
            navigationType: 'Other',
            wasFetchedViaSpdy: false,
            wasNpnNegotiated: true,
            npnNegotiatedProtocol: 'h2',
            wasAlternateProtocolAvailable: false,
            connectionInfo: 'h2'
        };
    };

    // Add csi function (Chrome Speed Index)
    window.chrome.csi = function() {
        const now = Date.now();
        return {
            onloadT: now,
            pageT: 1234.5,
            startE: now - 2000,
            tran: 15
        };
    };

    // Add app property
    window.chrome.app = {
        isInstalled: false,
        InstallState: {
            DISABLED: 'disabled',
            INSTALLED: 'installed',
            NOT_INSTALLED: 'not_installed'
        },
        RunningState: {
            CANNOT_RUN: 'cannot_run',
            READY_TO_RUN: 'ready_to_run',
            RUNNING: 'running'
        }
    };

    // Add runtime with realistic methods
    window.chrome.runtime = {
        OnInstalledReason: {
            CHROME_UPDATE: 'chrome_update',
            INSTALL: 'install',
            SHARED_MODULE_UPDATE: 'shared_module_update',
            UPDATE: 'update'
        },
        OnRestartRequiredReason: {
            APP_UPDATE: 'app_update',
            OS_UPDATE: 'os_update',
            PERIODIC: 'periodic'
        },
        PlatformArch: {
            ARM: 'arm',
            ARM64: 'arm64',
            MIPS: 'mips',
            MIPS64: 'mips64',
            X86_32: 'x86-32',
            X86_64: 'x86-64'
        },
        PlatformNaclArch: {
            ARM: 'arm',
            MIPS: 'mips',
            MIPS64: 'mips64',
            X86_32: 'x86-32',
            X86_64: 'x86-64'
        },
        PlatformOs: {
            ANDROID: 'android',
            CROS: 'cros',
            LINUX: 'linux',
            MAC: 'mac',
            OPENBSD: 'openbsd',
            WIN: 'win'
        },
        RequestUpdateCheckStatus: {
            NO_UPDATE: 'no_update',
            THROTTLED: 'throttled',
            UPDATE_AVAILABLE: 'update_available'
        }
    };

    // ============================================================
    // PART 4: Mock Plugins with Realistic Data
    // ============================================================

    Object.defineProperty(navigator, 'plugins', {
        get: () => {
            const plugins = [
                {
                    name: 'Chrome PDF Plugin',
                    filename: 'internal-pdf-viewer',
                    description: 'Portable Document Format',
                    length: 1,
                    0: {
                        type: 'application/x-google-chrome-pdf',
                        suffixes: 'pdf',
                        description: 'Portable Document Format',
                        enabledPlugin: null
                    }
                },
                {
                    name: 'Chrome PDF Viewer',
                    filename: 'mhjfbmdgcfjbbpaeojofohoefgiehjai',
                    description: 'Portable Document Format',
                    length: 1,
                    0: {
                        type: 'application/pdf',
                        suffixes: 'pdf',
                        description: 'Portable Document Format',
                        enabledPlugin: null
                    }
                },
                {
                    name: 'Native Client',
                    filename: 'internal-nacl-plugin',
                    description: '',
                    length: 2,
                    0: {
                        type: 'application/x-nacl',
                        suffixes: '',
                        description: 'Native Client Executable',
                        enabledPlugin: null
                    },
                    1: {
                        type: 'application/x-pnacl',
                        suffixes: '',
                        description: 'Portable Native Client Executable',
                        enabledPlugin: null
                    }
                }
            ];

            plugins.length = 3;
            plugins.item = function(index) { return this[index] || null; };
            plugins.namedItem = function(name) {
                return this.find(p => p.name === name) || null;
            };
            plugins.refresh = function() {};

            return plugins;
        },
        enumerable: true,
        configurable: true
    });

    // ============================================================
    // PART 5: Mock Permissions API
    // ============================================================

    const originalQuery = window.navigator.permissions.query;
    window.navigator.permissions.query = function(parameters) {
        if (parameters.name === 'notifications') {
            return Promise.resolve({
                state: Notification.permission,
                onchange: null
            });
        }
        return originalQuery.call(navigator.permissions, parameters);
    };

    // ============================================================
    // PART 6: Add Realistic Navigator Properties
    // ============================================================

    // Languages
    Object.defineProperty(navigator, 'languages', {
        get: () => ['en-US', 'en'],
        enumerable: true,
        configurable: true
    });

    // Vendor
    Object.defineProperty(navigator, 'vendor', {
        get: () => 'Google Inc.',
        enumerable: true,
        configurable: true
    });

    // Platform (OS-specific)
    Object.defineProperty(navigator, 'platform', {
        get: () => 'Linux x86_64',
        enumerable: true,
        configurable: true
    });

    // Hardware concurrency
    Object.defineProperty(navigator, 'hardwareConcurrency', {
        get: () => 8,
        enumerable: true,
        configurable: true
    });

    // Device memory (in GB)
    Object.defineProperty(navigator, 'deviceMemory', {
        get: () => 8,
        enumerable: true,
        configurable: true
    });

    // Max touch points
    Object.defineProperty(navigator, 'maxTouchPoints', {
        get: () => 0,
        enumerable: true,
        configurable: true
    });

    // ============================================================
    // PART 7: Patch Function.prototype.toString
    // ============================================================

    const originalToString = Function.prototype.toString;
    const proxyToString = new Proxy(originalToString, {
        apply(target, thisArg, args) {
            // If the function was overridden by us, show native code
            if (thisArg === navigator.permissions.query ||
                thisArg === window.chrome.loadTimes ||
                thisArg === window.chrome.csi) {
                return 'function () { [native code] }';
            }
            return target.apply(thisArg, args);
        }
    });

    Function.prototype.toString = proxyToString;

    // ============================================================
    // PART 8: Clean up Error stack traces
    // ============================================================

    const originalPrepareStackTrace = Error.prepareStackTrace;
    Error.prepareStackTrace = function(error, stack) {
        // Filter out traces that might reveal CDP
        const filteredStack = stack.filter(frame => {
            const fileName = frame.getFileName() || '';
            return !fileName.includes('devtools://');
        });

        if (originalPrepareStackTrace) {
            return originalPrepareStackTrace(error, filteredStack);
        }
        return filteredStack;
    };

    // ============================================================
    // PART 9: Prevent detection via iframe
    // ============================================================

    Object.defineProperty(HTMLIFrameElement.prototype, 'contentWindow', {
        get: function() {
            const win = Object.getOwnPropertyDescriptor(
                HTMLIFrameElement.prototype,
                'contentWindow'
            ).get.call(this);

            if (win) {
                try {
                    win.navigator.webdriver = false;
                } catch(e) {}
            }
            return win;
        }
    });

})();
"#;

/// Basic bypass script (lighter weight alternative)
pub const BASIC_BYPASS: &str = r#"
Object.defineProperty(navigator, 'webdriver', { get: () => false });
delete navigator.__proto__.webdriver;
window.chrome = { runtime: {}, loadTimes: function() {}, csi: function() {} };
"#;
