import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  OnInit,
  ViewChild,
} from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import {
  BlockSyncService,
  LocationService,
  LoggingService,
  TokenService,
  TransactionService,
  UserService,
} from '@app/_services';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { first } from 'rxjs/operators';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { copyToClipboard, CustomErrorStateMatcher, exportCsv } from '@app/_helpers';
import { MatSnackBar } from '@angular/material/snack-bar';
import { add0x, strip0x } from '@src/assets/js/ethtx/dist/hex';
import { environment } from '@src/environments/environment';
import { AccountDetails, AreaName, AreaType, Category, Transaction } from '@app/_models';

@Component({
  selector: 'app-account-details',
  templateUrl: './account-details.component.html',
  styleUrls: ['./account-details.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AccountDetailsComponent implements OnInit {
  transactionsDataSource: MatTableDataSource<any>;
  transactionsDisplayedColumns: Array<string> = ['sender', 'recipient', 'value', 'created', 'type'];
  transactionsDefaultPageSize: number = 10;
  transactionsPageSizeOptions: Array<number> = [10, 20, 50, 100];
  @ViewChild('TransactionTablePaginator', { static: true }) transactionTablePaginator: MatPaginator;
  @ViewChild('TransactionTableSort', { static: true }) transactionTableSort: MatSort;

  userDataSource: MatTableDataSource<any>;
  userDisplayedColumns: Array<string> = ['name', 'phone', 'created', 'balance', 'location'];
  usersDefaultPageSize: number = 10;
  usersPageSizeOptions: Array<number> = [10, 20, 50, 100];
  @ViewChild('UserTablePaginator', { static: true }) userTablePaginator: MatPaginator;
  @ViewChild('UserTableSort', { static: true }) userTableSort: MatSort;

  accountInfoForm: FormGroup;
  account: AccountDetails;
  accountAddress: string;
  accountStatus: any;
  accounts: Array<AccountDetails> = [];
  accountsType: string = 'all';
  categories: Array<Category>;
  areaNames: Array<AreaName>;
  areaTypes: Array<AreaType>;
  transaction: any;
  transactions: Array<Transaction>;
  transactionsType: string = 'all';
  accountTypes: Array<string>;
  transactionsTypes: Array<string>;
  genders: Array<string>;
  matcher: CustomErrorStateMatcher = new CustomErrorStateMatcher();
  submitted: boolean = false;
  bloxbergLink: string;

  constructor(
    private formBuilder: FormBuilder,
    private locationService: LocationService,
    private transactionService: TransactionService,
    private userService: UserService,
    private route: ActivatedRoute,
    private router: Router,
    private tokenService: TokenService,
    private loggingService: LoggingService,
    private blockSyncService: BlockSyncService,
    private cdr: ChangeDetectorRef,
    private snackBar: MatSnackBar
  ) {
    this.accountInfoForm = this.formBuilder.group({
      name: ['', Validators.required],
      phoneNumber: ['', Validators.required],
      age: ['', Validators.required],
      type: ['', Validators.required],
      bio: ['', Validators.required],
      gender: ['', Validators.required],
      businessCategory: ['', Validators.required],
      userLocation: ['', Validators.required],
      location: ['', Validators.required],
      locationType: ['', Validators.required],
    });
    this.route.paramMap.subscribe(async (params: Params) => {
      this.accountAddress = add0x(params.get('id'));
      this.bloxbergLink =
        'https://blockexplorer.bloxberg.org/address/' + this.accountAddress + '/transactions';
      (await this.userService.getAccountByAddress(this.accountAddress, 100)).subscribe(
        async (res) => {
          if (res !== undefined) {
            this.account = res;
            this.cdr.detectChanges();
            this.loggingService.sendInfoLevelMessage(this.account);
            // this.userService.getAccountStatus(this.account.vcard?.tel[0].value).pipe(first())
            //   .subscribe(response => this.accountStatus = response);
            this.accountInfoForm.patchValue({
              name: this.account.vcard?.fn[0].value,
              phoneNumber: this.account.vcard?.tel[0].value,
              age: this.account.age,
              type: this.account.type,
              bio: this.account.products,
              gender: this.account.gender,
              businessCategory: this.account.category,
              userLocation: this.account.location.area_name,
              location: this.account.location.area,
              locationType: this.account.location.area_type,
            });
          } else {
            alert('Account not found!');
          }
        }
      );
      this.blockSyncService.blockSync(this.accountAddress);
    });
    this.userService
      .getCategories()
      .pipe(first())
      .subscribe((res) => (this.categories = res));
    this.locationService
      .getAreaNames()
      .pipe(first())
      .subscribe((res) => (this.areaNames = res));
    this.locationService
      .getAreaTypes()
      .pipe(first())
      .subscribe((res) => (this.areaTypes = res));
    this.userService
      .getAccountTypes()
      .pipe(first())
      .subscribe((res) => (this.accountTypes = res));
    this.userService
      .getTransactionTypes()
      .pipe(first())
      .subscribe((res) => (this.transactionsTypes = res));
    this.userService
      .getGenders()
      .pipe(first())
      .subscribe((res) => (this.genders = res));
  }

  ngOnInit(): void {
    this.userService.accountsSubject.subscribe((accounts) => {
      this.userDataSource = new MatTableDataSource<any>(accounts);
      this.userDataSource.paginator = this.userTablePaginator;
      this.userDataSource.sort = this.userTableSort;
      this.accounts = accounts;
    });

    this.transactionService.transactionsSubject.subscribe((transactions) => {
      this.transactionsDataSource = new MatTableDataSource<any>(transactions);
      this.transactionsDataSource.paginator = this.transactionTablePaginator;
      this.transactionsDataSource.sort = this.transactionTableSort;
      this.transactions = transactions;
    });
  }

  doTransactionFilter(value: string): void {
    this.transactionsDataSource.filter = value.trim().toLocaleLowerCase();
  }

  doUserFilter(value: string): void {
    this.userDataSource.filter = value.trim().toLocaleLowerCase();
  }

  viewTransaction(transaction): void {
    this.transaction = transaction;
  }

  viewAccount(account): void {
    this.router.navigateByUrl(
      `/accounts/${strip0x(account.identities.evm[`bloxberg:${environment.bloxbergChainId}`][0])}`
    );
  }

  get accountInfoFormStub(): any {
    return this.accountInfoForm.controls;
  }

  async saveInfo(): Promise<void> {
    this.submitted = true;
    if (this.accountInfoForm.invalid || !confirm(`Change user's profile information?`)) {
      return;
    }
    const accountKey = await this.userService.changeAccountInfo(
      this.accountAddress,
      this.accountInfoFormStub.name.value,
      this.accountInfoFormStub.phoneNumber.value,
      this.accountInfoFormStub.age.value,
      this.accountInfoFormStub.type.value,
      this.accountInfoFormStub.bio.value,
      this.accountInfoFormStub.gender.value,
      this.accountInfoFormStub.businessCategory.value,
      this.accountInfoFormStub.userLocation.value,
      this.accountInfoFormStub.location.value,
      this.accountInfoFormStub.locationType.value
    );
    this.submitted = false;
  }

  filterAccounts(): void {
    if (this.accountsType === 'all') {
      this.userService.accountsSubject.subscribe((accounts) => {
        this.userDataSource.data = accounts;
        this.accounts = accounts;
      });
    } else {
      this.userDataSource.data = this.accounts.filter(
        (account) => account.type === this.accountsType
      );
    }
  }

  filterTransactions(): void {
    if (this.transactionsType === 'all') {
      this.transactionService.transactionsSubject.subscribe((transactions) => {
        this.transactionsDataSource.data = transactions;
        this.transactions = transactions;
      });
    } else {
      this.transactionsDataSource.data = this.transactions.filter(
        (transaction) => transaction.type === this.transactionsType
      );
    }
  }

  resetPin(): void {
    if (!confirm(`Reset user's pin?`)) {
      return;
    }
    this.userService
      .resetPin(this.account.vcard.tel[0].value)
      .pipe(first())
      .subscribe((res) => {
        this.loggingService.sendInfoLevelMessage(`Response: ${res}`);
      });
  }

  downloadCsv(data: any, filename: string): void {
    exportCsv(data, filename);
  }

  copyAddress(): void {
    if (copyToClipboard(this.accountAddress)) {
      this.snackBar.open(this.accountAddress + ' copied successfully!', 'Close', {
        duration: 3000,
      });
    }
  }
}
