// Tests for the UTC Timestamps setting.
//
// The checkbox was moved out of the Token Spam Protection well and into the
// Display well next to the theme selector.  It is wired by id through the $()
// helper, so the move cannot break the handler — but nothing in the suite said
// so.  These tests pin both halves down: the markup lives in Display and
// nowhere else, and the value still round-trips through storage.

const fs = require("fs");
const path = require("path");

const { makeStorageStub } = require("./support/storageStub");

const POPUP_HTML = fs.readFileSync(
    path.join(__dirname, "..", "src", "popup", "index.html"),
    "utf8",
);

// The body of one `<div class="bg-well ...">` well, selected by its heading.
function wellWithHeading(html, heading) {
    const headingIndex = html.indexOf(
        '<h3 class="font-bold mb-1">' + heading + "</h3>",
    );
    expect(headingIndex).toBeGreaterThan(-1);
    const start = html.lastIndexOf('<div class="bg-well', headingIndex);
    const end = html.indexOf('<div class="bg-well', headingIndex);
    return html.slice(start, end === -1 ? html.length : end);
}

describe("the UTC Timestamps checkbox placement", () => {
    test("the checkbox appears exactly once in the popup markup", () => {
        const matches = POPUP_HTML.match(/id="settings-utc-timestamps"/g);
        expect(matches).toHaveLength(1);
    });

    test("it renders in the Display well, alongside the theme selector", () => {
        const display = wellWithHeading(POPUP_HTML, "Display");

        expect(display).toContain('id="settings-utc-timestamps"');
        expect(display).toContain('id="settings-theme"');
    });

    test("it does not render in the Token Spam Protection well", () => {
        const spam = wellWithHeading(POPUP_HTML, "Token Spam Protection");

        expect(spam).not.toContain('id="settings-utc-timestamps"');
        // The filters that do belong there are untouched.
        expect(spam).toContain('id="settings-hide-low-holders"');
        expect(spam).toContain('id="settings-hide-fraud-contracts"');
        expect(spam).toContain('id="settings-hide-dust"');
        expect(spam).toContain('id="settings-dust-threshold"');
    });
});

describe("the UTC Timestamps setting round-trips through storage", () => {
    let storage;

    // The stub clones in both directions, as the real chrome.storage.local
    // does. It used to alias, which is fatal to a round-trip test in
    // particular: the object the module holds and the object "storage" holds
    // are then the same object, so the setting appears to have been persisted
    // and read back on a build where neither happened. See
    // tests/support/storageStub.js.
    function loadStateModule() {
        storage = makeStorageStub();
        global.chrome = { storage };
        jest.resetModules();
        return require("../src/shared/state");
    }

    afterEach(() => {
        delete global.chrome;
    });

    test("defaults to off with nothing persisted", async () => {
        const { state, loadState } = loadStateModule();

        await loadState();

        expect(state.utcTimestamps).toBe(false);
    });

    test("an enabled checkbox is persisted and read back", async () => {
        const first = loadStateModule();

        // What the change handler in views/settings.js does.
        first.state.utcTimestamps = true;
        await first.saveState();
        expect(storage.read("autistmask").utcTimestamps).toBe(true);

        // A fresh popup load sees it — and, before that load, refuses to
        // answer at all rather than reporting the default. That refusal is
        // what makes the assertion below evidence of a read from storage
        // instead of a value that was already sitting in memory
        // (https://git.eeqj.de/sneak/AutistMask/issues/324).
        jest.resetModules();
        const second = require("../src/shared/state");
        expect(() => second.state.utcTimestamps).toThrow(
            second.StateNotLoadedError,
        );
        await second.loadState();
        expect(second.state.utcTimestamps).toBe(true);
    });

    test("turning it back off is persisted too", async () => {
        const { state, saveState, loadState } = loadStateModule();

        state.utcTimestamps = true;
        await saveState();
        state.utcTimestamps = false;
        await saveState();

        state.utcTimestamps = true;
        await loadState();
        expect(state.utcTimestamps).toBe(false);
    });
});
