import { delGroupSuccess, buddy2 } from './../store/messenger/sync/actions';
import { Injectable, Inject } from '@angular/core';

import { tap, withLatestFrom } from 'rxjs/operators';

import { Store, select } from '@ngrx/store';

import {
  SSVC_TYPE_LOGOUT_RES,
  SSVC_TYPE_LOGOUT_REMOTE_NOTI,
  AuthenticationProtocolService,
  LogoutResponse,
  LogoutRemoteNotification
} from '@ucap-webmessenger/protocol-authentication';

import { NGXLogger } from 'ngx-logger';
import {
  EventProtocolService,
  SSVC_TYPE_EVENT_SEND_NOTI,
  SendNotification,
  SSVC_TYPE_EVENT_READ_NOTI,
  SSVC_TYPE_EVENT_CANCEL_NOTI,
  SSVC_TYPE_EVENT_DEL_RES,
  SSVC_TYPE_EVENT_SEND_RES,
  SSVC_TYPE_EVENT_READ_RES
} from '@ucap-webmessenger/protocol-event';
import {
  InfoProtocolService,
  SSVC_TYPE_INFO_USER_NOTI,
  UserNotification
} from '@ucap-webmessenger/protocol-info';
import {
  RoomProtocolService,
  SSVC_TYPE_ROOM_INVITE_NOTI,
  SSVC_TYPE_ROOM_EXIT_NOTI,
  SSVC_TYPE_ROOM_EXIT_FORCING_NOTI,
  SSVC_TYPE_ROOM_FONT_UPD_NOTI,
  InviteNotification,
  UpdateNotification as RoomUpdateNotification,
  SSVC_TYPE_ROOM_UPD_RES,
  SSVC_TYPE_ROOM_EXIT_FORCING_RES,
  SSVC_TYPE_ROOM_EXIT_RES,
  SSVC_TYPE_ROOM_INVITE_RES,
  ExitForcingResponse
} from '@ucap-webmessenger/protocol-room';
import {
  StatusProtocolService,
  SSVC_TYPE_STATUS_NOTI,
  StatusNotification
} from '@ucap-webmessenger/protocol-status';
import {
  ReadNotification,
  CancelNotification,
  DelNotification
} from '@ucap-webmessenger/protocol-event';
import {
  ExitNotification,
  ExitForcingNotification,
  UpdateFontNotification
} from '@ucap-webmessenger/protocol-room';
import {
  GroupProtocolService,
  SSVC_TYPE_GROUP_UPD_RES2,
  UpdateNotification as GroupUpdateNotification,
  SSVC_TYPE_GROUP_ADD_RES,
  AddNotification as GroupAddNotification,
  SSVC_TYPE_GROUP_DEL_RES,
  DelNotification as GroupDelNotification
} from '@ucap-webmessenger/protocol-group';
import {
  BuddyProtocolService,
  SSVC_TYPE_BUDDY_UPD_RES,
  UpdateNotification as BuddyUpdateNotification,
  SSVC_TYPE_BUDDY_ADD_RES,
  AddNotification as BuddyAddNotification,
  SSVC_TYPE_BUDDY_DEL_RES,
  DelNotification as BuddyDelNotification
} from '@ucap-webmessenger/protocol-buddy';

import * as AuthenticationStore from '@app/store/account/authentication';
import * as InfoStore from '@app/store/account/info';
import * as EventStore from '@app/store/messenger/event';
import * as SyncStore from '@app/store/messenger/sync';
import * as RoomStore from '@app/store/messenger/room';
import * as StatusStore from '@app/store/messenger/status';
import {
  NotificationRequest,
  NativeService,
  UCAP_NATIVE_SERVICE,
  NotificationType
} from '@ucap-webmessenger/native';
import { StringUtil } from '@ucap-webmessenger/ui';
import {
  UmgProtocolService,
  SSVC_TYPE_UMG_NOTI,
  UmgNotiNotification
} from '@ucap-webmessenger/protocol-umg';
import { LocalStorageService } from '@ucap-webmessenger/web-storage';
import { AppUserInfo, KEY_APP_USER_INFO } from '@app/types/app-user-info.type';

import { environment } from '../../environments/environment';

@Injectable()
export class AppNotificationService {
  constructor(
    private authenticationProtocolService: AuthenticationProtocolService,
    private eventProtocolService: EventProtocolService,
    private infoProtocolService: InfoProtocolService,
    private roomProtocolService: RoomProtocolService,
    private groupProtocolService: GroupProtocolService,
    private buddyProtocolService: BuddyProtocolService,
    private statusProtocolService: StatusProtocolService,
    private umgProtocolService: UmgProtocolService,
    private localStorageService: LocalStorageService,
    @Inject(UCAP_NATIVE_SERVICE) private nativeService: NativeService,
    private store: Store<any>,
    private logger: NGXLogger
  ) {}

  public subscribe(): void {
    this.authenticationProtocolService.logoutNotification$
      .pipe(
        tap(notiOrRes => {
          switch (notiOrRes.SSVC_TYPE) {
            case SSVC_TYPE_LOGOUT_RES:
              {
                const res = notiOrRes as LogoutResponse;
                this.logger.debug(
                  'Notification::authenticationProtocolService::LogoutResponse',
                  res
                );
              }
              break;
            case SSVC_TYPE_LOGOUT_REMOTE_NOTI:
              {
                const noti = notiOrRes as LogoutRemoteNotification;
                this.logger.debug(
                  'Notification::authenticationProtocolService::LogoutRemoteNotification',
                  noti
                );
              }
              break;
            default:
              break;
          }
          this.store.dispatch(AuthenticationStore.loginRedirect());
        })
      )
      .subscribe();

    this.eventProtocolService.notification$
      .pipe(
        tap(notiOrRes => {
          switch (notiOrRes.SSVC_TYPE) {
            case SSVC_TYPE_EVENT_SEND_RES:
            case SSVC_TYPE_EVENT_SEND_NOTI:
              {
                const noti = notiOrRes as SendNotification;
                this.logger.debug(
                  'Notification::eventProtocolService::SendNotification',
                  noti
                );

                this.store.dispatch(
                  EventStore.sendNotification({
                    noti
                  })
                );

                // notification..
                if (notiOrRes.SSVC_TYPE === SSVC_TYPE_EVENT_SEND_NOTI) {
                  const appUserInfo = this.localStorageService.encGet<
                    AppUserInfo
                  >(KEY_APP_USER_INFO, environment.customConfig.appKey);

                  if (appUserInfo.settings.notification.use) {
                    const notiReq: NotificationRequest = {
                      type: NotificationType.Event,
                      seq: noti.roomSeq,
                      title: '메세지가 도착했습니다.',
                      contents: StringUtil.convertFinalEventMessage(
                        noti.eventType,
                        noti.message
                      ),
                      image: '',
                      useSound:
                        'SOUND' === appUserInfo.settings.notification.method ||
                        'SOUND_ALERT' ===
                          appUserInfo.settings.notification.method
                          ? true
                          : false,
                      displayTime:
                        appUserInfo.settings.notification.alertExposureTime
                    };
                    this.nativeService.notify(notiReq);
                  }
                }
              }
              break;
            case SSVC_TYPE_EVENT_READ_RES:
            case SSVC_TYPE_EVENT_READ_NOTI:
              {
                // 대화방 unread count 처리.
                const noti = notiOrRes as ReadNotification;
                this.logger.debug(
                  'Notification::eventProtocolService::ReadNotification',
                  noti
                );
                this.store.dispatch(EventStore.readNotification(noti));
              }
              break;
            case SSVC_TYPE_EVENT_CANCEL_NOTI:
              {
                const noti = notiOrRes as CancelNotification;
                this.logger.debug(
                  'Notification::eventProtocolService::CancelNotification',
                  noti
                );
                this.store.dispatch(
                  EventStore.cancelNotification({
                    noti
                  })
                );
              }
              break;
            case SSVC_TYPE_EVENT_DEL_RES:
              {
                const noti = notiOrRes as DelNotification;
                this.logger.debug(
                  'Notification::eventProtocolService::DelNotification',
                  noti
                );
                this.store.dispatch(
                  EventStore.delNotification({
                    noti
                  })
                );
              }
              break;
            default:
              break;
          }
        })
      )
      .subscribe();
    this.infoProtocolService.notification$
      .pipe(
        tap(notiOrRes => {
          switch (notiOrRes.SSVC_TYPE) {
            case SSVC_TYPE_INFO_USER_NOTI:
              {
                const noti = notiOrRes as UserNotification;
                this.logger.debug(
                  'Notification::infoProtocolService::UserNotification',
                  noti
                );
                this.store.dispatch(
                  InfoStore.userNotification({
                    noti
                  })
                );
              }
              break;
            default:
              break;
          }
        })
      )
      .subscribe();
    this.groupProtocolService.notification$
      .pipe(
        withLatestFrom(
          this.store.pipe(
            select(
              (state: any) => state.messenger.sync.group2.syncDate as string
            )
          )
        ),
        tap(([notiOrRes, syncDate]) => {
          switch (notiOrRes.SSVC_TYPE) {
            case SSVC_TYPE_GROUP_UPD_RES2:
              {
                const noti = notiOrRes as GroupUpdateNotification;
                this.logger.debug(
                  'Notification::groupProtocolService::GroupUpdateNotification',
                  noti
                );
                this.store.dispatch(
                  SyncStore.group2({
                    syncDate
                  })
                );
              }
              break;
            case SSVC_TYPE_GROUP_ADD_RES:
              {
                const noti = notiOrRes as GroupAddNotification;
                this.logger.debug(
                  'Notification::groupProtocolService::GroupAddNotification',
                  noti
                );
                this.store.dispatch(SyncStore.createGroupSuccess(noti));
              }
              break;
            case SSVC_TYPE_GROUP_DEL_RES:
              {
                const noti = notiOrRes as GroupDelNotification;
                this.logger.debug(
                  'Notification::groupProtocolService::GroupDelNotification',
                  noti
                );
                this.store.dispatch(SyncStore.delGroupSuccess(noti));
              }
              break;

            default:
              break;
          }
        })
      )
      .subscribe();
    this.buddyProtocolService.notification$
      .pipe(
        withLatestFrom(
          this.store.pipe(
            select(
              (state: any) => state.messenger.sync.buddy2.syncDate as string
            )
          )
        ),
        tap(([notiOrRes, syncDate]) => {
          switch (notiOrRes.SSVC_TYPE) {
            case SSVC_TYPE_BUDDY_UPD_RES:
              {
                const noti = notiOrRes as BuddyUpdateNotification;
                this.logger.debug(
                  'Notification::groupProtocolService::BuddyUpdateNotification',
                  noti
                );
                this.store.dispatch(SyncStore.updateBuddySuccess(noti));
              }
              break;
            case SSVC_TYPE_BUDDY_ADD_RES:
              {
                const noti = notiOrRes as BuddyAddNotification;
                this.logger.debug(
                  'Notification::groupProtocolService::BuddyAddNotification',
                  noti
                );
                this.store.dispatch(SyncStore.buddy2({ syncDate }));
              }
              break;
            case SSVC_TYPE_BUDDY_DEL_RES:
              {
                const noti = notiOrRes as BuddyDelNotification;
                this.logger.debug(
                  'Notification::groupProtocolService::BuddyDelNotification',
                  noti
                );
                this.store.dispatch(SyncStore.delBuddySuccess(noti));
              }
              break;

            default:
              break;
          }
        })
      )
      .subscribe();
    this.roomProtocolService.notification$
      .pipe(
        tap(notiOrRes => {
          switch (notiOrRes.SSVC_TYPE) {
            case SSVC_TYPE_ROOM_INVITE_RES:
              {
                const noti = notiOrRes as InviteNotification;
                this.logger.debug(
                  'Notification::roomProtocolService::InviteNotification',
                  noti
                );
                this.store.dispatch(
                  RoomStore.inviteSuccess({
                    roomSeq: noti.roomSeq
                  })
                );
              }
              break;
            case SSVC_TYPE_ROOM_UPD_RES:
              {
                const noti = notiOrRes as RoomUpdateNotification;
                this.logger.debug(
                  'Notification::roomProtocolService::RoomUpdateNotification',
                  noti
                );
                this.store.dispatch(
                  RoomStore.updateSuccess({
                    res: {
                      roomSeq: noti.roomSeq,
                      roomName:
                        noti.roomName.trim().length === 0
                          ? ' '
                          : noti.roomName.trim(),
                      receiveAlarm: noti.receiveAlarm,
                      syncAll: false
                    }
                  })
                );
              }
              break;
            case SSVC_TYPE_ROOM_INVITE_NOTI:
              {
                const noti = notiOrRes as InviteNotification;
                this.logger.debug(
                  'Notification::roomProtocolService::InviteNotification',
                  noti
                );
                this.store.dispatch(
                  RoomStore.inviteNotification({
                    noti
                  })
                );
              }
              break;
            case SSVC_TYPE_ROOM_EXIT_RES:
            case SSVC_TYPE_ROOM_EXIT_NOTI:
              {
                const noti = notiOrRes as ExitNotification;
                this.logger.debug(
                  'Notification::roomProtocolService::ExitNotification',
                  noti
                );
                this.store.dispatch(
                  RoomStore.exitNotification({
                    noti
                  })
                );
              }
              break;
            case SSVC_TYPE_ROOM_EXIT_FORCING_RES:
              {
                // 내가 강퇴 진행.
                const res = notiOrRes as ExitForcingResponse;
                this.logger.debug(
                  'Notification::roomProtocolService::ExitForcingNotification RES',
                  res
                );
                this.store.dispatch(
                  RoomStore.exitForcingSuccess({
                    res
                  })
                );
              }
              break;
            case SSVC_TYPE_ROOM_EXIT_FORCING_NOTI:
              {
                // 내가 강퇴 됨.
                const noti = notiOrRes as ExitForcingNotification;
                this.logger.debug(
                  'Notification::roomProtocolService::ExitForcingNotification NOTI',
                  noti
                );
                this.store.dispatch(
                  RoomStore.exitForcingNotification({
                    noti
                  })
                );
              }
              break;
            case SSVC_TYPE_ROOM_FONT_UPD_NOTI:
              {
                const noti = notiOrRes as UpdateFontNotification;
                this.logger.debug(
                  'Notification::roomProtocolService::UpdateFontNotification',
                  noti
                );
                this.store.dispatch(
                  RoomStore.updateFontNotification({
                    noti
                  })
                );
              }
              break;
            default:
              break;
          }
        })
      )
      .subscribe();
    this.statusProtocolService.notification$
      .pipe(
        tap(notiOrRes => {
          switch (notiOrRes.SSVC_TYPE) {
            case SSVC_TYPE_STATUS_NOTI:
              {
                const noti = notiOrRes as StatusNotification;
                this.logger.debug(
                  'Notification::statusProtocolService::StatusNotification',
                  noti
                );
                this.store.dispatch(
                  StatusStore.statusNotification({
                    noti
                  })
                );
              }
              break;
            default:
              break;
          }
        })
      )
      .subscribe();
    this.umgProtocolService.notification$
      .pipe(
        tap(notiOrRes => {
          switch (notiOrRes.SSVC_TYPE) {
            case SSVC_TYPE_UMG_NOTI:
              {
                const noti = notiOrRes as UmgNotiNotification;
                this.logger.debug(
                  'Notification::umgProtocolService::UmgNotiNotification',
                  noti
                );
                console.log(noti);
                // notification..
                const appUserInfo = this.localStorageService.encGet<
                  AppUserInfo
                >(KEY_APP_USER_INFO, environment.customConfig.appKey);

                if (appUserInfo.settings.notification.use) {
                  const notiReq: NotificationRequest = {
                    type: NotificationType.Message,
                    seq: noti.keyId,
                    title: '쪽지가 도착했습니다.',
                    contents: noti.text,
                    image: noti.senderInfo.profileImageFile,
                    useSound:
                      'SOUND' === appUserInfo.settings.notification.method ||
                      'SOUND_ALERT' === appUserInfo.settings.notification.method
                        ? true
                        : false,
                    displayTime:
                      appUserInfo.settings.notification.alertExposureTime
                  };
                  this.nativeService.notify(notiReq);
                }
              }
              break;
            default:
              break;
          }
        })
      )
      .subscribe();
  }
}