import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable, AsyncSubject, ReplaySubject } from 'rxjs';
import { map, filter, shareReplay, first, flatMap, withLatestFrom, tap } from 'rxjs/operators';

export interface BasicAuthorizationOptions {
  client: string;
  password: string;
  endpoints: string[];
}

export const SKIP_BASIC_AUTHORIZATION_INTERCEPTOR = '';

@Injectable()
export class BasicAuthorizationInterceptor implements HttpInterceptor {
  private optionsSub = new ReplaySubject<{ token: string; endpointMatchers: RegExp[] }>();

  constructor(options$: Observable<BasicAuthorizationOptions>) {
    options$
      .pipe(
        map((options) => {
          const token = btoa(`${options.client}:${options.password}`);
          const endpointMatchers: RegExp[] = [];
          for (const endpoint of options.endpoints) {
            endpointMatchers.push(new RegExp(`^${endpoint}`, 'i'));
          }

          return { token, endpointMatchers };
        })
      )
      .subscribe(this.optionsSub);
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    // let request = req;

    if (req.headers.has('SKIP_BASIC_AUTHORIZATION_INTERCEPTOR')) {
      return next.handle(req);
    }

    return this.optionsSub.pipe(
      first(),
      map((options) => {
        let request = req;
        if (options.endpointMatchers.find((matcher) => matcher.test(req.url))) {
          const headers = req.headers.set('Authorization', `Basic ${options.token}`);
          request = req.clone({ headers });
        }

        return request;
      }),
      flatMap((request) => next.handle(request))
    );
  }
}
