/**
 * Turnstile sitekey 提前捕获：在 goto 前挂载监听，避免 60s 空等后 iframe 已销毁
 */
const {
    extractSitekeyFromChallengeUrl,
    extractSitekeyFromHtml,
    extractTurnstileSitekey,
    waitForTurnstileSurface,
} = require('./turnstile-handler');

/**
 * @typedef {Object} SitekeyCaptureHandle
 * @property {() => string|null} get
 * @property {(page: import('puppeteer').Page, antiBot?: object) => Promise<string|null>} scanNow
 * @property {(page: import('puppeteer').Page, antiBot?: object, waitMs?: number) => Promise<string|null>} resolveForSolver
 * @property {() => void} detach
 */

/**
 * 尝试从 URL 字符串解析并缓存 sitekey
 * @param {string|null|undefined} url
 * @param {{ sitekey: string|null, log: (msg: string) => void }} state
 * @returns {string|null}
 */
function tryStoreSitekeyFromUrl(url, state) {
    const key = extractSitekeyFromChallengeUrl(url || '');
    if (key && !state.sitekey) {
        state.sitekey = key;
        state.log(`[CF] sitekey 捕获 (${key.slice(0, 12)}...) source=${url.slice(0, 80)}`);
    }
    return state.sitekey;
}

/**
 * 在 page.goto 之前挂载 frame/response/target 监听
 * @param {import('puppeteer').Page} page
 * @param {import('puppeteer').Browser} [browser]
 * @returns {SitekeyCaptureHandle}
 */
function attachSitekeyCapture(page, browser) {
    const state = {
        sitekey: null,
        attached: false,
        cleanups: [],
        log: (msg) => console.log(msg),
    };

    if (page.__sitekeyCaptureHandle) {
        return page.__sitekeyCaptureHandle;
    }

    const onFrameNavigated = (frame) => {
        try {
            tryStoreSitekeyFromUrl(frame.url(), state);
        } catch (_) {
            /* ignore */
        }
    };
    page.on('framenavigated', onFrameNavigated);
    state.cleanups.push(() => page.off('framenavigated', onFrameNavigated));

    const onResponse = (response) => {
        try {
            tryStoreSitekeyFromUrl(response.url(), state);
        } catch (_) {
            /* ignore */
        }
    };
    page.on('response', onResponse);
    state.cleanups.push(() => page.off('response', onResponse));

    if (browser && typeof browser.on === 'function') {
        const onTargetCreated = (target) => {
            try {
                tryStoreSitekeyFromUrl(target.url(), state);
            } catch (_) {
                /* ignore */
            }
        };
        browser.on('targetcreated', onTargetCreated);
        state.cleanups.push(() => browser.off('targetcreated', onTargetCreated));
    }

    state.attached = true;

    /** @type {SitekeyCaptureHandle} */
    const handle = {
        get: () => state.sitekey,
        scanNow: async (scanPage, antiBot) => {
            if (state.sitekey) {
                return state.sitekey;
            }

            const frames = scanPage.frames();
            for (const frame of frames) {
                tryStoreSitekeyFromUrl(frame.url(), state);
                if (state.sitekey) {
                    return state.sitekey;
                }
            }

            const html = await scanPage.content().catch(() => '');
            const fromHtml = extractSitekeyFromHtml(html);
            if (fromHtml) {
                state.sitekey = fromHtml;
                state.log(`[CF] sitekey 从 HTML 提取 (${fromHtml.slice(0, 12)}...)`);
                return fromHtml;
            }

            const browserRef = scanPage.browser();
            if (browserRef) {
                for (const target of browserRef.targets()) {
                    tryStoreSitekeyFromUrl(target.url(), state);
                    if (state.sitekey) {
                        return state.sitekey;
                    }
                }
            }

            const configured = String(antiBot?.turnstileSitekey || '').trim();
            if (configured && antiBot?.cfChallengeMode !== 'managed' && !antiBot?.cfCloudflareSolver) {
                state.sitekey = configured;
                state.log(`[CF] 使用 antiBot.turnstileSitekey (${configured.slice(0, 12)}...)`);
                return configured;
            }

            return null;
        },
        resolveForSolver: async (scanPage, antiBot, waitMs = 25000) => {
            let sitekey = await handle.scanNow(scanPage, antiBot);
            if (sitekey) {
                return sitekey;
            }

            sitekey = await waitForTurnstileSurface(scanPage, waitMs);
            if (sitekey) {
                state.sitekey = sitekey;
                return sitekey;
            }

            sitekey = await extractTurnstileSitekey(scanPage);
            if (sitekey) {
                state.sitekey = sitekey;
                return sitekey;
            }

            return handle.scanNow(scanPage, antiBot);
        },
        detach: () => {
            for (const fn of state.cleanups) {
                try {
                    fn();
                } catch (_) {
                    /* ignore */
                }
            }
            state.cleanups = [];
            state.attached = false;
            if (page.__sitekeyCaptureHandle === handle) {
                delete page.__sitekeyCaptureHandle;
            }
        },
    };

    page.__sitekeyCaptureHandle = handle;
    return handle;
}

/**
 * 读取 page 上已挂载的 capture（无则 null）
 * @param {import('puppeteer').Page} page
 * @returns {SitekeyCaptureHandle|null}
 */
function getSitekeyCapture(page) {
    return page?.__sitekeyCaptureHandle || null;
}

module.exports = {
    attachSitekeyCapture,
    getSitekeyCapture,
    tryStoreSitekeyFromUrl,
};
