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

import { PouchService } from "./pouch-service";
import { OdooService } from "../services/odoo-service";

import { DocStatus } from "../enums/doc-status";

import { getMetadataStorage } from "../odoo/utils/metadata-storage";

import "rxjs/add/observable/from";
import "rxjs/add/operator/filter";
import "rxjs/add/operator/concatMap";
import "rxjs/add/operator/concat";
import "rxjs/add/operator/map";
import "rxjs/add/operator/groupBy";
import "rxjs/add/operator/mergeAll";


@Injectable()
export class SyncService {

    constructor(
        public pouch: PouchService,
        public odoo: OdooService
    ) { }

    /**
     *
     */
    do(): Observable<any> {
        return this.login().concat(this.download());
    }

    /**
     *
     */
    protected login(): Observable<any> {
        let loginInformation = JSON.parse(localStorage.getItem("odoo"));

        this.odoo.initialize(loginInformation.host);
        return this.odoo.login(loginInformation.database, loginInformation.username, loginInformation.password);
    }

    /**
     *
     */
    protected logout(): Observable<any> {
        return this.odoo.logout();
    }

    /**
     *
     */
    protected getModels(): Observable<any> {
        return Observable.from(getMetadataStorage().getModels());
    }

    /**
     *
     */
    removeAll(): Observable<any> {
        // return this.getModels().concatMap(item => this.pouch.removeAll(item.model.name));
        return Observable.empty();
    }

    /**
     *
     */
    protected download(): Observable<any> {
        // return this.getModels()
        //     .concatMap(item => this.odoo.searchRead(item.model.name, item.model.domain, item.fields.getNames())
        //     .map(r => {
        //         delete r.length;

        //         return Object.assign(r, {
        //             odoo_model: item.model.name,
        //         });
        //     }))
        //     .concatMap(data => this.pouch.save(data));
        return this.getModels()
            .concatMap(item => this.odoo.searchRead(item.model.name, item.model.domain, item.fields.getNames())
            .map(response => {
                return response.records.map(record => {
                    record.odoo_id = record.id;
                    record.odoo_model = item.model.name;
                    record.odoo_status = "to_none";

                    delete record.id;
                    
                    return record;
                });
            }))
            .concatMap(data => this.pouch.bulkSave(data));
    }

    /**
     *
     */
    protected upload(): Observable<any> {
        return this.getModels()
            .concatMap(item => this.pouch.getAll(item.model.document))
            .concatMap(result => Observable.from(result.docs).filter((r: any) => {
                return r.doc_status != DocStatus.None;
            }).groupBy((r: any) => {
                return r.doc_status;
            }))
            .mergeAll()
            .concatMap(doc => this.send(doc));
    }

    /**
     *
     */
    protected send(data: any): Observable<any> {
        let id: number = data.remote_id;
        let model: string = data.type;

        delete data.type;
        delete data.remote_id;

        if (data.doc_state === DocStatus.Created) {
            return this.odoo.create(model, data);
        }
        
        if (data.doc_state === DocStatus.Updated) {
            return this.odoo.write(model, [[id], data]);
        } 

        return this.odoo.unlink(model, [[id]]);
    }
}