import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { ErrorService } from '../error/component/error.service';
import { Injectable } from '@angular/core';
import { OAuthErrorEvent } from 'angular-oauth2-oidc';
import { LoggingService, LogType } from '../services/logging.service';
import { isWhiteList } from '../utils/http-interceptor-whitelist.utils';

@Injectable()
export class HttpErrorHandlerInterceptor implements HttpInterceptor {
  constructor(private errorService: ErrorService, private logger: LoggingService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).pipe(catchError((error: HttpErrorResponse, caught: any) => this.handleError(error)));
  }

  getInvalidProperties(error: any) {
    if (
      error &&
      this.showInvalidProperties(error.url, error.status) &&
      error.error &&
      error.error.invalidProperties &&
      Object.keys(error.error.invalidProperties) &&
      Object.keys(error.error.invalidProperties).length > 0
    ) {
      return JSON.stringify(error.error.invalidProperties);
    }
    return undefined;
  }

  getMessage(error: any) {
    return error.error && error.error ? error.error.message : undefined;
  }

  private handleError(error: HttpErrorResponse) {
    if (!isWhiteList(error.url)) {
      if (isWhiteList(error.url, error.status)) {
        return throwError(error);
      }
      let errorMessage = '';
      this.logger.log('HUGENDUBEL INSTORE MA APP Backend', error, LogType.Error);
      if (error.error instanceof OAuthErrorEvent) {
        return;
      } else if (error.error instanceof ErrorEvent) {
        // client-side error
        errorMessage = `Client-Side => Error: ${error.error.message}`;
        this.errorService.addErrors(error.status, errorMessage, undefined);
      } else {
        // server-side error
        errorMessage = `Server-Side => Error Code: ${error.status}\nMessage: ${error.message}`;
        if (error.status === 503 && error.url.includes('/availability/')) {
          return throwError(errorMessage);
        }

        const message = this.getMessage(error);

        const invalidProperties = this.getInvalidProperties(error);

        const logout = error.status === 401;
        this.errorService.addErrors(error.status, message, invalidProperties, logout);
      }
      return throwError(errorMessage);
    } else {
      return throwError(error);
    }
  }

  private showInvalidProperties(url: string, code: number = -1) {
    const blackList: { url: string; codes: number[] }[] = [{ url: '/order/checkout', codes: [400] }];

    return !blackList.find((entry) => !!url.includes(entry.url) && !!entry.codes.includes(code));
  }
}
