import { FilteredMarkerSource } from './filtered-marker-source';
import { expect } from 'chai';
import sinon from 'sinon';
import { FilterItem } from './filter-item';
import { Marker } from './marker';

const sleep = time => new Promise(resolve => setTimeout(resolve, time));

describe('FilteredMarkerSource', () => {

    /** @type {FilteredMarkerSource} */
    let subject;

    beforeEach(() => {
        subject = new FilteredMarkerSource({ });
    });

    it('should call callbacks if new filter item added', () => {
        const cb = sinon.fake();
        subject.allFilterItems(cb);
        expect(cb.callCount).to.equal(1);
        expect(cb.getCall(0).args[0].length).to.equal(0);

        subject.addFilterItem(new FilterItem());
        expect(cb.callCount).to.equal(2);
        expect(cb.getCall(1).args[0].length).to.equal(1);
    });

    it('should call callbacks if new marker added', () => {
        const cb = sinon.fake();
        subject.allMarkers(cb);
        expect(cb.callCount).to.equal(1);
        expect(cb.getCall(0).args[0].length).to.equal(0);

        const marker = new Marker();
        marker.coordinates = { latitude: 50, longitude: 50 };
        subject.addMarker(marker);

        expect(cb.callCount).to.equal(2);
        expect(cb.getCall(1).args[0].length).to.equal(1);
    });


    it('should call callbacks if path changed', () => {
        const cb = sinon.fake();
        subject.currentFilter(cb);
        expect(cb.callCount).to.equal(1);
        expect(cb.getCall(0).args[0]).to.equal(null);

        const item = new FilterItem();
        item.path = '/foo';
        subject.setCurrentFilter(item);

        expect(cb.callCount).to.equal(2);
        expect(cb.getCall(1).args[0].path).to.equal('/foo');
    });

    it('should call filtered markers callbacks if new markers added', async () => {
        const cb = sinon.fake();
        subject.filteredMarkers(cb);

        await sleep(500);
        expect(cb.callCount).to.equal(1);

        const marker = new Marker();
        marker.coordinates = { latitude: 50, longitude: 50 };
        subject.addMarker(marker);
        await sleep(500);
        expect(cb.callCount).to.equal(2);
    });

    it('should call filtered markers callbacks if new filter path changed', async () => {
        const cb = sinon.fake();
        subject.filteredMarkers(cb);

        await sleep(500);
        expect(cb.callCount).to.equal(1);

        const item = new FilterItem();
        item.path = '/foo';
        subject.setCurrentFilter(item);
        await sleep(500);

        expect(cb.callCount).to.equal(2);
    });


    it('should filter markers based on path', async () => {
        const foo = new Marker();
        foo.coordinates = { latitude: 10, longitude: 10 };
        foo.paths = [ '/foo' ];
        subject.addMarker(foo);

        const fooBar = new Marker();
        fooBar.coordinates = { latitude: 10, longitude: 10 };
        fooBar.paths = [ '/foo/bar' ];
        subject.addMarker(fooBar);

        const test = new Marker();
        test.coordinates = { latitude: 10, longitude: 10 };
        test.paths = [ '/test' ];
        subject.addMarker(test);

        // Initial run: no filter
        const cb = sinon.fake();
        subject.filteredMarkers(cb);

        await sleep(500);
        expect(cb.lastCall.args[0].length).to.equal(3);


        const itemOne = new FilterItem();
        itemOne.path = '/foo';
        subject.setCurrentFilter(itemOne);
        await sleep(500);
        expect(cb.lastCall.args[0].length).to.equal(2);

        const itemTwo = new FilterItem();
        itemTwo.path = '/foo/bar';
        subject.setCurrentFilter(itemTwo);
        await sleep(500);
        expect(cb.lastCall.args[0].length).to.equal(1);
    });

});
