/*
 * Copyright (C) 2018 StApps
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, version 3.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <https://www.gnu.org/licenses/>.
 */
import {
  SCBulkAddRoute,
  SCBulkDoneRoute,
  SCDish,
  SCMessage,
  SCThingOriginType,
  SCThingType,
} from '@openstapps/core';
import {expect} from 'chai';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import chaiSpies from 'chai-spies';
import {HttpClient, Bulk, Client, BulkWithMultipleTypesError} from '../src/index.js';
import {addHours} from 'date-fns';

chai.should();
chai.use(chaiSpies);
chai.use(chaiAsPromised);

describe('Bulk', function () {
  const sandbox = chai.spy.sandbox();

  const bulkAddRoute = new SCBulkAddRoute();
  const bulkDoneRoute = new SCBulkDoneRoute();

  const httpClient = new HttpClient();
  const client = new Client(httpClient, 'http://localhost');

  afterEach(function () {
    sandbox.restore();
  });

  it('should add', async function () {
    sandbox.on(client, 'invokeRoute', () => {
      return {};
    });

    expect(client.invokeRoute).not.to.have.been.called();
    const expiration = addHours(new Date(), 1).toISOString();

    const bulk = new Bulk(SCThingType.Dish, client, {
      expiration,
      source: 'foo',
      state: 'in progress',
      type: SCThingType.Dish,
      uid: 'bar',
    });

    const dish: SCDish = {
      categories: ['main dish'],
      name: 'foobar',
      origin: {
        indexed: new Date().toISOString(),
        name: 'bar',
        type: SCThingOriginType.Remote,
      },
      type: SCThingType.Dish,
      uid: 'foo',
    };

    await bulk.add(dish);

    expect(client.invokeRoute).to.have.been.first.called.with(
      bulkAddRoute,
      {
        UID: 'bar',
      },
      dish,
    );
  });

  it('should fail add', async function () {
    const bulk = new Bulk(SCThingType.Dish, client, {
      expiration: addHours(new Date(), 1).toISOString(),
      source: 'foo',
      state: 'in progress',
      type: SCThingType.Dish,
      uid: 'bar',
    });

    const message: SCMessage = {
      audiences: ['students'],
      categories: ['news'],
      messageBody: 'Lorem ipsum.',
      name: 'foobar',
      origin: {
        indexed: new Date().toISOString(),
        name: 'bar',
        type: SCThingOriginType.Remote,
      },
      type: SCThingType.Message,
      uid: 'foo',
    };

    await bulk.add(message).should.be.rejectedWith(BulkWithMultipleTypesError);
  });

  it('should construct', function () {
    expect(() => {
      return new Bulk(SCThingType.Dish, client, {
        expiration: addHours(new Date(), 1).toISOString(),
        source: 'foo',
        state: 'in progress',
        type: SCThingType.Dish,
        uid: 'bar',
      });
    }).not.to.throw();
  });

  it('should done', async function () {
    sandbox.on(client, 'invokeRoute', () => {
      return {};
    });

    expect(client.invokeRoute).not.to.have.been.called();

    const bulk = new Bulk(SCThingType.Dish, client, {
      expiration: addHours(new Date(), 1).toISOString(),
      source: 'foo',
      state: 'in progress',
      type: SCThingType.Dish,
      uid: 'bar',
    });

    await bulk.done();

    expect(client.invokeRoute).to.have.been.first.called.with(bulkDoneRoute, {
      UID: 'bar',
    });
  });
});
