const ADDRESS = "0x66133E8ea0f5D1d612D2502a968757D1048c214a";

function oneWallet() {
    return [{ name: "Wallet 1", type: "hd", addresses: [ADDRESS] }];
}

// state.js resolves the storage API at require time, so the stub has to exist
// before the module is loaded, and the module registry has to be reset between
// cases because `state` is a module-level singleton.
function loadModuleWith(persisted) {
    jest.resetModules();
    const set = jest.fn(async () => {});
    global.chrome = {
        storage: {
            local: {
                get: jest.fn(async () =>
                    persisted ? { autistmask: persisted } : {},
                ),
                set,
            },
        },
    };
    return { mod: require("../src/shared/state"), set };
}

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

describe("loadState hasWallet reconciliation", () => {
    // A profile that deleted its last wallet on a build predating the write
    // path fix keeps hasWallet: true forever. It must load as no wallet, which
    // is what sends the popup to the welcome view.
    test("stored hasWallet true with zero wallets loads as no wallet", async () => {
        const { mod } = loadModuleWith({ hasWallet: true, wallets: [] });
        await mod.loadState();
        expect(mod.state.hasWallet).toBe(false);
    });

    test("stored hasWallet true with a missing wallets key loads as no wallet", async () => {
        const { mod } = loadModuleWith({ hasWallet: true });
        await mod.loadState();
        expect(mod.state.wallets).toEqual([]);
        expect(mod.state.hasWallet).toBe(false);
    });

    test("stored hasWallet false with one wallet loads as having a wallet", async () => {
        const { mod } = loadModuleWith({
            hasWallet: false,
            wallets: oneWallet(),
        });
        await mod.loadState();
        expect(mod.state.hasWallet).toBe(true);
    });

    test("absent hasWallet with wallets present loads as having a wallet", async () => {
        const { mod } = loadModuleWith({ wallets: oneWallet() });
        await mod.loadState();
        expect(mod.state.hasWallet).toBe(true);
    });

    test("consistent stored states are preserved", async () => {
        const withWallet = loadModuleWith({
            hasWallet: true,
            wallets: oneWallet(),
        });
        await withWallet.mod.loadState();
        expect(withWallet.mod.state.hasWallet).toBe(true);

        const without = loadModuleWith({ hasWallet: false, wallets: [] });
        await without.mod.loadState();
        expect(without.mod.state.hasWallet).toBe(false);
    });

    test("empty storage leaves the default no-wallet state", async () => {
        const { mod } = loadModuleWith(null);
        await mod.loadState();
        expect(mod.state.hasWallet).toBe(false);
        expect(mod.state.wallets).toEqual([]);
    });

    // The correction is derived on every load rather than written back, so a
    // load never has a storage side effect.
    test("loadState does not write to storage", async () => {
        const { mod, set } = loadModuleWith({ hasWallet: true, wallets: [] });
        await mod.loadState();
        expect(set).not.toHaveBeenCalled();
    });

    // Deriving must not disturb the rest of the load.
    test("other persisted fields still load", async () => {
        const { mod } = loadModuleWith({
            hasWallet: false,
            wallets: oneWallet(),
            networkId: "sepolia",
            theme: "dark",
            activeAddress: ADDRESS,
        });
        await mod.loadState();
        expect(mod.state.networkId).toBe("sepolia");
        expect(mod.state.theme).toBe("dark");
        expect(mod.state.activeAddress).toBe(ADDRESS);
    });
});
