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

import { Observable, Subject } from 'rxjs';
import { map, take, filter, tap, share } from 'rxjs/operators';

import { ProtocolService } from '@ucap-webmessenger/protocol';
import {
  LoginRequest,
  LoginResponse,
  encodeLogin,
  decodeLogin
} from '../protocols/login';
import {
  SVC_TYPE_LOGIN,
  SSVC_TYPE_LOGIN_REQ,
  SVC_TYPE_LOGOUT,
  SSVC_TYPE_LOGOUT_REQ,
  SSVC_TYPE_LOGOUT_REMOTE_REQ,
  SSVC_TYPE_LOGOUT_RES,
  SSVC_TYPE_LOGOUT_REMOTE_NOTI
} from '../types/service';
import {
  LogoutRequest,
  LogoutResponse,
  encodeLogout,
  decodeLogout,
  decodeLogoutNotification
} from '../protocols/logout';
import {
  encodeLogoutRemote,
  decodeLogoutRemote,
  LogoutRemoteRequest,
  LogoutRemoteResponse,
  decodeLogoutRemoteNotification,
  LogoutRemoteNotification
} from '../protocols/logout-remote';

type Notifications = LogoutResponse | LogoutRemoteNotification;

@Injectable({
  providedIn: 'root'
})
export class AuthenticationProtocolService {
  private logoutNotificationSubject: Subject<Notifications>;
  public logoutNotification$: Observable<Notifications>;

  constructor(private protocolService: ProtocolService) {
    this.logoutNotificationSubject = new Subject();
    this.logoutNotification$ = this.logoutNotificationSubject
      .asObservable()
      .pipe(share());

    this.protocolService.serverMessage
      .pipe(
        filter(message => message.serviceType === SVC_TYPE_LOGOUT),
        tap(message => {
          switch (message.subServiceType) {
            case SSVC_TYPE_LOGOUT_RES:
              {
                this.logoutNotificationSubject.next(
                  decodeLogoutNotification(message)
                );
              }
              break;
            case SSVC_TYPE_LOGOUT_REMOTE_NOTI:
              {
                this.logoutNotificationSubject.next(
                  decodeLogoutRemoteNotification(message)
                );
              }
              break;

            default:
              break;
          }
        })
      )
      .subscribe();
  }

  public login(req: LoginRequest): Observable<LoginResponse> {
    return this.protocolService
      .call(SVC_TYPE_LOGIN, SSVC_TYPE_LOGIN_REQ, ...encodeLogin(req))
      .pipe(
        take(1),
        map(res => decodeLogin(res))
      );
  }

  public logout(req: LogoutRequest): Observable<LogoutResponse> {
    return this.protocolService
      .call(SVC_TYPE_LOGOUT, SSVC_TYPE_LOGOUT_REQ, ...encodeLogout(req))
      .pipe(
        take(1),
        map(res => decodeLogout(res))
      );
  }

  public logoutRemote(
    req: LogoutRemoteRequest
  ): Observable<LogoutRemoteResponse> {
    return this.protocolService
      .call(
        SVC_TYPE_LOGOUT,
        SSVC_TYPE_LOGOUT_REMOTE_REQ,
        ...encodeLogoutRemote(req)
      )
      .pipe(
        take(1),
        map(res => decodeLogoutRemote(res))
      );
  }
}
