/**
 * 付费 Captcha API 兜底：CapSolver / 2Captcha 统一 Turnstile 求解接口
 */
const {
    CAPTCHA_PROVIDER,
    CAPTCHA_API_KEY,
    CAPTCHA_MAX_WAIT_MS,
} = require('./constants');
const { sanitizePageUrlForCfSolver } = require('./cf-detector');

/** AntiCloudflareTask 所需静态代理（ip:port:user:pass），未配置则不可用 */
const CAPTCHA_PROXY = (process.env.CAPTCHA_PROXY || '').trim();

/**
 * @param {string} url
 * @param {Record<string, string>} [headers]
 * @returns {Promise<any>}
 */
async function httpJsonPost(url, body, headers = {}) {
    const res = await fetch(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', ...headers },
        body: JSON.stringify(body),
    });
    const text = await res.text();
    try {
        return JSON.parse(text);
    } catch (_) {
        throw new Error(`Captcha API 返回非 JSON: ${text.slice(0, 200)}`);
    }
}

/**
 * @param {string} url
 * @returns {Promise<any>}
 */
async function httpJsonGet(url) {
    const res = await fetch(url);
    const text = await res.text();
    try {
        return JSON.parse(text);
    } catch (_) {
        throw new Error(`Captcha API 返回非 JSON: ${text.slice(0, 200)}`);
    }
}

/**
 * CapSolver Turnstile 求解
 * @param {{ pageUrl: string, sitekey: string, apiKey: string }} params
 * @returns {Promise<string>}
 */
async function solveViaCapSolver({ pageUrl, sitekey, apiKey }) {
    const create = await httpJsonPost('https://api.capsolver.com/createTask', {
        clientKey: apiKey,
        task: {
            type: 'AntiTurnstileTaskProxyLess',
            websiteURL: pageUrl,
            websiteKey: sitekey,
        },
    });

    if (create.errorId !== 0 || !create.taskId) {
        throw new Error(`CapSolver createTask 失败: ${create.errorDescription || create.errorCode || 'unknown'}`);
    }

    const deadline = Date.now() + CAPTCHA_MAX_WAIT_MS;
    while (Date.now() < deadline) {
        await new Promise((r) => setTimeout(r, 3000));
        const result = await httpJsonPost('https://api.capsolver.com/getTaskResult', {
            clientKey: apiKey,
            taskId: create.taskId,
        });

        if (result.status === 'ready' && result.solution && result.solution.token) {
            return result.solution.token;
        }
        if (result.errorId !== 0) {
            throw new Error(`CapSolver getTaskResult 失败: ${result.errorDescription || result.errorCode}`);
        }
    }
    throw new Error('CapSolver 求解超时');
}

/**
 * 2Captcha Turnstile 求解
 * @param {{ pageUrl: string, sitekey: string, apiKey: string }} params
 * @returns {Promise<string>}
 */
async function solveVia2Captcha({ pageUrl, sitekey, apiKey }) {
    const params = new URLSearchParams({
        key: apiKey,
        method: 'turnstile',
        sitekey,
        pageurl: pageUrl,
        json: '1',
    });

    const create = await httpJsonGet(`https://2captcha.com/in.php?${params.toString()}`);
    if (create.status !== 1 || !create.request) {
        throw new Error(`2Captcha in.php 失败: ${create.request || create.error_text || 'unknown'}`);
    }

    const taskId = create.request;
    const deadline = Date.now() + CAPTCHA_MAX_WAIT_MS;
    while (Date.now() < deadline) {
        await new Promise((r) => setTimeout(r, 5000));
        const result = await httpJsonGet(
            `https://2captcha.com/res.php?key=${encodeURIComponent(apiKey)}&action=get&id=${encodeURIComponent(taskId)}&json=1`
        );
        if (result.status === 1 && result.request) {
            return result.request;
        }
        if (result.request && result.request !== 'CAPCHA_NOT_READY') {
            throw new Error(`2Captcha res.php 失败: ${result.request}`);
        }
    }
    throw new Error('2Captcha 求解超时');
}

/**
 * CapSolver Managed Challenge（返回 cf_clearance cookie，需 CAPTCHA_PROXY）
 * @param {{ pageUrl: string, apiKey: string, proxy: string, html?: string, userAgent?: string }} params
 * @returns {Promise<{ cookies: Record<string, string>, userAgent?: string }>}
 */
async function solveViaCapSolverCloudflare({ pageUrl, apiKey, proxy, html, userAgent }) {
    const task = {
        type: 'AntiCloudflareTask',
        websiteURL: pageUrl,
        proxy,
    };
    if (html) {
        task.html = html.slice(0, 500000);
    }
    if (userAgent) {
        task.userAgent = userAgent;
    }

    const create = await httpJsonPost('https://api.capsolver.com/createTask', {
        clientKey: apiKey,
        task,
    });

    if (create.errorId !== 0 || !create.taskId) {
        throw new Error(`CapSolver AntiCloudflare createTask 失败: ${create.errorDescription || create.errorCode || 'unknown'}`);
    }

    const deadline = Date.now() + CAPTCHA_MAX_WAIT_MS;
    while (Date.now() < deadline) {
        await new Promise((r) => setTimeout(r, 3000));
        const result = await httpJsonPost('https://api.capsolver.com/getTaskResult', {
            clientKey: apiKey,
            taskId: create.taskId,
        });

        if (result.status === 'ready' && result.solution) {
            const cookies = result.solution.cookies || {};
            if (typeof cookies === 'string') {
                return { cookies: { cf_clearance: cookies }, userAgent: result.solution.userAgent };
            }
            if (result.solution.token && !cookies.cf_clearance) {
                return {
                    cookies: { cf_clearance: result.solution.token },
                    userAgent: result.solution.userAgent,
                };
            }
            return {
                cookies,
                userAgent: result.solution.userAgent,
            };
        }
        if (result.errorId !== 0) {
            throw new Error(`CapSolver AntiCloudflare getTaskResult 失败: ${result.errorDescription || result.errorCode}`);
        }
    }
    throw new Error('CapSolver AntiCloudflare 求解超时');
}

/**
 * 统一 Cloudflare Managed Challenge 求解
 * @param {{ pageUrl: string, provider?: string, apiKey?: string, proxy?: string, html?: string, userAgent?: string }} params
 * @returns {Promise<{ cookies: Record<string, string>, userAgent?: string, provider: string }>}
 */
async function solveCloudflare({ pageUrl, provider, apiKey, proxy, html, userAgent }) {
    const resolvedProvider = (provider || CAPTCHA_PROVIDER).toLowerCase();
    const resolvedKey = apiKey || CAPTCHA_API_KEY;
    const resolvedProxy = (proxy || CAPTCHA_PROXY).trim();
    const cleanPageUrl = sanitizePageUrlForCfSolver(pageUrl);

    if (!resolvedKey) {
        throw new Error('未配置 CAPTCHA_API_KEY，无法使用 AntiCloudflareTask');
    }
    if (!resolvedProxy) {
        throw new Error('AntiCloudflareTask 需要配置 CAPTCHA_PROXY（静态代理 ip:port:user:pass）');
    }

    if (resolvedProvider !== 'capsolver') {
        throw new Error('AntiCloudflareTask 当前仅支持 CapSolver');
    }

    const { cookies, userAgent: solvedUa } = await solveViaCapSolverCloudflare({
        pageUrl: cleanPageUrl,
        apiKey: resolvedKey,
        proxy: resolvedProxy,
        html,
        userAgent,
    });

    if (!cookies || !cookies.cf_clearance) {
        throw new Error('CapSolver AntiCloudflare 未返回 cf_clearance');
    }

    return { cookies, userAgent: solvedUa || userAgent, provider: resolvedProvider };
}

/**
 * 将 CapSolver AntiCloudflare 返回的 cookie / UA 写入页面并 reload
 * @param {import('puppeteer').Page} page
 * @param {string} cleanUrl
 * @param {{ cookies: Record<string, string>, userAgent?: string }} solution
 */
async function applyCfClearanceSolution(page, cleanUrl, solution) {
    if (solution.userAgent) {
        await page.setUserAgent(solution.userAgent).catch(() => {});
    }

    let host = '';
    let path = '/';
    try {
        const parsed = new URL(cleanUrl);
        host = parsed.hostname;
        path = parsed.pathname || '/';
    } catch (_) {
        host = '';
    }

    for (const [name, value] of Object.entries(solution.cookies || {})) {
        if (!value) {
            continue;
        }
        const cookieDomain = host.startsWith('.') ? host : `.${host}`;
        await page.setCookie({
            name,
            value: String(value),
            domain: cookieDomain,
            path: '/',
            secure: true,
            sameSite: 'None',
        }).catch(() => {});
    }

    console.log(`[CF] cf_clearance 已注入，goto 业务页 url=${cleanUrl}`);
    await page.goto(cleanUrl, {
        waitUntil: 'domcontentloaded',
        timeout: 60000,
    }).catch(() => {});
    await page.waitForNetworkIdle({ idleTime: 500, timeout: 30000 }).catch(() => {
        console.warn('[CF] cf_clearance goto 后 networkidle 超时，继续后续流程');
    });
}

/**
 * 统一 Turnstile 求解入口
 * @param {{ pageUrl: string, sitekey: string, provider?: string, apiKey?: string }} params
 * @returns {Promise<{ token: string, provider: string }>}
 */
async function solveTurnstile({ pageUrl, sitekey, provider, apiKey }) {
    const resolvedProvider = (provider || CAPTCHA_PROVIDER).toLowerCase();
    const resolvedKey = apiKey || CAPTCHA_API_KEY;
    const cleanPageUrl = sanitizePageUrlForCfSolver(pageUrl);

    if (!sitekey) {
        throw new Error('无法提取 Turnstile sitekey');
    }
    if (!resolvedKey) {
        throw new Error('未配置 CAPTCHA_API_KEY，无法使用付费 Captcha 兜底');
    }

    let token;
    if (resolvedProvider === '2captcha') {
        token = await solveVia2Captcha({ pageUrl: cleanPageUrl, sitekey, apiKey: resolvedKey });
    } else {
        token = await solveViaCapSolver({ pageUrl: cleanPageUrl, sitekey, apiKey: resolvedKey });
    }

    return { token, provider: resolvedProvider };
}

/**
 * Captcha API 是否已配置
 * @returns {boolean}
 */
function isCaptchaConfigured() {
    return CAPTCHA_API_KEY.length > 0;
}

module.exports = {
    solveTurnstile,
    solveCloudflare,
    applyCfClearanceSolution,
    isCaptchaConfigured,
};
