import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";
import { Observer } from "rxjs/Observer";
import PouchDB from "pouchdb";

import * as PouchFind from "pouchdb-find";

import "rxjs/add/observable/throw";
import "rxjs/add/observable/fromPromise";
import "rxjs/add/observable/from";
import "rxjs/add/operator/concatMap";

PouchDB.plugin(PouchFind);

@Injectable()
export class PouchService {

    pouchDB: any;

    constructor() {
        this.initialize();
    }

    /**
     *
     */
    private initialize(destroy?: boolean): Observable<any> {
        // PouchDB.debug.enable('pouchdb:api');
        this.pouchDB = new PouchDB("odoo", {
            auto_compaction: true
        });

        return Observable.fromPromise(this.pouchDB.createIndex({
            index: {
                fields: ['odoo_model']
            }
        }));
    }

    /**
     *
     */
    save(data: any): Observable<any> {
        if (!data.odoo_model) {
            return Observable.throw("Error: Cannot save data without model name");
        }

        return Observable.fromPromise(this.pouchDB.post(data));
    }

    /**
     * 
     * @param data 
     * @param model 
     */
    bulkSave(data: Array<any>): Observable<any> {
        return Observable.fromPromise(this.pouchDB.bulkDocs(data));
    }

    /**
     * 
     * @param data 
     */
    remove(data: any): Observable<any> {
        if (!data._id || !data._rev) {
            return Observable.throw("Error: Cannot remove data without id or rev");
        }

        return Observable.fromPromise(this.pouchDB.remove(data));
    }

    /**
     * 
     * @param data 
     */
    bulkRemove(data: Array<any>): Observable<any> {
        return this.bulkSave(data.map(item => {
            item._deleted = true;

            return item;
        }));
    }

    /**
     *
     */
    removeAll(type: string): Observable<any> {
        return this.getAll(type).concatMap(result => this.bulkRemove(result.docs));
    }

    /**
     *
     */
    get(data: any): Observable<any> {
        if (!data._id) {
            return Observable.throw("Error: Cannot get data without id");
        }

        return Observable.fromPromise(this.pouchDB.get(data._id));
    }

    /**
     *
     */
    getAll(odoo_model: string): Observable<any> {
        return Observable.fromPromise(this.pouchDB.find({
            selector: {
                odoo_model: {
                    $eq: odoo_model
                }
            }
        }));
    }

    /**
     *
     */
    destroy(): Observable<any> {
        return Observable.fromPromise(this.pouchDB.destroy());
    }

    /**
     *
     */
    destroyAndInitialize() {
        return this.destroy().concatMap(response => this.initialize(response.ok));
    }

    /**
     * 
     */
    changes(): Observable<any> {
        return Observable.create((o: Observer<any>) => {
            this.pouchDB.changes({
                since: "now",
                live: true
            }).on("change", change => {
                o.next(change);
            }).on("error", error => { 
                o.next(error);
            });
        });
    }
}
