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

import * as chai from 'chai';
import * as _ from './helpers';
import {Observable} from 'rxjs';

import {MemoryAdapter} from '../src/adapters/MemoryAdapter';
import {Connection} from '../src/Connection';
import {PersistedModel} from '../src/PersistedModel';

import {data} from './fixtures/data';
import * as models from './fixtures/models';
import {manager} from '../src/manager';

manager.defineConnection({
  name: 'default',
  adapter: MemoryAdapter
});

const expect = chai.expect;

describe('PersistedModel', () => {
  let book;
  
  beforeEach(done => {
    manager.init().subscribe(connection => {        
      done();
    });
  });
  
  _.checkClassExport(PersistedModel);

  
  it('prototype.destroy()', done => {
    book = new models.Book(data[0]);
    book.save()
      .mergeMap(book => book.destroy())
      .subscribe(result => {
        expect(result).to.be.true;
        done();
      });
  });
  
  it('prototype.save()', done => {
    book = new models.Book(data[0]);
    book.save().subscribe(result => {
      expect(book.title).to.be.equal(data[0].title);
      expect(book.price).to.be.equal(data[0].price);
      expect(book.available).to.be.equal(data[0].available);
      expect(book.id).to.be.ok;
      done();
    });
  });
  
  it('prototype.refresh()', done => {
    book = new models.Book(data[0]);
    book.save()
      .mergeMap(result => models.Book.update({id: result.id}, Object.assign({}, data[1])))
      .mergeMap(result => {
        expect(book.title).to.be.not.equal(data[1].title);
        expect(book.price).to.be.not.equal(data[1].price);
        return book.refresh();
      })      
      .subscribe(result => {
        expect(book.title).to.be.equal(data[1].title);
        expect(book.price).to.be.equal(data[1].price);        
        done();
      });
  });
  
  it('init()', () => {
    const book = models.Book.init(data[0]);
    expect(book.toJSON()).to.be.deep.equal(data[0]);
  });
  
  it('count()', done => {   
    book = new models.Book(data[0]); 
    models.Book.create(book)
      .mergeMap(() => models.Book.create(data[1]))
      .mergeMap(() => models.Book.create(data[2]))
      .mergeMap(() => models.Book.count())
      .mergeMap(count => {
        expect(count).to.be.equal(6);
        return models.Book.count({available: true}); 
      })
      .subscribe(count => {
        expect(count).to.be.equal(4);
      }, _.log, () => done());
  });
  
  it('destroy()', done => {
    let id;    
    models.Book.create(data[0])
      .mergeMap(book => {
        id = book['id'];
        return models.Book.destroy({id: book['id']});
      })
      .mergeMap(result => {
        expect(result).to.be.equal(1);
        return models.Book.exists(id); 
      })
      .subscribe(ex => {
        expect(ex).to.be.false;
      }, _.log, () => done());
  });
  
  it('find()', done => {
    models.Book.create(data[0])
      .mergeMap(() => models.Book.create(data[1]))
      .mergeMap(() => models.Book.create(data[2]))
      .mergeMap(() => models.Book.find({where: {available: true}}).toArray())
      .do(row => {
        expect((<any>row).length).to.be.equal(6);
        expect(row[0]['title']).to.be.equal('title');
        expect(row[0]['price']).to.be.equal(5);
      })
      .subscribe(ex => {}, _.log, () => done());
  });
  
  it('findOne()', done => {
    let lp = 0;
    models.Book.create(data[0])
      .mergeMap(() => models.Book.create(data[1]))
      .mergeMap(() => models.Book.create(data[2]))
      .mergeMap(() => models.Book.findOne({where: {available: true}}))      
      .subscribe(ex => {
        lp++;
      }, _.log, () => {
        expect(lp).to.be.equal(1);
        done();
      });
  });
  
  it('findOrCreate()', done => {
    let id;
    models.Book.findOrCreate({title: data[0].title}, data[0])
      .mergeMap(result => {
        id = result['id'];
        return models.Book.findOrCreate({title: data[0].title}, data[0]);
      })
      .subscribe(result => {
        expect(result['id']).to.be.equal(id);
        expect(result['title']).to.be.equal(data[0].title);
        expect(result['price']).to.be.equal(data[0].price);
      }, _.log, () => {
        done();
      });
  });

});