import {
  SSVC_TYPE_GROUP_UPD_RES2,
  SSVC_TYPE_GROUP_ADD_RES,
  SSVC_TYPE_GROUP_DEL_RES
} from './../types/service';
import { Injectable } from '@angular/core';

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

import { ProtocolService } from '@ucap-webmessenger/protocol';
import {
  SVC_TYPE_GROUP,
  SSVC_TYPE_GROUP_ADD_REQ,
  SSVC_TYPE_GROUP_DEL_REQ,
  SSVC_TYPE_GROUP_UPD_REQ,
  SSVC_TYPE_GROUP_UPD_REQ2
} from '../types/service';
import {
  AddRequest,
  encodeAdd,
  decodeAdd,
  AddResponse,
  decodeAddNotification,
  AddNotification
} from '../protocols/add';
import {
  DelRequest,
  encodeDel,
  decodeDel,
  DelResponse,
  decodeDelNotification,
  DelNotification
} from '../protocols/del';
import {
  UpdateRequest,
  encodeUpdate,
  decodeUpdate,
  encodeUpdate2,
  decodeUpdate2,
  UpdateResponse,
  UpdateNotification,
  decodeUpdate2Notification
} from '../protocols/update';

type Notifications = UpdateNotification | AddNotification | DelNotification;

@Injectable({
  providedIn: 'root'
})
export class GroupProtocolService {
  private notificationSubject: Subject<Notifications>;
  public notification$: Observable<Notifications>;

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

    this.protocolService.serverMessage
      .pipe(
        filter(message => message.serviceType === SVC_TYPE_GROUP),
        tap(message => {
          switch (message.subServiceType) {
            case SSVC_TYPE_GROUP_UPD_RES2:
              {
                this.notificationSubject.next(
                  decodeUpdate2Notification(message)
                );
              }
              break;
            case SSVC_TYPE_GROUP_ADD_RES:
              {
                this.notificationSubject.next(decodeAddNotification(message));
              }
              break;
            case SSVC_TYPE_GROUP_DEL_RES:
              {
                this.notificationSubject.next(decodeDelNotification(message));
              }
              break;

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

  public add(req: AddRequest): Observable<AddResponse> {
    return this.protocolService
      .call(SVC_TYPE_GROUP, SSVC_TYPE_GROUP_ADD_REQ, ...encodeAdd(req))
      .pipe(
        take(1),
        map(res => decodeAdd(res))
      );
  }

  public del(req: DelRequest): Observable<DelResponse> {
    return this.protocolService
      .call(SVC_TYPE_GROUP, SSVC_TYPE_GROUP_DEL_REQ, ...encodeDel(req))
      .pipe(
        take(1),
        map(res => decodeDel(res))
      );
  }

  public update(req: UpdateRequest): Observable<UpdateResponse> {
    return this.protocolService
      .call(SVC_TYPE_GROUP, SSVC_TYPE_GROUP_UPD_REQ, ...encodeUpdate(req))
      .pipe(
        take(1),
        map(res => decodeUpdate(res))
      );
  }

  public update2(req: UpdateRequest): Observable<UpdateResponse> {
    return this.protocolService
      .call(SVC_TYPE_GROUP, SSVC_TYPE_GROUP_UPD_REQ2, ...encodeUpdate2(req))
      .pipe(
        take(1),
        map(res => decodeUpdate2(res))
      );
  }
}
