import {
  AfterViewInit,
  Component,
  ElementRef,
  HostBinding,
  HostListener,
  OnChanges,
  OnInit,
  SimpleChanges,
  ViewChild,
} from '@angular/core';
import { MatMenuTrigger } from '@angular/material/menu';
import { Subject } from 'rxjs';
import { EnvironmentService } from 'src/environments/environment.service';
import { AccountAvatarRecord } from '../../server-services/query-records/account-records';
import { DialogService } from '../../services/dialog.service';
import { marker } from '@biesbjerg/ngx-translate-extract-marker';
import { ServerRestApiService } from '../../services/server-rest-api.service';
import {
  createContactQuery,
  deleteContactQuery,
  getContactListIdsQuery,
} from '../../server-services/querys';
import { AccountService } from '../../server-services/account.service';
import { SubscriptionService } from '../../server-services/subscription.service';
import { RouterHandler } from '../../services/router-handler.service';
import { Router } from '@angular/router';
import { DialogueService } from '../../server-services/dialogue.service';
import { AuthService } from '../../server-services/auth.service';
import { environment } from 'src/environments/environment';
import { ClipboardService } from '../../services/clipboard.service';
import { SnackBarService } from '../../services/snackbar.service';
import { AppStorage } from '../../app-storage';
import { AdvancedSettingsEnum } from 'src/app/components/advanced-settings/advanced-settings.component';
import { MatDialog } from '@angular/material/dialog';
import { VerifySignatureDialogComponent } from '../../dialogs/verify-signature-dialog/verify-signature-dialog.component';
import { AbstractAccountKeyring } from '../../crypto/keyring/account_base';

export let showUserInfoObserver = new Subject<{
  avatarInfo: AccountAvatarRecord;
  originElementRef: ElementRef;
}>();

@Component({
  selector: 'app-user-info-menu',
  templateUrl: './user-info-menu.component.html',
  styleUrls: ['./user-info-menu.component.scss'],
})
export class UserInfoMenuComponent implements AfterViewInit, OnInit {
  public avatar: AccountAvatarRecord;
  public me: AccountAvatarRecord;
  private contactList: string[];
  public avatarInContacts: boolean = false;
  public avatarRoomUrl: string;
  public inCurrentRoom: boolean = false;
  public isAnonymous: boolean = false;

  private originElementRef: ElementRef;
  @HostBinding('style.top') public top: string = '0px';
  @HostBinding('style.left') public left: string = '0px';
  @ViewChild(MatMenuTrigger) menuTrigger: MatMenuTrigger;

  private marginRight: number = 10;
  private menuAnimationInMillis: number = 0.25 * 1000;
  private menuFullyOpen: boolean = false;

  public isIdentitySettingsOn: boolean =
    AppStorage.getItem(AdvancedSettingsEnum.EXP_IDENTITY_SIGNATURE) == '1';

  constructor(
    private thisElementRef: ElementRef,
    private environmentService: EnvironmentService,
    private dialogService: DialogService,
    private dialogueService: DialogueService,
    private serverRestApiService: ServerRestApiService,
    private accountService: AccountService,
    private authService: AuthService,
    private subscriptionService: SubscriptionService,
    private router: Router,
    private routerHandler: RouterHandler,
    private clipboardService: ClipboardService,
    private snackbarService: SnackBarService,
    public dialog: MatDialog
  ) {}
  async ngOnInit(): Promise<void> {
    this.subscriptionService.subscribeWorkspaceLoaded(async () => {
      this.isAnonymous = this.authService.isAnonym();

      if (!this.isAnonymous) {
        [this.me, this.contactList] = await Promise.all([
          this.accountService.getMe(),
          this.serverRestApiService.query({ query: getContactListIdsQuery }),
        ]);
      } else {
        this.me = null;
        this.contactList = [];
      }
    });
  }

  ngAfterViewInit(): void {
    showUserInfoObserver.subscribe((clickData) => {
      if (this.menuFullyOpen && this.originElementRef == clickData.originElementRef) return;

      this.originElementRef = clickData.originElementRef;

      if (this.menuTrigger.menuOpen) {
        this.closeThenOpenMenu(clickData.avatarInfo);
      } else this.openMenu(clickData.avatarInfo);
    });
  }

  public copyContactId() {
    this.clipboardService
      .copy(this.avatar.id)
      .then(() => {
        this.snackbarService.showSnackbar(marker('Contact ID copied!'));
      })
      .catch((err) => {
        console.error('clipboard err', err);
        this.dialogService.openAlertDialog(
          marker('Copy Error'),
          marker('Could not copy to the clipboard')
        );
      });
  }

  copyContactUrl() {
    this.clipboardService
      .copy(environment.site_base + '/#contact' + RouterHandler.FRAGMENT_EQUAL + this.avatar.id)
      .then(() => {
        this.snackbarService.showSnackbar(marker('Contact URL copied!'));
      })
      .catch((err) => {
        console.error('clipboard err', err);
        this.dialogService.openAlertDialog(
          marker('Copy Error'),
          marker('Could not copy to the clipboard')
        );
      });
  }

  public addContact() {
    this.serverRestApiService
      .mutate({
        query: createContactQuery,
        variables: {
          peerId: this.avatar.id,
        },
      })
      .then((res) => {
        this.snackbarService.showSnackbar(marker('User added to your contact list.'));
      })
      .catch(() => {
        this.dialogService.openAlertDialog(
          marker('Error'),
          marker('Error happened during the operation.')
        );
      });
  }

  public goToDialog() {
    this.dialogueService
      .getData(this.avatar.id)
      .then((dialogueData) => {
        // there is already a dialogue for this user
        this.routerHandler.navigate(['room', this.avatar.id, 'chat', 'private']);
      })
      .catch((err) => {
        this.dialogService.openAlertDialog(
          marker('Error'),
          marker('Error happened during the operation')
        );
      });
  }

  public removeContact() {
    this.dialogService
      .openConfirmDialog(
        marker('Remove User'),
        marker('Are you sure you want to remove this user from your contact list?')
      )
      .subscribe((confirm) => {
        if (confirm) {
          this.serverRestApiService
            .mutate({
              query: deleteContactQuery,
              variables: {
                peerId: this.avatar.id,
              },
            })
            .then((res) => {
              this.snackbarService.showSnackbar(marker('User removed from your contact list.'));
            })
            .catch(() => {
              this.dialogService.openAlertDialog(
                marker('Error'),
                marker('Error happened during the operation.')
              );
            });
        }
      });
  }

  @HostListener('document:click', ['$event'])
  private clickedOutside(event: MouseEvent) {
    if (this.menuFullyOpen && !this.thisElementRef.nativeElement.contains(event.target)) {
      this.menuTrigger.closeMenu();
      setTimeout(() => {
        this.menuFullyOpen = false;
      }, this.menuAnimationInMillis);
    }
  }

  private closeThenOpenMenu(avatar: AccountAvatarRecord): void {
    this.menuTrigger.closeMenu();

    setTimeout(() => {
      this.openMenu(avatar);
    }, this.menuAnimationInMillis);
  }

  private openMenu(avatar: AccountAvatarRecord): void {
    this.avatar = avatar;

    this.isIdentitySettingsOn =
      AppStorage.getItem(AdvancedSettingsEnum.EXP_IDENTITY_SIGNATURE) == '1';

    const { x, y } = this.originElementRef.nativeElement.getBoundingClientRect();
    const width = this.originElementRef.nativeElement.offsetWidth;
    this.left = x + this.marginRight + width + 'px';
    this.top = y + 'px';
    this.menuTrigger.openMenu();

    this.avatarRoomUrl = `/room/${avatar.id}/chat/private`;
    this.avatarInContacts = this.contactList.some((contactId) => contactId == this.avatar.id);
    this.inCurrentRoom = this.avatarRoomUrl == this.router.url;

    setTimeout(() => {
      this.menuFullyOpen = true;
    }, this.menuAnimationInMillis);
  }

  public verifyIdentity() {
    this.dialog.open(VerifySignatureDialogComponent, {
      data: this.avatar,
    });
  }
}
