import { Injectable } from '@angular/core';
import { ProtocolService } from '@ucap-webmessenger/protocol';
import { Observable } from 'rxjs';
import { take, map, takeWhile } from 'rxjs/operators';
import {
  AuthRequest,
  AuthResponse,
  encodeAuth,
  decodeAuth
} from '../protocols/auth';
import {
  SVC_TYPE_QUERY_DATA,
  SSVC_TYPE_QUERY_AUTH_REQ,
  SSVC_TYPE_QUERY_DEPT_REQ,
  SSVC_TYPE_QUERY_DEPT_RES,
  SSVC_TYPE_QUERY_DEPT_DATA,
  SSVC_TYPE_QUERY_DEPT_USER_RES,
  SSVC_TYPE_QUERY_DEPT_USER_DATA,
  SSVC_TYPE_QUERY_DEPT_USER_REQ,
  SSVC_TYPE_QUERY_USER_SEQ_REQ,
  SSVC_TYPE_QUERY_USER_SEQ_RES,
  SSVC_TYPE_QUERY_USER_SEQ_DATA,
  SSVC_TYPE_QUERY_USER_SEQ_DATA2,
  SSVC_TYPE_QUERY_USER_ID_REQ,
  SSVC_TYPE_QUERY_USER_ID_RES,
  SSVC_TYPE_QUERY_USER_ID_DATA,
  SSVC_TYPE_QUERY_USER_BY_DN_REQ,
  SSVC_TYPE_QUERY_USER_BY_DN_RES,
  SSVC_TYPE_QUERY_USER_BY_DN_DATA,
  SSVC_TYPE_QUERY_DATA_USER_REQ,
  SSVC_TYPE_QUERY_EXT_DATA_USER_REQ,
  SSVC_TYPE_QUERY_DEPT_USER2_REQ,
  SSVC_TYPE_QUERY_DEPT_USER2_DATA,
  SSVC_TYPE_QUERY_DEPT_USER2_RES
} from '../types/service';
import {
  DeptRequest,
  DeptResponse,
  encodeDept,
  decodeDept,
  decodeDeptData,
  DeptData
} from '../protocols/dept';
import {
  encodeDeptUser,
  decodeDeptUser,
  decodeDeptUserData,
  DeptUserRequest,
  DeptUserData,
  DeptUserResponse
} from '../protocols/dept-user';
import {
  UserSeqData,
  UserSeqData2,
  encodeUserSeq,
  decodeUserSeqData,
  decodeUserSeqData2,
  UserSeqRequest
} from '../protocols/user-seq';
import {
  UserIdRequest,
  UserIdResponse,
  UserIdData,
  encodeUserId,
  decodeUserId,
  decodeUserIdData
} from '../protocols/user-id';
import {
  UserDnRequest,
  UserDnResponse,
  UserDnData,
  encodeUserDn,
  decodeUserDnData,
  decodeUserDn
} from '../protocols/user-dn';
import {
  DataUserRequest,
  DataUserResponse,
  encodeDataUser,
  decodeDataUser
} from '../protocols/data-user';
import {
  DataUserExtRequest,
  DataUserExtResponse,
  encodeDataUserExt,
  decodeDataUserExt
} from '../protocols/data-user-ext';

@Injectable({
  providedIn: 'root'
})
export class QueryProtocolService {
  constructor(private protocolService: ProtocolService) {}

  public auth(req: AuthRequest): Observable<AuthResponse> {
    return this.protocolService
      .call(SVC_TYPE_QUERY_DATA, SSVC_TYPE_QUERY_AUTH_REQ, ...encodeAuth(req))
      .pipe(
        take(1),
        map(res => decodeAuth(res))
      );
  }

  public dept(req: DeptRequest): Observable<DeptResponse | DeptData> {
    return this.protocolService
      .call(SVC_TYPE_QUERY_DATA, SSVC_TYPE_QUERY_DEPT_REQ, ...encodeDept(req))
      .pipe(
        takeWhile(res => SSVC_TYPE_QUERY_DEPT_RES !== res.subServiceType, true),
        map(res => {
          if (SSVC_TYPE_QUERY_DEPT_DATA === res.subServiceType) {
            return decodeDeptData(res);
          }

          return decodeDept(res);
        })
      );
  }
  public deptUser(
    req: DeptUserRequest
  ): Observable<DeptUserResponse | DeptUserData> {
    return this.protocolService
      .call(
        SVC_TYPE_QUERY_DATA,
        SSVC_TYPE_QUERY_DEPT_USER_REQ,
        ...encodeDeptUser(req)
      )
      .pipe(
        takeWhile(
          res => SSVC_TYPE_QUERY_DEPT_USER_RES !== res.subServiceType,
          true
        ),
        map(res => {
          if (SSVC_TYPE_QUERY_DEPT_USER_DATA === res.subServiceType) {
            return decodeDeptUserData(res);
          }

          return decodeDeptUser(res);
        })
      );
  }
  public deptUser2(
    req: DeptUserRequest
  ): Observable<DeptUserResponse | DeptUserData> {
    return this.protocolService
      .call(
        SVC_TYPE_QUERY_DATA,
        SSVC_TYPE_QUERY_DEPT_USER2_REQ,
        ...encodeDeptUser(req)
      )
      .pipe(
        takeWhile(
          res => SSVC_TYPE_QUERY_DEPT_USER2_RES !== res.subServiceType,
          true
        ),
        map(res => {
          if (SSVC_TYPE_QUERY_DEPT_USER2_DATA === res.subServiceType) {
            return decodeDeptUserData(res);
          }

          return decodeDeptUser(res);
        })
      );
  }

  public userSeq(req: UserSeqRequest): Observable<UserSeqData | UserSeqData2> {
    return this.protocolService
      .call(
        SVC_TYPE_QUERY_DATA,
        SSVC_TYPE_QUERY_USER_SEQ_REQ,
        ...encodeUserSeq(req)
      )
      .pipe(
        takeWhile(
          res => SSVC_TYPE_QUERY_USER_SEQ_RES !== res.subServiceType,
          true
        ),
        map(res => {
          if (SSVC_TYPE_QUERY_USER_SEQ_DATA === res.subServiceType) {
            return decodeUserSeqData(res);
          } else if (SSVC_TYPE_QUERY_USER_SEQ_DATA2 === res.subServiceType) {
            return decodeUserSeqData2(res);
          }
        })
      );
  }
  public userId(req: UserIdRequest): Observable<UserIdResponse | UserIdData> {
    return this.protocolService
      .call(
        SVC_TYPE_QUERY_DATA,
        SSVC_TYPE_QUERY_USER_ID_REQ,
        ...encodeUserId(req)
      )
      .pipe(
        takeWhile(
          res => SSVC_TYPE_QUERY_USER_ID_RES !== res.subServiceType,
          true
        ),
        map(res => {
          if (SSVC_TYPE_QUERY_USER_ID_DATA === res.subServiceType) {
            return decodeUserIdData(res);
          }

          return decodeUserId(res);
        })
      );
  }
  public userDn(req: UserDnRequest): Observable<UserDnResponse | UserDnData> {
    return this.protocolService
      .call(
        SVC_TYPE_QUERY_DATA,
        SSVC_TYPE_QUERY_USER_BY_DN_REQ,
        ...encodeUserDn(req)
      )
      .pipe(
        takeWhile(
          res => SSVC_TYPE_QUERY_USER_BY_DN_RES !== res.subServiceType,
          true
        ),
        map(res => {
          if (SSVC_TYPE_QUERY_USER_BY_DN_DATA === res.subServiceType) {
            return decodeUserDnData(res);
          }

          return decodeUserDn(res);
        })
      );
  }

  public dataUser(req: DataUserRequest): Observable<DataUserResponse> {
    return this.protocolService
      .call(
        SVC_TYPE_QUERY_DATA,
        SSVC_TYPE_QUERY_DATA_USER_REQ,
        ...encodeDataUser(req)
      )
      .pipe(
        take(1),
        map(res => decodeDataUser(res))
      );
  }
  public dataUserExt(req: DataUserExtRequest): Observable<DataUserExtResponse> {
    return this.protocolService
      .call(
        SVC_TYPE_QUERY_DATA,
        SSVC_TYPE_QUERY_EXT_DATA_USER_REQ,
        ...encodeDataUserExt(req)
      )
      .pipe(
        take(1),
        map(res => decodeDataUserExt(res))
      );
  }
}
