import { Bus } from "async-i2c-bus";
import { A0,  A2,  A5,  B3, MCP23017 } from "../index";

jest.mock("i2c-bus", () => {
    const createI2cBusMock =
    require("async-i2c-bus/dist/main/lib/createI2cBusMock").default;
    const buffer = Buffer.alloc(0xff, 0);
    for (let i = 0; i < 0xff; i++) {
        buffer[i] = i;
    }
    return {
        open: createI2cBusMock({
            devices: {
                0x20: buffer,
                0x21: Buffer.alloc(0xff, 0),
            },
        }),
    };
});

describe("MCP23017 test suite", () => {
    it("performs an initial opening", async () => {
        const bus = Bus({});
        await bus.open();
        const spy = jest.spyOn(bus, "readI2cBlock");
        const mcp = new MCP23017(bus);
        await mcp.init();
        expect(spy).toHaveBeenLastCalledWith(
            0x20, 0x0, 0x16, spy.mock.calls[spy.mock.calls.length - 1][3]);
    });

    it("performs an initial opening in segregated mode", async () => {
        const bus = Bus({});
        await bus.open();
        const spy = jest.spyOn(bus, "readI2cBlock");
        const mcp = new MCP23017(bus, {address: 0x21, separate: true});
        await mcp.init();
        expect(spy).toHaveBeenNthCalledWith(
            1, 0x21, 0, 0xa, spy.mock.calls[0][3]);
        expect(spy).toHaveBeenNthCalledWith(
            2, 0x21, 0x10, 0xa, spy.mock.calls[0][3]);
    });

    it("performs an initial opening in normal" +
       "mode and change to separate mode", async () => {
        const bus = Bus({});
        await bus.open();
        const spy = jest.spyOn(bus, "readI2cBlock");
        const mcp = new MCP23017(bus);
        await mcp.setSeparate(true);
        await mcp.init();
        expect(spy).toHaveBeenCalledTimes(4);
    });

    it("performs a read on GPIO in mixed mode", async () => {
        const bus = Bus({});
        await bus.open();
        const mcp = new MCP23017(bus);
        await mcp.init();
        const val = await mcp.read();
        expect(val).toEqual(0x1213);
    });

    it("performs a read on GPIO in separate mode", async () => {
        const bus = Bus({});
        await bus.open();
        const mcp = new MCP23017(bus, {separate: true});
        await mcp.init();
        const val = await mcp.read();
        expect(val).toEqual(0x1909);
    });

    it("performs a write on GPIO in normal mode", async () => {
        const bus = Bus({});
        await bus.open();
        const spy = jest.spyOn(bus, "writeWord");
        const mcp = new MCP23017(bus, {address: 0x21});
        await mcp.init();
        await mcp.write(A0 | A5 | B3, 0);
        await mcp.write(A2, A5);
        expect(spy).toHaveBeenCalledTimes(2);
        expect(spy).toHaveBeenNthCalledWith(
            1, 0x21, 0x14, 0x821);
        expect(spy).toHaveBeenNthCalledWith(
            2, 0x21, 0x14, 0x805);
    });

    it("performs a write on GPIO in separate mode", async () => {
        const bus = Bus({});
        await bus.open();
        const spy = jest.spyOn(bus, "writeByte");
        const mcp = new MCP23017(bus, {separate: true});
        await mcp.init();
        await mcp.write(A0 | A5 | B3, 0);
        await mcp.write(A2, A5);
        expect(spy).toHaveBeenNthCalledWith(1, 0x20, 0xa, 0x21);
        expect(spy).toHaveBeenNthCalledWith(2, 0x20, 0x1a, 0x8);
        expect(spy).toHaveBeenNthCalledWith(3, 0x20, 0xa, 0x5);
        expect(spy).toHaveBeenCalledTimes(3);
    });
});
