import { Http, RequestOptions, Response } from '@angular/http';

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

import 'rxjs/add/observable/of';
import 'rxjs/add/observable/throw';

import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';

import { ICountries, ICountry } from './country.model';

import { TokenService } from '../token/token.service';

import { IApiError, IApiResponseError, IApiResponseSuccess, isApiResponseError } from '../token/apiresponse.model';

@Injectable()
export class CountryService {
    country: ICountry;

    constructor(private http: Http, private tokenService: TokenService) { }

    get Country(): Observable<ICountry> {
        if (this.country) {
            return Observable.of(this.country);
        }
        return this.http
            .get('//geoip.nekudo.com/api/')
            .map((response: Response) => {
                const {country: {code}}: { country: { code: string } } = response.json();
                return code;
            })
            .flatMap((countrySymbol: string) =>
                this.http
                    .get(`${SETTINGS.API_URL}/general/Countries/${countrySymbol}`,
                    new RequestOptions({ headers: this.tokenService.authorizationHeaders })))
            .map((response: Response) => {
                const data: IApiResponseError | IApiResponseSuccess<ICountries> = response.json();
                if (isApiResponseError(data)) {
                    return Observable.throw(data.error);
                }
                return data.result;
            })
            .map((countries: ICountries) => {
                // const [country]: ICountry[] = countries.items;
                if (countries.items.length > 0) {
                    this.country = countries.items[0];
                    return countries.items[0];
                }
            }).catch(this.handleError);
    }

    private handleError(error: IApiError): Observable<ICountry> {
        return Observable.throw(error.msg || error);
    }
}
