import { jsx as _jsx } from "react/jsx-runtime";
import React from "react";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { render, Text } from "ink";
import { Writable } from "node:stream";
import { useTranscriptScroll } from "./useTranscriptScroll.js";
import { getTranscriptScrollOffset, resetTranscriptScroll, setTranscriptScrollBounds, } from "../stores/transcript-scroll-store.js";
const inputHandlers = [];
vi.mock("ink", async (importOriginal) => {
    const actual = await importOriginal();
    return {
        ...actual,
        useInput: (handler, opts) => {
            if (opts?.isActive !== false)
                inputHandlers.push(handler);
        },
    };
});
function key(overrides = {}) {
    return {
        upArrow: false,
        downArrow: false,
        leftArrow: false,
        rightArrow: false,
        pageDown: false,
        pageUp: false,
        return: false,
        escape: false,
        ctrl: false,
        shift: false,
        tab: false,
        backspace: false,
        delete: false,
        meta: false,
        ...overrides,
    };
}
function Harness({ totalLines, viewportRows, resetToken }) {
    useTranscriptScroll({ totalLines, viewportRows, active: true, resetToken });
    return _jsx(Text, { children: getTranscriptScrollOffset() });
}
function renderHarness(props) {
    inputHandlers.length = 0;
    const stdout = new Writable({
        write(_chunk, _encoding, callback) {
            callback();
        },
    });
    stdout.columns = 80;
    stdout.rows = 24;
    const instance = render(_jsx(Harness, { ...props }), { stdout, patchConsole: false });
    return { instance };
}
async function press(input, k = {}) {
    inputHandlers.at(-1)?.(input, key(k));
    // Let React flush the state update + commit before assertions read it.
    await new Promise((resolve) => setImmediate(resolve));
}
async function flush() {
    await new Promise((resolve) => setImmediate(resolve));
}
// The store is a module singleton; reset it before each test.
beforeEach(() => {
    setTranscriptScrollBounds(0);
    resetTranscriptScroll();
});
describe("useTranscriptScroll", () => {
    it("starts stuck to the bottom", async () => {
        renderHarness({ totalLines: 100, viewportRows: 10, resetToken: 0 });
        await flush();
        expect(getTranscriptScrollOffset()).toBe(0);
    });
    it("syncs the store bounds from totalLines and viewportRows", async () => {
        renderHarness({ totalLines: 100, viewportRows: 10, resetToken: 0 });
        await flush();
        // maxOffset = 100 - 10 = 90, so g (top) lands at 90.
        await press("g");
        expect(getTranscriptScrollOffset()).toBe(90);
    });
    it("pages up by viewportRows - 1", async () => {
        renderHarness({ totalLines: 100, viewportRows: 10, resetToken: 0 });
        await flush();
        await press("", { pageUp: true });
        expect(getTranscriptScrollOffset()).toBe(9);
    });
    it("pages down toward the bottom and clamps at 0", async () => {
        renderHarness({ totalLines: 100, viewportRows: 10, resetToken: 0 });
        await flush();
        await press("", { pageUp: true });
        await press("", { pageDown: true });
        expect(getTranscriptScrollOffset()).toBe(0);
    });
    it("scrolls line-by-line with shift+arrows", async () => {
        renderHarness({ totalLines: 100, viewportRows: 10, resetToken: 0 });
        await flush();
        await press("", { shift: true, upArrow: true });
        expect(getTranscriptScrollOffset()).toBe(1);
        await press("", { shift: true, downArrow: true });
        expect(getTranscriptScrollOffset()).toBe(0);
    });
    it("jumps to top with g and bottom with G", async () => {
        renderHarness({ totalLines: 100, viewportRows: 10, resetToken: 0 });
        await flush();
        await press("g");
        expect(getTranscriptScrollOffset()).toBe(90);
        await press("G");
        expect(getTranscriptScrollOffset()).toBe(0);
    });
    it("resets to the bottom when the reset token changes", async () => {
        const { instance } = renderHarness({ totalLines: 100, viewportRows: 10, resetToken: 0 });
        await flush();
        await press("", { pageUp: true });
        expect(getTranscriptScrollOffset()).toBeGreaterThan(0);
        instance.rerender(_jsx(Harness, { totalLines: 100, viewportRows: 10, resetToken: 1 }));
        await flush();
        expect(getTranscriptScrollOffset()).toBe(0);
    });
});
//# sourceMappingURL=useTranscriptScroll.test.js.map