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

import {Observable} from 'rxjs';
import {isObject} from 'util';
import {Query} from 'blow-query';
import * as chai from 'chai';
import * as helpers from './helpers';
import {adapters} from '../src/blow-data';
import * as models from './fixtures/models';
import {phonesData} from './fixtures/data';
import {manager} from '../src/manager';

const expect = chai.expect;

manager.defineConnection({
  name: 'mongo',
  adapter: adapters.MongoDBAdapter,
  params: {
    url: 'mongodb://localhost:27017/test'
  }
});

const fillData = () => {
  return Observable.from(phonesData)
      .mergeMap(data => models.Phone.create(data))
      .toArray()
}

describe('MongoDBAdapter', () => {
  
  beforeEach(done => {
    manager.init()
      .mergeMap(() => models.Phone.destroy())
      .subscribe(connection => {                    
        done();
      });
  });
  
  helpers.checkClassExport(adapters.MongoDBAdapter);
  
  it('create', done => {
    Observable.from(phonesData)
      .mergeMap(data => models.Phone.create(data))
      .subscribe(row => {
        expect(row['_id']).to.be.ok;
      }, err => console.log(err), () => done());
  });
  
  it('count', done => {
    fillData()
      .mergeMap(() => models.Phone.count())
      .subscribe(count => {
        expect(count).to.be.equal(32);
      }, err => console.log(err), () => done());
  });
  
  it('findById', done => {
    let phone;
    fillData()
      .mergeMap(phones => {
        phone = phones[10];
        return models.Phone.findById(phones[10]['_id']);
      })
      .subscribe(row => {
        expect(row['manufacturer']).to.be.equal(phone['manufacturer']);
        expect(row['model']).to.be.equal(phone['model']);
      }, err => console.log(err), () => {
        done();
      });
  });
  
  it('find', done => {
    fillData()
      .mergeMap(() => models.Phone.find({where: {manufacturer: 'Dell'}, sort: {model: -1}, limit: 1, skip: 1}))
      .subscribe(row => {
        expect(row['manufacturer']).to.be.equal('Dell');
        expect(row['model']).to.be.equal('Venue');
      }, err => console.log(err), () => {
        done();
      });
  });
  
  it('destroyById', done => {
    let phone;
    fillData()
      .mergeMap(phones => {
        phone = phones[10];
        return models.Phone.destroyById(phones[10]['_id']);
      })
      .subscribe(row => {
        expect(row).to.be.true;
      }, err => console.log(err), () => {
        done();
      });
  });
  
  it('exists', done => {
    let phone;
    fillData()
      .mergeMap(phones => {
        phone = phones[10];
        return models.Phone.exists(phones[10]['_id']);
      })
      .subscribe(row => {
        expect(row).to.be.true;
      }, err => console.log(err), () => {
        done();
      });
  });
  
  it('findOne', done => {
    let c = 0;
    fillData().mergeMap(() => models.Phone.findOne({where: {manufacturer: 'Acer'}}))
      .subscribe(row => {
        c++;
        expect(row['manufacturer']).to.be.equal('Acer');
      }, err => console.log(err), () => {
        expect(c).to.be.equal(1);
        done();
      });
  });
  
  it('findOrCreate', done => {
    let id;
    models.Phone.findOrCreate({model: 'iPhone'}, {manufacturer: 'Apple', model: 'iPhone'})
      .mergeMap(result => {
        id = result['_id'];
        return models.Phone.findOrCreate({model: 'iPhone'}, {manufacturer: 'Apple', model: 'iPhone'});
      })
      .subscribe(result => {
        expect(result['_id']).to.be.equal(id);
      }, err => console.log(err), () => done());
  });
  
  it('update', done => {
    fillData()
      .mergeMap(() => models.Phone.update({manufacturer: 'Dell'}, {model: 'model'}))
      .subscribe(row => expect(row).to.be.equal(4),
        err => console.log(err), () => done());
  });
  
  it('updateOrCreate', done => {
    let id;
    let phone;
    fillData()
      .mergeMap(phones => {
        phone = phones[1];
        phone['model'] = 'MODEL 1';
        id = phone['_id'];
        return models.Phone.updateOrCreate(phone);
      })
      .mergeMap(result => {
        expect(result['_id']).to.be.equal(id);        
        return models.Phone.updateOrCreate({
          manufacturer: phone['manufacturer'],
          model: phone['model']
        });
      })
      .subscribe(result => expect(result['_id']).to.be.not.equal(id),
        err => console.log(err), () => done());
  });
});