import {
  ChangeDetectorRef,
  Component,
  ElementRef,
  HostListener,
  OnDestroy,
  OnInit,
  ViewChild,
} from "@angular/core";
import { TranslateService } from "@ngx-translate/core";
import { Observable, Subject } from "rxjs";

import { MatDialog } from "@angular/material/dialog";
import { AuthService } from "./shared/server-services/auth.service";
import { RouterHandler } from "./shared/services/router-handler.service";
import { ServerRestApiService } from "./shared/services/server-rest-api.service";
import { SubscriptionService } from "./shared/server-services/subscription.service";
import {
  sideMenuActiveObserver,
  styleChangedObserver,
} from "./components/header/header.component";
import { AccountService } from "./shared/server-services/account.service";
import { MeRecord } from "./shared/server-services/query-records/account-records";
import { ChangeUsernameDialogComponent } from "./components/account-settings/change-username-dialog/change-username-dialog.component";
import { SearchService } from "./shared/server-services/search-service";
import { getTimedOffersQuery } from "./shared/server-services/querys";
import { marker } from "@biesbjerg/ngx-translate-extract-marker";
import { TimedOfferRecord } from "./shared/server-services/query-records/timed-offer-records";
import {
  SubscriptionServiceEvent,
  SubscriptionServiceEventType,
} from "./shared/server-services/subscription-event";
import { environment } from "./../environments/environment";
import { showWorkerGraph } from "./components/advanced-settings/advanced-settings.component";
import { DownloadManagerService } from "./shared/services/download-manager-service";
import { DeviceDetectorService } from "ngx-device-detector";
import { DialogService } from "./shared/services/dialog.service";

import {
  WorkspaceSubscriptionDialogueMessageEventRecord,
  WorkspaceSubscriptionRoomMessageEventRecord,
} from "./shared/server-services/query-records/workspace-records";
import { CordovaService } from "src/app/shared/services/cordova.service";
import { RoomData, RoomService } from "./shared/server-services/room.service";
import { getTimeFromId } from "./shared/crypto/context/timestamp";
import { generateAvatar } from "./shared/avatar-generator";
@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.scss"],
})
export class AppComponent implements OnInit, OnDestroy {
  public styleMode: string = "dark";
  public showSidebar = false;
  public mobileShowSidebar = false;
  public initConnection = false;
  public newOffers = false;
  public hideOffers = false;
  public isCookieAccepted: boolean = false;
  public legalURL = environment.url_landing + "/legal";
  public dragging = false;
  public sideWidth: number = 280;
  public windowWidth: number;
  public isOnMobile: boolean;

  // development feature for debug
  public workerGraph: boolean = false;

  private hideSidebarHere = ["simplepay-back"];

  public onRouterChange = (res) => {
    if (this.initConnection) {
      this.handleAutoNavigation();
      this.showSidebar =
        !this.authService.isAnonym() &&
        !this.hideSidebarHere.some((hideHere) => res.url.startsWith(hideHere));
    }
  };

  private onWorkspaceLoaded() {
    if (this.routerHandler.isOnPage("search")) {
      let routeParam = this.routerHandler.getRoute();
      let search = routeParam.fragment?.search;
      let resourceId = routeParam.params.resourceId; // it can be "all"
      this.searchService.search(resourceId, search, "en"); // TODO lang
    }

    this.checkAvatar();

    this.serverRestApiService
      .query({
        query: getTimedOffersQuery,
      })
      .then((offers: TimedOfferRecord[]) => {
        if (offers && offers.length > 0) {
          this.newOffers = true;
        }
      });
  }

  private onOfferEvent() {
    this.newOffers = true;
  }

  @HostListener("window:beforeunload")
  canDeactivate(): boolean {
    return !(
      this.downloadManagerService.isDownloadInProgress() ||
      this.downloadManagerService.isUploadInProgress()
    );
  }

  constructor(
    private translate: TranslateService,
    private dialog: MatDialog,
    private authService: AuthService,
    private accountService: AccountService,
    private routerHandler: RouterHandler,
    private serverRestApiService: ServerRestApiService,
    private subscriptionService: SubscriptionService,
    private searchService: SearchService,
    private cdRef: ChangeDetectorRef,
    private downloadManagerService: DownloadManagerService,
    private dialogService: DialogService,
    private deviceDetector: DeviceDetectorService,
    private roomService: RoomService,
    private cordovaService: CordovaService
  ) {

    this.isOnMobile = this.cordovaService.isOnApp();

    this.isCookieAccepted =
      localStorage.getItem("accept-cookies-v2") !== null;

    // load user from localstorage or generate anonym user
    this.subscriptionService.subscribeWorkspaceLoaded(
      this.onWorkspaceLoaded.bind(this)
    );

    this.subscriptionService.subscribe(
      SubscriptionServiceEvent.ACCOUNT_OFFER_EVENT,
      SubscriptionServiceEventType.CREATE,
      this.onOfferEvent.bind(this)
    );

    this.authService.onLogin(() => {
      this.stateInit();
    });

    this.authService.onLogout(() => {
      this.stateInit();
    });

    this.serverRestApiService.subscribeOnAuthCloseSubscribe(() => {
      this.routerHandler.navigate(["/login"]);
    });

    // default css mode light/dark/etc
    this.styleMode = localStorage.getItem("style_mode");
    if (this.styleMode === null) {
      this.styleMode = "dark";
      localStorage.setItem("style_mode", this.styleMode);

      styleChangedObserver.next("dark");
    }

    styleChangedObserver.subscribe((style) => {
      document.body.classList.remove("theme-" + this.styleMode);
      this.styleMode = style;
      localStorage.setItem("style_mode", this.styleMode);
      document.body.classList.add("theme-" + this.styleMode);
    });

    // default languages
    let lang = localStorage.getItem("lang");
    if (lang === null) {
      lang = navigator.language.split("-")[0];
      localStorage.setItem("lang", lang);
    }

    // this language will be used as a fallback when a translation isn't found in the current language
    this.translate.setDefaultLang("en");

    // the lang to use, if the lang isn't available, it will use the current loader to get them
    this.translate.use(lang);

    sideMenuActiveObserver.subscribe((shouldOpen: boolean | null) => {
      if (this.showSidebar) {
        if (shouldOpen != null) this.mobileShowSidebar = shouldOpen;
        else this.mobileShowSidebar = !this.mobileShowSidebar;

        this.cdRef.detectChanges();
      }
    });

    // do not allow to load outcome source into the view and reload the page
    window.addEventListener(
      "drop",
      function (e) {
        e.preventDefault();
      },
      false
    );
    window.addEventListener(
      "dragover",
      function (e) {
        e.preventDefault();
      },
      false
    );

    showWorkerGraph.subscribe((show) => {
      this.workerGraph = show;
      console.log("show graph", show);
    });

    if (this.deviceDetector.browser == "Safari") {
      if (!localStorage.getItem("safari-notice-read")) {
        localStorage.setItem("safari-notice-read", "1");
        this.dialogService.openAlertDialog(
          marker("Safari experimental support"),
          marker(
            "Safari support is currently in experimental phase. If you experience any issues we recommend using Chrome or a chromium-based browser for the time being."
          )
        );
      }
    } else if (
      this.deviceDetector.browser != "Chrome" &&
      this.deviceDetector.browser != "Opera" &&
      this.deviceDetector.browser != "MS-Edge" &&
      this.deviceDetector.browser != "MS-Edge-Chromium"
    ) {
      if (!localStorage.getItem("chrome-notice-read")) {
        localStorage.setItem("chrome-notice-read", "1");
        this.dialogService.openAlertDialog(
          marker("Browser support notice"),
          marker(
            "Because of the technologies used in our webapp, we highly recommend using Chrome or a chromium based web browser."
          )
        );
      }
    }

    this.setSidebarWidthFromStorage();
  }

  public acceptCookies() {
    this.isCookieAccepted = true;
    localStorage.setItem("accept-cookies-v2", "1");
  }

  private stateInit() {
    this.initConnection = true;
    let route = this.routerHandler.getRoute();
    if (route) {
      var url = this.routerHandler.getRoute().url;
      this.showSidebar =
        !this.authService.isAnonym() &&
        !this.hideSidebarHere.some((hideHere) => url.startsWith(hideHere));
    }
  }

  private handleAutoNavigation() {
    this.stateInit();
  }

  /*
   * Check if avatarname is filled out. If not, prompt user to enter name.
   */
  checkAvatar() {
    this.accountService.getMe().then((me: MeRecord) => {
      if (!me.avatarImageKey) {
        generateAvatar(me.id + Math.random()).then((avatarBlob) => {
          avatarBlob.arrayBuffer().then((buffer) => {
            this.accountService
              .setAvatar(buffer)
              .then((res) => {
                me.avatarImageKey = res;
              })
              .catch((err) => console.error("set avatar", err));
          });
        });
      }
      if (me.avatarName) {
        this.handleAutoNavigation();
      } else {
        var ref = this.dialog.open(ChangeUsernameDialogComponent, {
          data: { firstSetup: true },
          disableClose: true,
        });

        ref.afterClosed().subscribe((userName) => {
          this.accountService
            .changeAvatarName(userName)
            .then((res) => {
              me.avatarName = userName;
              this.handleAutoNavigation();
            })
            .catch((err) => console.error(err));
        });
      }
    });
  }

  ngOnInit() {
    this.routerHandler.subscribeAll(this.onRouterChange);
    document.body.classList.add("theme-" + this.styleMode);
    this.windowWidth = window.innerWidth;
  }

  @HostListener('window:resize', ['$event']) windowResize(e): void{
    this.windowWidth = e.target.innerWidth;
  }

  get isMobileResponsiveView(): boolean{
    if(this.deviceDetector.isMobile()) return true;

    return this.windowWidth < 761;
  }

  ngOnDestroy() {
    this.routerHandler.unsubscribeAll(this.onRouterChange);

    this.subscriptionService.unsubscribe(
      SubscriptionServiceEvent.ACCOUNT_OFFER_EVENT,
      SubscriptionServiceEventType.CREATE,
      this.onOfferEvent.bind(this)
    );
  }

  private setSidebarWidthFromStorage(): void{
    var storedWidth = localStorage.getItem("sideBarWidth");
    if(storedWidth)
      this.sideWidth = parseInt(storedWidth);
  }

  public closeOffers(event) {
    this.hideOffers = true;
    event.stopPropagation();
  }

  public draggerPointerDown(){
    this.dragging = true;
  }
  @HostListener('document:pointerup', ['$event']) pointerUp(e: MouseEvent){
    if(this.dragging){
      this.dragging = false;
      localStorage.setItem("sideBarWidth", e.clientX.toString());
    }
  }
  @HostListener('document:mousemove', ['$event']) 
  onMouseMove(e:MouseEvent) {
    if(this.dragging){
      this.sideWidth = e.clientX;
    }
  }
}
