import { Updux } from '.';
import { action } from './actions';

test('basic selectors', () => {
    const updux = new Updux({
        subduxes: {
            bogeys: new Updux({
                selectors: {
                    bogey: (bogeys) => (id) => bogeys[id],
                },
            }),
        },
        selectors: {
            bogeys: ({ bogeys }) => bogeys,
        },
    });

    const state = {
        bogeys: {
            foo: 1,
            bar: 2,
        },
    };

    expect(updux.selectors.bogeys(state)).toMatchObject({ foo: 1, bar: 2 });
    expect(updux.selectors.bogey(state)('foo')).toEqual(1);
});

test('available in the middleware', () => {
    const doIt = action('doIt');

    const updux = new Updux({
        actions: { doIt },
        subduxes: {
            bogeys: new Updux({
                initial: { enkidu: 'foo' },
                selectors: {
                    bogey: (bogeys) => (id) => bogeys[id],
                },
            }),
        },
        effects: {
            doIt:
                ({ selectors: { bogey }, getState }) =>
                (next) =>
                (action) => {
                    next({
                        ...action,
                        payload: bogey(getState())('enkidu'),
                    });
                },
        },
        mutations: {
            doIt: (payload) => (state) => ({ ...state, payload }),
        },
    });

    const store = updux.createStore();
    store.dispatch(updux.actions.doIt());

    expect(store.getState()).toMatchObject({ payload: 'foo' });
});

test('selector typescript', () => {
    const bar = new Updux({
        initial: { baz: 1 },
        selectors: {
            getBaz: (state) => state.baz,
            getStringBaz: (state) => `${state.baz}`,
            getMultBaz: (state) => (mult) => state.baz * mult,
        },
    });

    expect(bar.selectors.getBaz(bar.initial)).toEqual(1);
    expect(bar.selectors.getMultBaz({ baz: 3 })(2)).toEqual(6);

    // subduxes
    const foo = new Updux({
        subduxes: { bar },
        selectors: {
            getRoot: () => 'root',
        },
    });

    expect(foo.selectors.getBaz(foo.initial)).toEqual(1);
    expect(foo.selectors.getMultBaz({ bar: { baz: 3 } })(2)).toEqual(6);

    expect(foo.selectors.getRoot).toBeTruthy();

    /// no root selector
    const foo3 = new Updux({
        subduxes: {
            quux: new Updux({}),
            bar: new Updux({
                selectors: {
                    getBaz: () => 'baz',
                },
            }),
        },
    });

    expect(foo3.selectors.getBaz).toBeTruthy();
});

test('selector in mw', () => {
    const myDux = new Updux({
        initial: { stuff: 12 },
        subduxes: {
            bar: new Updux({
                initial: 'potato',
                selectors: { getBar: () => 'meh' },
            }),
        },
        selectors: {
            getStuff: (state) => state.stuff,
        },
    });

    let ranEffect = false;

    myDux.addEffect('*', ({ selectors, getState }) => () => () => {
        ['getStuff', 'getBar'].forEach((selector) =>
            expect(typeof selectors[selector]).toEqual('function')
        );

        expect(getState.getStuff()).toEqual(12);
        expect(getState.getBar()).toEqual('meh');

        ranEffect = true;
    });

    myDux.createStore().dispatch({ type: 'foo' });

    expect(ranEffect).toBeTruthy();
});
