/// <reference path="../typings/tsd.d.ts" />
'use strict';

import {Observable} from 'rxjs';
import * as chai from 'chai';
import * as helpers from './helpers';
import {Collection} from '../src/blow-collection';

const expect = chai.expect;

describe('Collection', () => {
  let collection;

  helpers.checkClassExport(Collection);

  before(() => {
    collection = new Collection();
  });

  it('generate id', done => {
    const data = [
      { title: 'title 1' },
      { title: 'title 2' },
      { title: 'title 3' }
    ];

    Observable.from(data)
      .mergeMap(book => collection.create(book))
      .subscribe(
      item => expect(item['_id']).to.be.ok,
      error => console.log(error),
      () => {
        expect(collection.size).to.be.equal(3);
        done();
      });
  });

  it('use passed id', done => {
    const data = [
      { title: 'title 1', _id: 1 },
      { title: 'title 2', _id: 2 },
      { title: 'title 3', _id: 3 }
    ];
    let index = 0;

    Observable.from(data)
    .mergeMap(book => collection.create(book))
      .subscribe(
      item => expect(item['_id']).to.be.equal(data[index++]._id),
      error => console.log(error),
      () => {
        expect(collection.size).to.be.equal(6);
        done();
      });
  });

  it('count', done => {
    collection.count({title: 'title 1'})
      .subscribe(
        c => expect(c).to.be.equal(2),
        error => console.log(error),
        () => done()
      );
  });

  it('update', done => {
    collection.update({title: 'title 2'}, {title: 'title 3'})
      .subscribe(
        c => expect(c).to.be.equal(2),
        error => console.log(error),
        () => done()
      );
  });

  it('find', done => {
    let count = 0;
    collection.find({where: {title: 'title 3'}})
      .subscribe(
        c => {
          expect(c.title).to.be.equal('title 3');
          count++;
        },
        error => console.log(error),
        () => {
          expect(count).to.be.equal(4);
          done();
        }
      );
  });

  it('find with skip', done => {
    let count = 0;
    collection.find({where: {_id: {$lt: 3}}, sort: {_id: 1}, limit: 1})
      .subscribe(
        c => {
          expect(c._id).to.be.equal(1);
          count++;
        },
        error => console.log(error),
        () => {
          expect(count).to.be.equal(1);
          done();
        }
      );
  });

  it('find - where conditions', done => {
    const $neq = collection.find({where: {_id: {$neq: 1}}}).toArray().do(arr => expect(arr.length).to.be.equal(5));
    const $lte =  collection.find({where: {_id: {$lte: 1}}}).toArray().do(arr => expect(arr.length).to.be.equal(1));
    const $in = collection.find({where: {_id: {$in: [1]}}}).toArray().do(arr => expect(arr.length).to.be.equal(1));
    const $nin = collection.find({where: {_id: {$nin: [1]}}}).toArray().do(arr => expect(arr.length).to.be.equal(5));

    Observable.from([$neq, $lte, $in, $nin])
      .mergeMap((i: any) => i)
      .subscribe(() => { /** ok */ }, err => console.log(err), () => done());
  });

  it('findOne', done => {
    collection.findOne({where: {title: 'title 3'}}).toArray().map(d => d.length)
      .subscribe(s => expect(s).to.be.equal(1), error => console.log(error), () => done());
  });

  it('findById', done => {
    collection.findById(3)
      .subscribe(b => expect(b.title).to.be.equal('title 3'), error => console.log(error), () => done());
  });

  it('destroy by id', done => {
    collection.destroyById(1)
      .subscribe(
        c => {
          expect(c).to.be.equal(true);
        },
        error => console.log(error),
        () => {
          done();
        }
      );
  });

  it('destroy', done => {
    collection.destroy({_id: {$neq: 2}})
      .subscribe(
        c => {
          expect(c).to.be.equal(4);
        },
        error => console.log(error),
        () => {
          done();
        }
      );
  });

  it('exists', done => {
    collection.exists(1)
      .mergeMap(ex => {
        expect(ex).to.be.false;
        return collection.exists(2);
      })
      .subscribe(b => expect(b).to.be.true, error => console.log(error), () => done());
  });

  it('find or create', done => {
    collection.findOrCreate({title: 'title 10'}, {title: 'title 10'})
      .mergeMap(i => {
        expect(i._id).to.be.ok;
        return collection.findOrCreate({_id: i._id}, {title: 'title 11'});
      })
      .subscribe(i => expect(i.title).to.be.equal('title 10'), err => console.log(err), () => done());
  });

  it('update or create', done => {
    collection.updateOrCreate({_id: 10, title: '30'})
      .mergeMap(() => {
        expect(collection.size).to.be.equal(3);
        return collection.updateOrCreate({_id: 10, title: '50'});
      })
      .subscribe(i => expect(i.title).to.be.equal('50'), err => console.log(err), () => done());
  });

  it('don\'t keep reference', done => {
    collection = new Collection();
    let data = {title: 'title 1'};
    let obj1;
    collection.create(data)
      .mergeMap(result => {
        expect(data['_id']).to.be.equal(undefined);
        obj1 = result;
        return collection.update({_id: obj1._id}, {title: 'title 2'});
      })
      .mergeMap(() => collection.find())
      .subscribe(result => {
        expect(obj1.title).to.be.not.equal(result.title);
      }, err => console.log(err), () => done());
  });
});
