import create from "../store";

jest.mock("react");

import { useEffect, useState } from "react";

describe("Store Library", () => {
  it("creates a store", () => {
    let v;
    useState.mockImplementation(fn => {
      v = fn();
      return [
        v,
        x => {
          v = x;
        },
      ];
    });

    let unsub = null;
    useEffect.mockImplementation(fn => {
      if (unsub) {
        unsub();
      }
      unsub = fn();
    });

    const [hooks, actions, watch] = create(store => ({
      counter: 0,
      increment: () => {
        store.counter++;
      },
      changeCounter: counter => store({ counter }),
      doInvalid: () => {
        store.invalidKey = 7;
      },

      getReflectedKeys: () => Reflect.ownKeys(store),
    }));

    const changes = [];
    watch.onChange((...args) => {
      changes.push(args);
    });
    const calls = [];
    watch.onCall((...args) => {
      calls.push(args);
    });

    expect(hooks.useCounter).toBeInstanceOf(Function);
    expect(actions.increment).toBeInstanceOf(Function);
    expect(actions.changeCounter).toBeInstanceOf(Function);
    expect(watch.onChange).toBeInstanceOf(Function);
    expect(watch.onCall).toBeInstanceOf(Function);
    expect(watch.setGlobal).toBeInstanceOf(Function);

    expect(hooks.useCounter(() => true)).toBe(0);
    actions.increment();
    expect(hooks.useCounter()).toBe(1);
    actions.changeCounter(x => x * 3);
    expect(hooks.useCounter()).toBe(3);
    actions.changeCounter(10);
    expect(hooks.useCounter()).toBe(10);

    expect(actions.getReflectedKeys()).toMatchSnapshot();

    expect(actions.doInvalid).toThrow();

    expect(changes).toMatchSnapshot();
    expect(calls).toMatchSnapshot();
    watch.setGlobal("testing-store");
    expect(window["testing-store"]).toBeDefined();
  });
});
