import { Location } from '@angular/common';
import {
  ChangeDetectorRef,
  Component,
  ElementRef,
  HostListener,
  OnDestroy,
  OnInit,
  ViewChild,
} from '@angular/core';
import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { MatDialog } from '@angular/material/dialog';
import { NavigationStart, Router } from '@angular/router';
import { marker } from '@biesbjerg/ngx-translate-extract-marker';
import { Subscription } from 'rxjs';
import { AppStorage } from 'src/app/shared/app-storage';
import { InviteUserDialogComponent } from 'src/app/shared/dialogs/invite-user-dialog/invite-user-dialog.component';
import { AccountService } from 'src/app/shared/server-services/account.service';
import { AuthService } from 'src/app/shared/server-services/auth.service';
import { DialogueService } from 'src/app/shared/server-services/dialogue.service';
import {
  AccountAvatarRecord,
  MeRecord,
  UserRole,
} from 'src/app/shared/server-services/query-records/account-records';
import { TimedOfferRecord } from 'src/app/shared/server-services/query-records/timed-offer-records';
import { getTimedOffersQuery } from 'src/app/shared/server-services/querys';
import { RoomService } from 'src/app/shared/server-services/room.service';
import { SidebarService } from 'src/app/shared/server-services/sidebar.service';
import {
  SubscriptionServiceEvent,
  SubscriptionServiceEventType,
} from 'src/app/shared/server-services/subscription-event';
import { SubscriptionService } from 'src/app/shared/server-services/subscription.service';
import { recalculateNews } from 'src/app/shared/services/cache/cache-logic/response-merger/subscription-merger/sub-merger/news-handler/news-handler';
import { CacheService } from 'src/app/shared/services/cache/cache.service';
import { ClipboardService } from 'src/app/shared/services/clipboard.service';
import { CordovaService } from 'src/app/shared/services/cordova.service';
import { DialogService } from 'src/app/shared/services/dialog.service';
import {
  CollectionManagerType,
  downloadCollectionStartedObserver,
  DownloadManagerService,
  downloadStartedObserver,
  FileManagerType,
  uploadStartedObserver,
} from 'src/app/shared/services/download-manager-service';
import {
  NanoActionQueueService,
  NanoActionType,
} from 'src/app/shared/services/nano-action-queue.service';
import {
  ServerRestApiService,
  WebSocketStatus,
} from 'src/app/shared/services/server-rest-api.service';
import { SnackBarService } from 'src/app/shared/services/snackbar.service';
import { SwipeService } from 'src/app/shared/services/swipe.service';
import { EnvironmentService } from 'src/environments/environment.service';
import { RouterHandler } from '../../shared/services/router-handler.service';
import {
  showWorkspaceTabObserver,
  sideMenuActiveObserver,
  styleChangedObserver,
} from '../../shared/shared-observers';
import { DownloadManagerComponent } from '../download-manager/download-manager.component';

@Component({
  selector: 'app-header',
  templateUrl: './header.component.html',
  styleUrls: ['./header.component.scss'],
})
export class HeaderComponent implements OnInit, OnDestroy {
  public name = 'guest';
  public colorTheme;
  public downloadProgress: {
    fileList: FileManagerType[];
    collectionList: CollectionManagerType[];
  } = { fileList: [], collectionList: [] };
  public actionList: NanoActionType[] = [];
  public onboardingPage: boolean = false;
  public accountMenuOpen: boolean = false;
  public playDownloadAnimation: boolean = false;
  protected downloadAnimationTimeout: NodeJS.Timeout;
  public me: MeRecord;
  public isDistributor: boolean = false;
  public isAdmin: boolean = false;
  public webDocLink: string = marker('https://www.clarabot.info/nano/en/');
  public googlePlayStoreLink: string = marker('googlePlayStoreLink');
  public iosAppStoreLink: string = marker('iosAppStoreLink');
  public news: number = 0;
  public offersAvailable: boolean = false;
  public isAnonym: boolean = true;
  public isOnLoginPage: boolean = false;
  public wsConnectionStatus: WebSocketStatus;
  public WebSocketStatus = WebSocketStatus;

  protected onWsConnectionChangeSubsciption: Subscription;

  @ViewChild('menuToolbar', { read: ElementRef }) menuToolbar: ElementRef;
  @ViewChild('accountInfo', { read: ElementRef }) accountInfo: ElementRef;
  @ViewChild('minimalMenu', { read: ElementRef }) minimalMenu: ElementRef;

  constructor(
    protected authService: AuthService,
    protected accountService: AccountService,
    protected router: Router,
    protected downloadManagerService: DownloadManagerService,
    protected nanoActionQueueService: NanoActionQueueService,
    protected dialogService: DialogService,
    protected dialog: MatDialog,
    public environmentService: EnvironmentService,
    protected subscriptionService: SubscriptionService,
    protected serverRestApi: ServerRestApiService,
    protected routerHandler: RouterHandler,
    protected snackbarService: SnackBarService,
    protected cacheService: CacheService,
    protected sidebarService: SidebarService,
    protected cordovaService: CordovaService,
    protected bottomSheet: MatBottomSheet,
    protected location: Location,
    protected dialogueService: DialogueService,
    protected roomService: RoomService,
    protected cd: ChangeDetectorRef,
    protected clipboardService: ClipboardService,
    protected swipeService: SwipeService
  ) {
    this.colorTheme = AppStorage.getItem('style_mode');
    styleChangedObserver.subscribe((style) => {
      this.colorTheme = style;
    });

    this.isOnLoginPage = this.routerHandler.isOnPage('login');
    this.routerHandler.subscribeAll((res) => {
      this.isOnLoginPage = this.routerHandler.isOnPage('login');
    });

    this.onboardingPage = this.isOnBoardingPage();
    this.routerHandler.subscribeAll((res) => {
      this.onboardingPage = this.isOnBoardingPage();
    });

    /*newsObserver.subscribe((news) => {
      this.news = news;
    });*/

    router.events.subscribe((val) => {
      if (val instanceof NavigationStart) this.switchMenuOpen(false);
    });

    this.downloadProgress = {
      fileList: downloadManagerService.getFileList(),
      collectionList: downloadManagerService.getCollectionList(),
    };

    this.authService.onLogout(() => {
      this.downloadProgress = {
        fileList: downloadManagerService.getFileList(),
        collectionList: downloadManagerService.getCollectionList(),
      };
    });

    // // [
    // // ...downloadManagerService.getFileList(),
    // // ...downloadManagerService.getCollectionList(),
    // // ];
    this.actionList = nanoActionQueueService.getActionList();

    uploadStartedObserver.subscribe((file: FileManagerType) => this.downloadStartedEvent(file));
    downloadStartedObserver.subscribe((file: FileManagerType) => this.downloadStartedEvent(file));
    downloadCollectionStartedObserver.subscribe((collection: CollectionManagerType) =>
      this.downloadCollectionStartedEvent(collection)
    );

    this.subscriptionService.subscribe(
      SubscriptionServiceEvent.ACCOUNT_EVENT,
      SubscriptionServiceEventType.MODIFY,
      this.onAccountChange.bind(this)
    );

    this.subscriptionService.subscribeWorkspaceLoaded(() => {
      this.isAnonym = this.authService.isAnonym();
      if (!this.isAnonym) {
        this.serverRestApi
          .query({ query: getTimedOffersQuery })
          .then((offers: TimedOfferRecord[]) => {
            this.offersAvailable = offers && offers.length > 0;
          });
      }
    });

    this.serverRestApi.subscribeOnWSDisconnected(this.onWSDisconnect);
    this.serverRestApi.subscribeOnWSConnected(this.onWSConnect);

    this.subscriptionService.subscribe(
      SubscriptionServiceEvent.ROOM_MESSAGE_EVENT,
      SubscriptionServiceEventType.CREATE,
      this.recalculateBadge
    );

    this.subscriptionService.subscribe(
      SubscriptionServiceEvent.DIALOGUE_MESSAGE_EVENT,
      SubscriptionServiceEventType.CREATE,
      this.recalculateBadge
    );

    this.subscriptionService.subscribe(
      SubscriptionServiceEvent.ROOM_EVENT,
      SubscriptionServiceEventType.MODIFY,
      this.recalculateBadge
    );

    this.subscriptionService.subscribe(
      SubscriptionServiceEvent.DIALOGUE_EVENT,
      SubscriptionServiceEventType.ALL,
      this.recalculateBadge
    );
  }

  private isOnBoardingPage(): boolean {
    return (
      this.routerHandler.isOnPage('login') ||
      this.routerHandler.isOnPage('register') ||
      this.routerHandler.isOnPage('register-confirm') ||
      this.routerHandler.isOnPage('account-recovery') ||
      this.routerHandler.isOnPage('account-recovery-confirm') ||
      this.routerHandler.isOnPage('license-view')
    );
  }

  onWSDisconnect = () => {
    if (this.wsConnectionStatus != WebSocketStatus.DISCONNECTED) {
      this.snackbarService.showSnackbar(marker('Lost connection to server!'));
      this.wsConnectionStatus = WebSocketStatus.DISCONNECTED;
    }
  };

  onWSConnect = () => {
    if (this.wsConnectionStatus != WebSocketStatus.CONNECTED) {
      this.snackbarService.showSnackbar(marker('Regained connection to server!'));
      this.wsConnectionStatus = WebSocketStatus.CONNECTED;
    }
  };

  public onAccountChange(ev) {
    this.accountService.getMe().then((data) => {
      this.me = Object.assign({}, data);
      this.isAnonym = this.authService.isAnonym();
    });
  }

  ngOnInit(): void {
    this.subscriptionService.subscribeWorkspaceLoaded(() => {
      this.accountService.getMe().then((data: MeRecord) => {
        console.log('me', data);
        this.me = data;
        this.isDistributor = this.accountService.isCurrentUserInRole(UserRole.DISTRIBUTOR, this.me);
        this.isAdmin = this.accountService.isCurrentUserInRole(UserRole.ADMIN, this.me);
      });
    });
  }

  ngOnDestroy() {
    this.subscriptionService.unsubscribe(
      SubscriptionServiceEvent.ACCOUNT_EVENT,
      SubscriptionServiceEventType.MODIFY,
      this.onAccountChange.bind(this)
    );

    this.serverRestApi.unsubscribeOnWSDisconnected(this.onWSDisconnect);
    this.serverRestApi.unsubscribeOnWSConnected(this.onWSConnect);

    this.subscriptionService.unsubscribe(
      SubscriptionServiceEvent.ROOM_MESSAGE_EVENT,
      SubscriptionServiceEventType.CREATE,
      this.recalculateBadge
    );

    this.subscriptionService.unsubscribe(
      SubscriptionServiceEvent.DIALOGUE_MESSAGE_EVENT,
      SubscriptionServiceEventType.CREATE,
      this.recalculateBadge
    );

    this.subscriptionService.unsubscribe(
      SubscriptionServiceEvent.ROOM_EVENT,
      SubscriptionServiceEventType.MODIFY,
      this.recalculateBadge
    );

    this.subscriptionService.unsubscribe(
      SubscriptionServiceEvent.DIALOGUE_EVENT,
      SubscriptionServiceEventType.ALL,
      this.recalculateBadge
    );
  }

  downloadStartedEvent(file: FileManagerType) {
    console.log('download started file', file);
    this.playDownloadAnimation = true;

    if (this.downloadAnimationTimeout) clearTimeout(this.downloadAnimationTimeout);

    this.downloadAnimationTimeout = setTimeout(() => {
      this.playDownloadAnimation = false;
      this.downloadAnimationTimeout = null;
    }, 3 * 1000);
  }
  downloadCollectionStartedEvent(collection: CollectionManagerType) {
    console.log('download started coll', collection);
    this.playDownloadAnimation = true;

    if (this.downloadAnimationTimeout) clearTimeout(this.downloadAnimationTimeout);

    this.downloadAnimationTimeout = setTimeout(() => {
      this.playDownloadAnimation = false;
      this.downloadAnimationTimeout = null;
    }, 3 * 1000);
  }

  burgerClick(shouldOpen: boolean = null): void {
    sideMenuActiveObserver.next(shouldOpen);
    showWorkspaceTabObserver.next();
    this.recalculateBadge();
  }

  protected recalculateBadge = () => {
    recalculateNews(this.cacheService);
    this.sidebarService.getSidebarNews().then((news) => {
      this.sidebarService.getGrantedRooms().then((granted) => {
        this.news = news.news + (granted.length > 0 ? 1 : 0);
      });
    });
  };

  closeSideBar(): void {
    sideMenuActiveObserver.next(false);
  }

  showWorkSpaceTab(): void {
    showWorkspaceTabObserver.next();
  }

  switchMenuOpen(open: boolean = null) {
    this.accountMenuOpen = open != null ? open : !this.accountMenuOpen;
  }
  @HostListener('document:click', ['$event'])
  documentClick(event: MouseEvent) {
    if (
      this.menuToolbar &&
      this.accountInfo &&
      this.menuToolbar.nativeElement &&
      this.accountInfo.nativeElement &&
      !this.menuToolbar.nativeElement.contains(event.target) &&
      !this.accountInfo.nativeElement.contains(event.target) &&
      !this.minimalMenu.nativeElement.contains(event.target)
    )
      this.switchMenuOpen(false);
  }

  openInviteDialog() {
    this.accountService.getAllAccount().then((partners) => {
      const dialogRef = this.dialog.open<
        InviteUserDialogComponent,
        AccountAvatarRecord[],
        AccountAvatarRecord[]
      >(InviteUserDialogComponent, {
        data: partners,
      });

      dialogRef.afterClosed().subscribe((result) => {});
    });
  }

  public get showLoadingBar(): boolean {
    return (
      this.downloadManagerService.isDownloadInProgress() ||
      this.downloadManagerService.isUploadInProgress()
    );
  }

  public get overallProgress(): number {
    let activeFiles = this.downloadProgress.fileList.filter((file) => file.progress != 100);
    let fileProgressCount: number = 0;
    let maxFile: number = activeFiles.length * 100;
    activeFiles.map((file) => file.progress).forEach((prog) => (fileProgressCount += prog));

    let activeCollections = this.downloadProgress.collectionList.filter(
      (collection) => !collection.done
    );
    let collectionProgressCount: number = 0;
    let maxColl: number = activeCollections.length * 100;
    activeCollections
      .map((collection) => collection.progress)
      .forEach((prog) => (collectionProgressCount += prog));

    return ((fileProgressCount + collectionProgressCount) / (maxFile + maxColl)) * 100;
  }

  public showDownloadSheet(): void {
    this.bottomSheet.open(DownloadManagerComponent);
  }
}
