import { Injectable } from '@angular/core';
import { Http, Response, Headers, RequestOptions } from '@angular/http';
import { Observable } from 'rxjs/Observable'
import { Token } from '../components/token-component';
import { PreferencesProvider } from './preferences-provider';

import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import 'rxjs/add/observable/throw'

@Injectable()
export class TokenService {

    username: string = 'admin';
    password: string = 'admin';
    url: string = 'http://192.168.88.123:8069';

    constructor(
        private http: Http,
        private preferencesProvider: PreferencesProvider
    ) {
    }

    /**
     * Pass token auth
     */
    getToken(): Promise<any> {
        return new Promise((resolve, reject) => {
            this.getTokenFromServer().subscribe(data => {
                this.preferencesProvider.setHost(this.url);
                this.preferencesProvider.setToken(data.value);

                resolve(data.value);
            }, err => {
                reject(err);
            });
        });
    }

    /**
     * Check if token is present locally
     */
    tokenIsPresent(): boolean {
        return this.getTokenFromLocal() ? true : false;
    }

    /**
     * Check local token on the server
     */
    checkTokenOnServer(): Observable<Response> {
        let body = 'token=' + this.getTokenFromLocal();
        let headers = new Headers({ 'Content-Type':  'application/x-www-form-urlencoded' });
        let options = new RequestOptions({ headers: headers });

        return this.http.post(this.normalizeCheckUrl(this.url), body, options).map(this.extractCheckData).catch(this.handleError);
    }
    
    /**
    * Extract check value from token verification
    */
    private extractCheckData(response: Response): boolean {
        let body = response.json();
        return body.token == 'valid' ? true : false;
    }

    /**
     * Get token from local storage
     */
    private getTokenFromLocal(): string {
        return this.preferencesProvider.getToken();
    }

    /**
     * Handle error if ocurred
     */
    private normalizeCheckUrl(url: string): string {
        return (url.startsWith('http://') || url.startsWith('https://')  ? url : 'http://' + url) + '/api/check';
    }

    /**
     * Normalize provide url
     */
    private normalizeJwtUrl(url: string): string {
        return (url.startsWith('http://') || url.startsWith('https://') ? url : 'http://' + url) + '/api/jwt';
    }

    /**
     * Get token from server
     */
    private getTokenFromServer(): Observable<Token> {
        let body = 'username=' + this.username + '&password=' + this.password;
        let headers = new Headers({ 'Content-Type':  'application/x-www-form-urlencoded' });
        let options = new RequestOptions({ headers: headers });

        return this.http.post(this.normalizeJwtUrl(this.url), body, options).map(this.extractTokenData).catch(this.handleError);
    }

    /**
     * Extract token data from http response
     */
    private extractTokenData(response: Response) {
        let body = response.json();
        let token = new Token(body.token);

        return token;
    }

    /**
     * Handle error if ocurred
     */
    private handleError(error: any) {
        let msg = error._body;

        return Observable.throw(msg);
    }
}
