import { Injectable } from '@angular/core';
import { Headers, Http, RequestOptions, Response, ResponseOptions, ResponseOptionsArgs } from '@angular/http';

import { Observable } from 'rxjs/Observable';

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

import { IAccount, ICreateUser, IUser, IUserAccounts, IUserCredentials, User } from './user.model';

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

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

import { ErrorObservable } from 'rxjs/observable/ErrorObservable';
import { Subject } from 'rxjs/Subject';
import { ReplaySubject } from 'rxjs/ReplaySubject';
import { ResponseType } from '@angular/http/src/enums';

@Injectable()
export class UserService {
  userAccounts: IUserAccounts = undefined;
  accounts: IAccount[] = [];
  user: IUser = undefined;
  testParam: string;

  get userChanged(): Observable<IUser | undefined> {
    return this.userChange$.asObservable().debounceTime(10);
  }

  get userIsKnokser(): boolean {
    try {
      return Boolean(this.user.userIsKnokser);
    } catch (e) {
      return false;
    }
  }

  get UserCredentials(): IUserCredentials {
    return this.user || this.userCredentials;
  }

  set UserCredentials(value: IUserCredentials) {
    this.userCredentials = value;
  }

  private userCredentials: IUserCredentials;
  private userChange$: ReplaySubject<IUser | undefined> = new ReplaySubject<IUser | undefined>(1);

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

  createUser(user: ICreateUser): Observable<IUser> {
    let headers: Headers = new Headers({
      'Content-Type': 'application/json',
      Authorization: this.tokenService.authorization
    });
    let options: RequestOptions = new RequestOptions({headers});
    let req: Observable<Response> = this.http.post(`${SETTINGS.API_URL}/general/newuser`, user, options);
    return req.map((response: Response) => {
      let data: IApiResponseError | IApiResponseSuccess<IUser> = response.json();
      if (isApiResponseError(data)) {
        throw Observable.throw(data.error);
      }
      let createdUser: IUser = data.result;
      this.user = createdUser;
      createdUser.password = user.password;
      this.userChange$.next(this.user);
      return createdUser;
    }).catch(this.handleError);
  }

  loadUser(): Observable<IUserAccounts> {
    let headers: Headers = new Headers({
      'Content-Type': 'application/json',
      Authorization: this.tokenService.authorization
    });
    let options: RequestOptions = new RequestOptions({headers});
    let req: Observable<Response> = this.http.get(`${SETTINGS.API_URL}/account/useraccounts`, options);
    return req.catch((response: Response): any => {
      // console.error(response);
      let opts: ResponseOptionsArgs;
      let responseOptions: ResponseOptions;
      opts = {
        status: response.status,
        statusText: response.statusText,
        headers: response.headers,
        type: response.type,
        url: response.url,
        body: {error: {id: -1, msg: `Got ${response.status} ${response.statusText}`, errors: []}}
      };
      responseOptions = new ResponseOptions(opts);
      response = new Response(responseOptions);
      // throw Observable.throw({id: -1, msg: `Got ${response.status} ${response.statusText}`, errors: []});
      // return Observable.empty();
      return Observable.of(response);
    }).map((response: Response) => {
      // console.warn(response);
      let data: IApiResponseError | IApiResponseSuccess<IUserAccounts> = response.json();
      if (isApiResponseError(data)) {
        this.user = undefined;
        this.userChange$.next(this.user);
        // throw data.error;
        throw Observable.throw(data.error);
      }
      this.userAccounts = data.result;
      this.accounts = data.result.accounts;
      this.user = data.result.user;
      this.userChange$.next(this.user);
      return data.result;
    }).catch(this.handleError);
  }

  sendPasswordReset(email: string, url: string): Observable<boolean> {
    const headers: Headers = new Headers({
      'Content-Type': 'application/json',
      Authorization: this.tokenService.authorization
    });
    const options: RequestOptions = new RequestOptions({headers});
    const req: Observable<Response> = this.http.post(`${SETTINGS.API_URL}/general/sendpasswordreset`, {email: email, url: url}, options);
    return req.map((response: Response) => {
      const data: IApiResponseError | IApiResponseSuccess<boolean> = response.json();
      if (isApiResponseError(data)) {
        throw Observable.throw(data.error);
      }
      return data.result;
    }).catch(error => {
      console.log(error);
      return Observable.throw(error.msg || error);
    });
  }

  resetPassword(token: string, newPassword: string): Observable<boolean> {
    const headers: Headers = new Headers({
      'Content-Type': 'application/json',
      Authorization: this.tokenService.authorization
    });
    const options: RequestOptions = new RequestOptions({headers});
    const req: Observable<Response> = this.http.post(`${SETTINGS.API_URL}/general/passwordreset`, {token: token, newPassword: newPassword}, options);
    return req.map((response: Response) => {
      const data: IApiResponseError | IApiResponseSuccess<boolean> = response.json();
      if (isApiResponseError(data)) {
        throw Observable.throw(data.error);
      }
      return data.result;
    }).catch(error => {
      console.log(error);
      return Observable.throw(error.msg || error);
    });
  }

  checkPasswordResetToken(token: string): Observable<boolean> {
    const headers: Headers = new Headers({
      'Content-Type': 'application/json',
      Authorization: this.tokenService.authorization
    });
    const options: RequestOptions = new RequestOptions({headers});
    const req: Observable<Response> = this.http.post(`${SETTINGS.API_URL}/general/checkpasswordresettoken`, {token: token}, options);
    return req.map((response: Response) => {
      const data: IApiResponseError | IApiResponseSuccess<boolean> = response.json();
      if (isApiResponseError(data)) {
        throw Observable.throw(data.error);
      }
      return data.result;
    }).catch(error => {
      console.log(error);
      return Observable.throw(error.msg || error);
    });
  }

  updateUser(user: IUser): Observable<IUser> {
    let headers: Headers = new Headers({
      'Content-Type': 'application/json',
      Authorization: this.tokenService.authorization
    });
    let options: RequestOptions = new RequestOptions({headers});
    let req: Observable<Response> = this.http.put(`${SETTINGS.API_URL}/general/user`, user, options);
    return req.map((response: Response) => {
      let data: IApiResponseError | IApiResponseSuccess<IUser> = response.json();
      if (isApiResponseError(data)) {
        this.userChange$.next(this.user);
        throw Observable.throw(data.error);
      }
      this.user = Object.assign(this.user, data.result);
      this.userChange$.next(this.user);
      return data.result;
    }).catch(this.handleError);
  }

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