import { describe, it, expect } from "@normalized:N&&&@ohos/hypium/index&1.0.25";
import type webview from "@ohos:web.webview";
import { RenderRecovery } from "@normalized:N&&&tencentqianwebview/src/main/ets/internal/RenderRecovery&1.0.0";
/**
 * 渲染进程崩溃恢复策略单测（对齐 Android WebViewPoolRenderProcessGoneTest 的恢复链维度）。
 *
 * 覆盖 fix：`RenderRecovery.recover` 的恢复链 `loadUrl(fallback)` → `refresh()` → `onUnrecoverable()`
 * （loadUrl 优先，进程崩溃后 refresh 常失效，与 Android/iOS 对齐），
 * 以及 `captureLastUrl` 的主框架 URL 提取（供 recover 的 fallback 兜底）。
 *
 * 纯逻辑单测：用 mock `WebviewController` 记录/抛错来驱动各分支，不依赖真实 WebView / UIContext。
 */
/** 可编排行为的 mock WebviewController：记录调用序列，可令 refresh/loadUrl 抛错模拟失效。 */
class MockController {
    public refreshCalled: number = 0;
    public loadUrlCalls: string[] = [];
    public refreshThrows: boolean = false;
    public loadUrlThrows: boolean = false;
    public refresh(): void {
        this.refreshCalled++;
        if (this.refreshThrows) {
            throw new Error('refresh failed (render process dead)');
        }
    }
    public loadUrl(url: string): void {
        if (this.loadUrlThrows) {
            throw new Error('loadUrl failed (render process dead)');
        }
        this.loadUrlCalls.push(url);
    }
}
function asController(m: MockController): webview.WebviewController {
    return m as any as webview.WebviewController;
}
export default function renderRecoveryTest() {
    describe('RenderRecovery', () => {
        // ────────── performRecover 恢复链（同步核心）──────────
        it('performRecover_loadUrlSucceeds_stopsAtLoadUrl', 0, () => {
            // loadUrl(fallback) 成功 → 不再走 refresh，不触发 onUnrecoverable（loadUrl 优先）
            const m = new MockController();
            let unrecoverableCalled = false;
            RenderRecovery.performRecover(asController(m), 'https://x/sign', () => {
                unrecoverableCalled = true;
            });
            expect(m.loadUrlCalls.length).assertEqual(1);
            expect(m.loadUrlCalls[0]).assertEqual('https://x/sign');
            expect(m.refreshCalled).assertEqual(0);
            expect(unrecoverableCalled).assertFalse();
        });
        it('performRecover_loadUrlFails_fallsBackToRefresh', 0, () => {
            // loadUrl 抛错 → refresh() 兜底成功 → 不触发 onUnrecoverable
            const m = new MockController();
            m.loadUrlThrows = true;
            let unrecoverableCalled = false;
            RenderRecovery.performRecover(asController(m), 'https://x/sign', () => {
                unrecoverableCalled = true;
            });
            expect(m.refreshCalled).assertEqual(1);
            expect(unrecoverableCalled).assertFalse();
        });
        it('performRecover_emptyFallbackAndRefreshFails_firesUnrecoverable', 0, () => {
            // fallback 为空 → 跳过 loadUrl，退化 refresh 兜底；refresh 抛错 → 触发 onUnrecoverable
            const m = new MockController();
            m.refreshThrows = true;
            let unrecoverableCalled = false;
            RenderRecovery.performRecover(asController(m), '', () => {
                unrecoverableCalled = true;
            });
            expect(m.refreshCalled).assertEqual(1);
            expect(m.loadUrlCalls.length).assertEqual(0);
            expect(unrecoverableCalled).assertTrue();
        });
        it('performRecover_bothFail_firesUnrecoverable', 0, () => {
            // loadUrl 抛错 + refresh 也抛错（controller 已彻底失效）→ 触发 onUnrecoverable（关闭容器）
            const m = new MockController();
            m.loadUrlThrows = true;
            m.refreshThrows = true;
            let unrecoverableCalled = false;
            RenderRecovery.performRecover(asController(m), 'https://x/sign', () => {
                unrecoverableCalled = true;
            });
            expect(m.refreshCalled).assertEqual(1);
            expect(unrecoverableCalled).assertTrue();
        });
        it('performRecover_unrecoverableOptional_noCallbackNoCrash', 0, () => {
            // onUnrecoverable 未传 → 全部失败也不崩溃（best-effort）
            const m = new MockController();
            m.loadUrlThrows = true;
            m.refreshThrows = true;
            let threw = false;
            try {
                RenderRecovery.performRecover(asController(m), 'https://x/sign');
            }
            catch (_e) {
                threw = true;
            }
            expect(threw).assertFalse();
        });
        // ────────── recover 延迟调度 ──────────
        it('recover_isDeferred_notInvokedSynchronously', 0, () => {
            // recover 延迟调度：同步返回后 refresh 尚未被调用（避免瞬间抢资源再次崩溃）。
            // 延迟窗口过后的实际执行由 performRecover 的同步用例覆盖。
            const m = new MockController();
            RenderRecovery.recover(asController(m), 'https://x/sign');
            expect(m.refreshCalled).assertEqual(0);
            expect(m.loadUrlCalls.length).assertEqual(0);
        });
        it('recover_returnsTimerId_cancellable', 0, () => {
            // recover 返回可取消的 timer id：用户在延迟窗口内关闭页面时，clearTimeout 取消恢复，
            // 避免回调访问已销毁 controller（野指针）。取消后即便等待也不应执行 refresh。
            const m = new MockController();
            const timerId: number = RenderRecovery.recover(asController(m), 'https://x/sign');
            clearTimeout(timerId);
            expect(m.refreshCalled).assertEqual(0);
            expect(m.loadUrlCalls.length).assertEqual(0);
        });
        // ────────── captureLastUrl（供 recover 的 fallback 兜底）──────────
        it('captureLastUrl_extractsUrlFromEvent', 0, () => {
            const event: any = { url: 'https://x/page2' } as any;
            expect(RenderRecovery.captureLastUrl(event, 'https://x/page1')).assertEqual('https://x/page2');
        });
        it('captureLastUrl_emptyUrl_keepsCurrent', 0, () => {
            // 事件 url 为空 → 不覆盖原值
            const event: any = { url: '' } as any;
            expect(RenderRecovery.captureLastUrl(event, 'https://x/page1')).assertEqual('https://x/page1');
        });
        it('captureLastUrl_missingUrl_keepsCurrent', 0, () => {
            // 事件无 url 字段 → 不覆盖原值
            const event: any = {} as any;
            expect(RenderRecovery.captureLastUrl(event, 'https://x/page1')).assertEqual('https://x/page1');
        });
    });
}
