// angular
import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
// libs
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
// libs
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
// app
import { QueryAction, SetEntriesAction, UnreadAction } from '../actions/loop-assignment.action';
import { APIDispatcher, APIRequestOptions, ResponseBody } from '../utils/index';
import { LoopAssignmentPayload, LoopAssignmentSubmissionPayload } from '../interfaces/index';

@Injectable()
export class LoopAssignmentService extends APIDispatcher {

    constructor(public http: Http, public store: Store<any>) {
        super(http, store);
    }

    fetch(identities: string[], page: number = 0, size: number = 10, options?: APIRequestOptions) {
        return Observable.create((observer: any) => {
            this.post('ma_loop/api/v1/assignments/fetch', identities, page, size, options).map(res => res.json())
                .catch(this.handleError)
                .subscribe((response: ResponseBody) => {
                    this.loaded = true;
                    this.lastRequest = response;
                    this.lastRequest.payload = identities;
                    this.lastRequest.currentPage = page;
                    this.lastRequest.requestSize = size;
                    this.lastRequest.options = options;
                    this.store.dispatch(new QueryAction(response.content));
                    observer.next(response.content);
                    observer.complete();
                });
        });
    }

    fetchForUsers(
        userIdentities: string[],
        page: number = 0,
        size: number = 10,
        options?: APIRequestOptions,
        forStore: Boolean = true
    ) {
        return Observable.create((observer: any) => {
            this.post('ma_loop/api/v1/assignments/users', userIdentities, page, size, options).map(res => res.json())
                .catch(this.handleError)
                .subscribe((response: ResponseBody) => {
                    if(forStore) {
                        this.loaded = true;
                        this.lastRequest = response;
                        this.lastRequest.payload = userIdentities;
                        this.lastRequest.currentPage = page;
                        this.lastRequest.requestSize = size;
                        this.lastRequest.options = options;
                        this.store.dispatch(new QueryAction(response.content));
                    }
                    observer.next(response);
                    observer.complete();
                });
        });
    }

    checkUnread(userIdentities: string[]) {
        return Observable.create((observer: any) => {
            this.post('ma_loop/api/v1/assignments/users', userIdentities, 0, 1, {
                unread: 'unread',
                sortBy: 'due_at'
            })
            .map(res => res.json())
            .catch(this.handleError)
            .subscribe((response: ResponseBody) => {
                this.store.dispatch(new UnreadAction(response.totalElements));
                observer.next(response);
                observer.complete();
            });
        });
    }

    create(payload: LoopAssignmentPayload) {
        return this.http.post('ma_loop/api/v1/assignments', payload)
            .catch(this.handleError);
    }

    update(payload: LoopAssignmentPayload) {
        return this.http.put('ma_loop/api/v1/assignments', payload)
            .catch(this.handleError);
    }

    submit(identity: string, payload: LoopAssignmentSubmissionPayload) {
        return this.http.post('ma_loop/api/v1/assignment_submission/' + identity, payload)
            .catch(this.handleError);
    }

    /**
     * Resets the entries in the app-state slice for Loop Assignments
     *
     *
     * @memberOf LoopAssignmentService
     */
    resetEntries() {
        this.loaded = false;
        this.lastRequest = undefined;
        this.store.dispatch(new SetEntriesAction([]));
    }


    /**
     * Fetches the next available page for assignments, if any
     */
    getNextFetchPage() {
        if(this.hasNext && !this.fetchingNext) {
            this.fetchingNext = true;
            this.fetch(
                this.lastRequest.payload,
                this.lastRequest.currentPage + 1,
                this.lastRequest.requestSize,
                this.lastRequest.options
            ).subscribe(() => {
                this.fetchingNext = false;
            });
        }
    }

    /**
     * Fetches the next available page for assignments, if any
     */
    getNextFetchUsersPage() {
        if(this.hasNext && !this.fetchingNext) {
            this.fetchingNext = true;
            this.fetchForUsers(
                this.lastRequest.payload,
                this.lastRequest.currentPage + 1,
                this.lastRequest.requestSize,
                this.lastRequest.options
            ).subscribe(() => {
                this.fetchingNext = false;
            });
        }
    }
}

