/*
 * 网页自动打字脚本 - 优化版
 * 作者：@ergoubtc
 * 推特：@https://x.com/ergoubtc 
 * 微信：spdh0321
 * 更多免费脚本：@http://ergoubtc.vip/
 * 
 * 优化版要点：
 * - 可配置：选择器、按钮文案、延迟范围、颜色判断、最大轮数
 * - 输入目标更通用：支持 input、textarea、contenteditable
 * - 事件更真实：InputEvent + KeyboardEvent；逐字随机延迟可调
 * - 点击更稳健：自动滚动至视图、兼容 [role="button"] / <a>
 * - 按键停止：按 ESC 开关运行；也可在控制台设置 window.AUTO_TYPE_STOP = true
 * - 容错：更宽松的按钮查找（大小写不敏感，包含匹配）
 * - 日志：可控 debug 输出
 */

(function () {
    'use strict';

    const CONFIG = {
        // 目标元素配置
        inputSelectors: [
            'input[type="text"]',
            'textarea',
            '[contenteditable="true"]'
        ],
        wordSelector: 'div[class*="text-"]',
        activeWordColor: 'rgb(255, 255, 255)',

        // 按钮文案（大小写不敏感、包含匹配）
        submitText: 'Submit to Leaderboard',
        playAgainText: 'Play Again',

        // 延迟与节奏
        perCharDelayMinMs: 80,
        perCharDelayMaxMs: 100,
        afterWordSpaceDelayMs: 200,
        afterSubmitDelayMs: 2000,
        afterPlayAgainDelayMs: 3000,
        idleCheckDelayMs: 1000,
        loopDelayMs: 500,

        // 真人化错误输入配置
        humanizeErrors: {
            enabled: true,                    // 是否启用错误输入
            errorRate: 0.15,                  // 错误率 15%
            typoRate: 0.08,                   // 拼写错误率 8%
            doubleCharRate: 0.05,             // 重复字符率 5%
            skipCharRate: 0.03,               // 漏字符率 3%
            wrongCharRate: 0.04,              // 错误字符率 4%
            correctionDelayMinMs: 500,        // 修正前最小延迟
            correctionDelayMaxMs: 1500,       // 修正前最大延迟
            backspaceDelayMinMs: 50,          // 退格键最小延迟
            backspaceDelayMaxMs: 100,         // 退格键最大延迟
            maxCorrectionAttempts: 3          // 最大修正尝试次数
        },

        // 控制
        maxRounds: Infinity, // 可设置为数字限制输词轮数
        autoDoubleTabWhenSingleWord: true,
        debug: true
    };

    if (typeof window.AUTO_TYPE_STOP === 'undefined') {
        window.AUTO_TYPE_STOP = false;
    }

    AddHotkeyStop();

    async function Sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    function Log(message) {
        if (CONFIG.debug) console.log(message);
    }

    function RandomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    function RandomFloat() {
        return Math.random();
    }

    function ShouldMakeError() {
        return CONFIG.humanizeErrors.enabled && RandomFloat() < CONFIG.humanizeErrors.errorRate;
    }

    function GetTypoChar(originalChar) {
        const typos = {
            'a': ['q', 's', 'z'],
            'b': ['v', 'g', 'n'],
            'c': ['x', 'v', 'f'],
            'd': ['s', 'e', 'r', 'f'],
            'e': ['w', 's', 'd', 'r'],
            'f': ['d', 'r', 't', 'g', 'v'],
            'g': ['f', 't', 'y', 'h', 'b'],
            'h': ['g', 'y', 'u', 'j', 'n'],
            'i': ['u', 'j', 'k', 'o'],
            'j': ['h', 'u', 'i', 'k', 'm'],
            'k': ['j', 'i', 'o', 'l'],
            'l': ['k', 'o', 'p'],
            'm': ['n', 'j', 'k'],
            'n': ['b', 'h', 'j', 'm'],
            'o': ['i', 'k', 'l', 'p'],
            'p': ['o', 'l'],
            'q': ['w', 'a', 's'],
            'r': ['e', 'd', 'f', 't'],
            's': ['a', 'w', 'e', 'd', 'z', 'x'],
            't': ['r', 'f', 'g', 'y'],
            'u': ['y', 'h', 'j', 'i'],
            'v': ['c', 'f', 'g', 'b'],
            'w': ['q', 'a', 's', 'e'],
            'x': ['z', 's', 'd', 'c'],
            'y': ['t', 'g', 'h', 'u'],
            'z': ['a', 's', 'x']
        };
        const char = originalChar.toLowerCase();
        if (typos[char] && typos[char].length > 0) {
            return typos[char][RandomInt(0, typos[char].length - 1)];
        }
        return originalChar;
    }

    function SimulateBackspace(inputElement, count = 1) {
        for (let i = 0; i < count; i++) {
            const backspaceEvent = new KeyboardEvent('keydown', { 
                key: 'Backspace', 
                code: 'Backspace', 
                keyCode: 8, 
                which: 8, 
                bubbles: true 
            });
            inputElement.dispatchEvent(backspaceEvent);
            Sleep(RandomInt(CONFIG.humanizeErrors.backspaceDelayMinMs, CONFIG.humanizeErrors.backspaceDelayMaxMs));
        }
    }

    function GetInputElement() {
        for (const selector of CONFIG.inputSelectors) {
            const el = document.querySelector(selector);
            if (el) return el;
        }
        return null;
    }

    function DispatchValueChange(inputElement, value) {
        // 处理 input/textarea
        if (inputElement instanceof HTMLInputElement || inputElement instanceof HTMLTextAreaElement) {
            const proto = inputElement instanceof HTMLInputElement
                ? window.HTMLInputElement.prototype
                : window.HTMLTextAreaElement.prototype;
            const setter = Object.getOwnPropertyDescriptor(proto, 'value')?.set;
            if (setter) setter.call(inputElement, value);
            const inputEvent = new InputEvent('input', { bubbles: true });
            inputElement.dispatchEvent(inputEvent);
            return;
        }
        // 处理 contenteditable
        if (inputElement && inputElement.isContentEditable) {
            inputElement.textContent = value;
            const inputEvent = new InputEvent('input', { bubbles: true });
            inputElement.dispatchEvent(inputEvent);
        }
    }

    function TriggerInput(inputElement, value, lastChar) {
        DispatchValueChange(inputElement, value);
        // 模拟按键事件（keydown/keyup）
        const key = lastChar ?? (value ? value[value.length - 1] : '');
        if (key) {
            const keydown = new KeyboardEvent('keydown', { key, bubbles: true, composed: true });
            const keyup = new KeyboardEvent('keyup', { key, bubbles: true, composed: true });
            inputElement.dispatchEvent(keydown);
            inputElement.dispatchEvent(keyup);
        }
    }

    function ScrollIntoViewIfNeeded(element) {
        try { element.scrollIntoView({ behavior: 'smooth', block: 'center' }); } catch (_) {}
    }

    function ElementLooksClickable(element) {
        const rect = element.getBoundingClientRect();
        const visible = rect.width > 0 && rect.height > 0;
        const styles = window.getComputedStyle(element);
        const clickable = styles.pointerEvents !== 'none' && styles.visibility !== 'hidden' && styles.display !== 'none';
        return visible && clickable;
    }

    function ClickElement(element) {
        if (!element) return false;
        if (element.disabled) return false;
        ScrollIntoViewIfNeeded(element);
        if (!ElementLooksClickable(element)) return false;
        try {
            element.dispatchEvent(new MouseEvent('mouseover', { bubbles: true, cancelable: true, view: window }));
            element.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true, view: window }));
            element.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, cancelable: true, view: window }));
            element.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true, view: window }));
            return true;
        } catch (e) {
            try { element.click?.(); return true; } catch (_) { return false; }
        }
    }

    function TriggerSingleTab() {
        const el = document.activeElement || document.body;
        el.dispatchEvent(new KeyboardEvent('keydown', { key: 'Tab', code: 'Tab', keyCode: 9, which: 9, bubbles: true }));
        el.dispatchEvent(new KeyboardEvent('keyup', { key: 'Tab', code: 'Tab', keyCode: 9, which: 9, bubbles: true }));
    }

    async function TriggerDoubleTab() {
        Log('🔄🔄 模拟双 Tab 键');
        TriggerSingleTab();
        await Sleep(100);
        TriggerSingleTab();
    }

    function NormalizeText(text) {
        return (text || '').trim().toLowerCase();
    }

    function FindButtonByText(text) {
        const target = NormalizeText(text);
        const candidates = [
            ...document.querySelectorAll('button'),
            ...document.querySelectorAll('[role="button"]'),
            ...document.querySelectorAll('a')
        ];
        for (const el of candidates) {
            const t = NormalizeText(el.textContent);
            if (t.includes(target) && ElementLooksClickable(el)) return el;
        }
        return null;
    }

    function FindActiveWord() {
        const wordElems = document.querySelectorAll(CONFIG.wordSelector);
        for (const el of wordElems) {
            const text = (el.innerText || '').trim();
            if (!text) continue;
            const color = window.getComputedStyle(el).color;
            if (color === CONFIG.activeWordColor) return el;
        }
        return null;
    }

    async function WaitForInputFocusAndNewWord(maxAttempts = 10) {
        let attempts = 0;
        while (attempts < maxAttempts && !window.AUTO_TYPE_STOP) {
            const input = GetInputElement();
            const activeWord = FindActiveWord();
            if (input && document.activeElement === input && activeWord) return true;
            if (input) { input.focus(); input.click?.(); }
            TriggerSingleTab();
            await Sleep(500);
            attempts++;
        }
        return false;
    }

    function AddHotkeyStop() {
        window.addEventListener('keydown', (e) => {
            if (e.key === 'Escape') {
                window.AUTO_TYPE_STOP = !window.AUTO_TYPE_STOP;
                console.log(window.AUTO_TYPE_STOP ? '⏸ 已暂停' : '▶️ 已继续');
            }
        });
        console.log('按 ESC 可暂停/继续；也可设置 window.AUTO_TYPE_STOP = true 停止。');
    }

    async function MainLoop() {
        let rounds = 0;
        while (!window.AUTO_TYPE_STOP) {
            if (rounds >= CONFIG.maxRounds) { console.log('✅ 达到最大轮数，停止。'); break; }

            const input = GetInputElement();
            if (!input) { await Sleep(CONFIG.idleCheckDelayMs); continue; }
            input.focus(); input.click?.();

            const submitButton = FindButtonByText(CONFIG.submitText);
            if (submitButton) {
                while (!window.AUTO_TYPE_STOP && !ClickElement(submitButton)) await Sleep(500);
                await Sleep(CONFIG.afterSubmitDelayMs);

                const playAgainButton = FindButtonByText(CONFIG.playAgainText);
                if (playAgainButton) {
                    while (!window.AUTO_TYPE_STOP && !ClickElement(playAgainButton)) await Sleep(500);
                    await Sleep(CONFIG.afterPlayAgainDelayMs);
                    await WaitForInputFocusAndNewWord();
                    TriggerSingleTab();
                    rounds++;
                    continue;
                }
            }

            const activeWordEl = FindActiveWord();
            if (!activeWordEl) { await Sleep(CONFIG.idleCheckDelayMs); continue; }

            const word = (activeWordEl.innerText || '').trim();
            if (!word) { await Sleep(CONFIG.loopDelayMs); continue; }
            Log(`📝 正在输入: ${word}`);

            let current = '';
            let hasError = false;
            
            for (let i = 0; i < word.length; i++) {
                const char = word[i];
                let inputChar = char;
                
                // 决定是否输入错误
                if (ShouldMakeError()) {
                    const errorType = RandomFloat();
                    if (errorType < CONFIG.humanizeErrors.typoRate) {
                        // 拼写错误
                        inputChar = GetTypoChar(char);
                        hasError = true;
                        Log(`🔤 拼写错误: ${char} -> ${inputChar}`);
                    } else if (errorType < CONFIG.humanizeErrors.typoRate + CONFIG.humanizeErrors.doubleCharRate) {
                        // 重复字符
                        current += char;
                        TriggerInput(input, current, char);
                        await Sleep(RandomInt(CONFIG.perCharDelayMinMs, CONFIG.perCharDelayMaxMs));
                        inputChar = char; // 再次输入相同字符
                        hasError = true;
                        Log(`🔄 重复字符: ${char}`);
                    } else if (errorType < CONFIG.humanizeErrors.typoRate + CONFIG.humanizeErrors.doubleCharRate + CONFIG.humanizeErrors.skipCharRate) {
                        // 漏字符
                        hasError = true;
                        Log(`⏭️ 漏字符: ${char}`);
                        continue; // 跳过这个字符
                    } else if (errorType < CONFIG.humanizeErrors.typoRate + CONFIG.humanizeErrors.doubleCharRate + CONFIG.humanizeErrors.skipCharRate + CONFIG.humanizeErrors.wrongCharRate) {
                        // 错误字符
                        inputChar = String.fromCharCode(97 + RandomInt(0, 25)); // 随机字母
                        hasError = true;
                        Log(`❌ 错误字符: ${char} -> ${inputChar}`);
                    }
                }
                
                current += inputChar;
                TriggerInput(input, current, inputChar);
                await Sleep(RandomInt(CONFIG.perCharDelayMinMs, CONFIG.perCharDelayMaxMs));
                if (window.AUTO_TYPE_STOP) break;
            }
            
            if (window.AUTO_TYPE_STOP) break;

            // 如果有错误，模拟修正
            if (hasError && CONFIG.humanizeErrors.enabled) {
                Log(`🔧 开始修正错误...`);
                await Sleep(RandomInt(CONFIG.humanizeErrors.correctionDelayMinMs, CONFIG.humanizeErrors.correctionDelayMaxMs));
                
                // 清空输入框
                const currentValue = input.value || input.textContent || '';
                for (let i = 0; i < currentValue.length; i++) {
                    SimulateBackspace(input, 1);
                    await Sleep(RandomInt(CONFIG.humanizeErrors.backspaceDelayMinMs, CONFIG.humanizeErrors.backspaceDelayMaxMs));
                }
                
                // 重新输入正确的单词
                current = '';
                for (const char of word) {
                    current += char;
                    TriggerInput(input, current, char);
                    await Sleep(RandomInt(CONFIG.perCharDelayMinMs, CONFIG.perCharDelayMaxMs));
                }
                Log(`✅ 修正完成`);
            }

            // 输入空格以提交当前词
            TriggerInput(input, current + ' ', ' ');
            await Sleep(CONFIG.afterWordSpaceDelayMs);

            const wordElems = document.querySelectorAll(CONFIG.wordSelector);
            if (CONFIG.autoDoubleTabWhenSingleWord && wordElems.length === 1) {
                await TriggerDoubleTab();
                await Sleep(1000);
                const playAgainButton = FindButtonByText(CONFIG.playAgainText);
                if (playAgainButton) {
                    Log('🔄 双 Tab 可能失败，尝试点击 Play Again 按钮');
                    while (!window.AUTO_TYPE_STOP && !ClickElement(playAgainButton)) await Sleep(500);
                    await Sleep(CONFIG.afterPlayAgainDelayMs);
                    await WaitForInputFocusAndNewWord();
                    TriggerSingleTab();
                }
            }

            rounds++;
            await Sleep(CONFIG.loopDelayMs);
        }
    }

    MainLoop().catch(err => console.error('脚本运行异常：', err));
})();
