import { Component, OnDestroy, OnInit } from '@angular/core';
import { UntypedFormControl } from '@angular/forms';
import { MatTooltipDefaultOptions, MAT_TOOLTIP_DEFAULT_OPTIONS } from '@angular/material/tooltip';
import { marker } from '@biesbjerg/ngx-translate-extract-marker';
import { AppStorage } from 'src/app/shared/app-storage';
import { ObjectSorter } from 'src/app/shared/object-sorter';
import { SafeRadix32 } from 'src/app/shared/safe-radix32';
import { AccountService } from 'src/app/shared/server-services/account.service';
import { DialogueService } from 'src/app/shared/server-services/dialogue.service';
import { AccountAvatarRecord } from 'src/app/shared/server-services/query-records/account-records';
import { ID } from 'src/app/shared/server-services/query-records/common-records';
import {
  createContactQuery,
  deleteContactQuery,
  getAccountQuery,
  getContactListIdsQuery,
} from 'src/app/shared/server-services/querys';
import {
  SubscriptionServiceEvent,
  SubscriptionServiceEventType,
} from 'src/app/shared/server-services/subscription-event';
import { SubscriptionService } from 'src/app/shared/server-services/subscription.service';
import { DialogService } from 'src/app/shared/services/dialog.service';
import { RouterHandler } from 'src/app/shared/services/router-handler.service';
import { ServerRestApiService } from 'src/app/shared/services/server-rest-api.service';
import { SnackBarService } from 'src/app/shared/services/snackbar.service';
import { sideMenuActiveObserver } from 'src/app/shared/shared-observers';
import { WeightedSearch } from 'src/app/shared/weighted-search';

enum ViewModeEnum {
  TILE = 0,
  LIST = 1,
}

const customToolTipOptions: MatTooltipDefaultOptions = {
  showDelay: 200,
  hideDelay: 0,
  touchendHideDelay: 0,
  disableTooltipInteractivity: true,
};

@Component({
  selector: 'app-contact-list',
  templateUrl: './contact-list.component.html',
  styleUrls: ['./contact-list.component.scss'],
  providers: [{ provide: MAT_TOOLTIP_DEFAULT_OPTIONS, useValue: customToolTipOptions }],
})
export class ContactListComponent implements OnInit, OnDestroy {
  public contactList: AccountAvatarRecord[];
  public filteredContactList: AccountAvatarRecord[];
  public foundError: boolean = false;
  public foundAccount: AccountAvatarRecord = null;
  public isLoading: boolean = false;
  public me: AccountAvatarRecord;

  public searchTermControl = new UntypedFormControl('');

  public viewModeEnum = ViewModeEnum;
  public viewMode: ViewModeEnum = ViewModeEnum.TILE;

  private CONTACT_LIST_VIEW_MODE = 'contactListViewMode';

  constructor(
    private serverRestApiService: ServerRestApiService,
    private accountService: AccountService,
    private subscriptionService: SubscriptionService,
    private dialogService: DialogService,
    private dialogueService: DialogueService,
    private routerHandler: RouterHandler,
    private snackbarService: SnackBarService
  ) {
    this.accountService
      .getMe()
      .then((me) => {
        this.me = me;
      })
      .then(() => {
        this.reloadAndsortContactList();
      });

    var viewMode = AppStorage.getItem(this.CONTACT_LIST_VIEW_MODE);
    if (viewMode) this.viewMode = Number.parseInt(viewMode);

    this.subscriptionService.subscribe(
      SubscriptionServiceEvent.ACCOUNT_CONTACT_EVENT,
      SubscriptionServiceEventType.ALL,
      this.reloadAndsortContactList.bind(this)
    );
  }

  ngOnDestroy() {
    this.subscriptionService.unsubscribe(
      SubscriptionServiceEvent.ACCOUNT_CONTACT_EVENT,
      SubscriptionServiceEventType.ALL,
      this.reloadAndsortContactList.bind(this)
    );
  }

  private reloadAndsortContactList() {
    return this.serverRestApiService
      .query({
        query: getContactListIdsQuery,
      })
      .then((contactIds: ID[]) => {
        this.accountService.getAccounts(contactIds).then((accounts) => {
          this.contactList = ObjectSorter.sort(Object.values(accounts), 'avatarName');
          this.filter();
        });
      });
  }

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

  public searchUser() {
    this.foundError = false;
    this.isLoading = true;
    this.foundAccount = null;

    this.searchTermControl.setErrors(null);

    if (!SafeRadix32.isSafeRadix(this.searchTermControl.value)) {
      this.filter();
      return;
    }

    var userId = this.searchTermControl.value;

    this.serverRestApiService
      .query({
        query: getAccountQuery,
        variables: {
          id: userId,
        },
      })
      .then((acc) => {
        if (acc) {
          this.foundAccount = acc;
        } else {
          this.foundError = true;
        }
      })
      .catch((err) => {
        this.foundError = true;
      })
      .finally(() => {
        this.isLoading = false;

        if (this.foundError) this.searchTermControl.setErrors({ foundError: true });
        if (this.foundAccount) {
          if (this.foundAccount == this.me) this.searchTermControl.setErrors({ meError: true });
          else if (this.contactList?.includes(this.foundAccount))
            this.searchTermControl.setErrors({ existsError: true });
        }
      });
  }

  public deleteContact(acc: AccountAvatarRecord) {
    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: acc.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.')
              );
            });
        }
      });
  }

  public createContact(acc: AccountAvatarRecord) {
    if (acc) {
      this.serverRestApiService
        .mutate({
          query: createContactQuery,
          variables: {
            peerId: acc.id,
          },
        })
        .then((res) => {
          this.foundAccount = null;
          this.snackbarService.showSnackbar(marker('User added to your contact list.'));
        })
        .catch((err) => {
          if (err.message === 'Contacts limit is reached (10000)') {
            this.dialogService.openAlertDialog(
              marker('Contact limit'),
              marker('Contacts limit is reached.')
            );
          } else {
            this.dialogService.openAlertDialog(
              marker('Error'),
              marker('Error happened during the operation.')
            );
          }
        });
    }
  }

  public switchViewMode(viewMode: ViewModeEnum): void {
    this.viewMode = viewMode;
    AppStorage.setItem(this.CONTACT_LIST_VIEW_MODE, viewMode.toString());
  }

  public get canAdd(): boolean {
    return !(
      this.isLoading ||
      this.foundError ||
      !this.foundAccount ||
      this.me === this.foundAccount ||
      this.foundAccount.deleted ||
      this.contactList.includes(this.foundAccount)
    );
  }

  private filter() {
    this.filteredContactList = WeightedSearch.search<AccountAvatarRecord>(
      this.searchTermControl.value,
      ['avatarName', 'id'],
      this.contactList
    );
    this.filteredContactList.sort((a, b) =>
      a.avatarName > b.avatarName ? 1 : a.avatarName < b.avatarName ? -1 : 0
    );
  }

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