import { Injectable } from '@angular/core'
import { HttpClient } from '@angular/common/http'
import { Subject } from 'rxjs/Subject'

import 'rxjs/add/operator/toPromise'

import { HelperService } from './svc.helper'

@Injectable()
export class MenuService {
    
    constructor(
        private helper: HelperService,
        private http: HttpClient
    ) { 
        this.secondaryState$.subscribe((result) => {
			this.currentSecondaryState = result
		})
    }


    // Vars
    // ----------------
    cachedMenus = {}
    cachedCategories
    currentSecondaryState

    // Observable String Source
    private stateSource             = new Subject<boolean>()
    private secondaryStateSource    = new Subject<boolean>()
    private secondaryMenuSource     = new Subject<any>()
    private activePrimarySource     = new Subject<string>()

    // Observable String Stream
    state$              = this.stateSource.asObservable()
    secondaryState$     = this.secondaryStateSource.asObservable()
    secondaryMenu$      = this.secondaryMenuSource.asObservable()
    activePrimary$      = this.activePrimarySource.asObservable()
    






    // Functions
    // -----------------


    /**
     * Error Handling
     * @param error 
     */
    private handleError(error: any): Promise<any> {
        console.error('An error occurred', error) // eslint-disable-line
        return Promise.reject(error.message || error)
    }






    // STATES

    /**
     * Set next state value of menu to false
     */
    close() {
        this.stateSource.next(false)
    }

    /**
     * Toggle menu state to given value
     * @param state 
     */
    toggleState(state: boolean) {
        this.stateSource.next(state)
    }


    /**
     * Set next state value of secondary menu to false
     */
    closeSecondary() {
        this.secondaryStateSource.next(false)
    }
    /**
     * Set next state value of secondary menu to true
     */
    openSecondary() {
        this.secondaryStateSource.next(true)
    }

    /**
     * Toggle secondary state
     */
    toggleSecondary() {
        this.secondaryStateSource.next(!this.currentSecondaryState)
    }


    /**
     * Set active primary name
     * @param active 
     */
    setActivePrimary(active:string) {
        this.activePrimarySource.next(active)
    }



    // Secondary menu

    /**
     * Get menu items based on `type`: category or page
     * and `target`: id
     * @param type 
     * @param target 
     */
    getSecondaryMenu(type:string, target:number, name:string = '') {
        let secondaryMenu = {
            parent: '',
            type: '',
            menu: []
        }

        if(!!type) {
            switch(type) {

                case 'category':
                    this.getMenuCategories().then((result) => {
                        // Filter categories
                        let filteredCats = result.find(function(cat){return cat.id == target })
                        
                        // Set values
                        // TODO: Tell Mikkel to homogonise naming
                        secondaryMenu.parent = filteredCats.urlkey
                        secondaryMenu.type = type
                        secondaryMenu.menu = filteredCats.children

                        // Update observable
                        this.secondaryMenuSource.next(secondaryMenu)
                    })
                    break

                case 'page':

                    this.getMenu(name).then((result) => {
                        // Filter pages
                        let filteredPages = result.find(function(page){return page.id == target })

                        // Set values
                        // TODO: Tell Mikkel to homogonise naming
                        secondaryMenu.parent = filteredPages.urlKey
                        secondaryMenu.type = type
                        secondaryMenu.menu = filteredPages.children

                        // Update observable
                        this.secondaryMenuSource.next(secondaryMenu)
                    })
                    break
            }
        }
        else {
            this.handleError('no type given')
            this.secondaryMenuSource.next(secondaryMenu)
        }

    }





    // Menu data handling

    /**
     * Get menu main or specified menu.
     * Returns cached menu if menu has already been called before
     * 
     * @todo Typing of response
     * @param name 
     */
    getMenu(name:string = ''): Promise<any[]> {
        name = !!name ? name : 'default'
        let menuNameStr     = name !== 'default' ? '&name=' + name : ''

        // Only get menu if it is not already in cachedMenus array
        if(!!!this.cachedMenus[name]) {
            
            return this.http.get(this.helper.server + 'feed/get/menu' + this.helper.credentials + menuNameStr)
                .toPromise()
                .then((response: any) => {
                    let res = response

                    if(res.status == 'error') {
                        console.error( {status: 'error', request: 'feed/get/menu/' + menuNameStr, message: res.data.errorMessage} ) // eslint-disable-line
                        return []
                    } else {
                        this.cachedMenus[name] = res.data.menu
                        return res.data.menu
                    }

                    
                })
                .catch(this.handleError)
        }
        else {

            return new Promise((resolve, reject) => {
                resolve(this.cachedMenus[name])
            })
        }
    }


    /**
     * Returns an array of categories
     * 
     * @todo Type response
     */
    getMenuCategories(): Promise<any[]> {
        if(!!!this.cachedCategories){

            return this.http.get(this.helper.server + 'feed/get/category' + this.helper.credentials)
                .toPromise()
                .then((response: any) => {
                    this.cachedCategories = response.data.categories
                    return response.data.categories
                })
                .catch(this.handleError)
        }
        else {

            return new Promise((resolve, reject) => {
                resolve(this.cachedCategories)
            })
        }
    }
}