import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { UntypedFormBuilder, Validators } from '@angular/forms';
import { marker } from '@biesbjerg/ngx-translate-extract-marker';
import { base64 } from 'rfc4648';
import { AppStorage } from 'src/app/shared/app-storage';
import { USE_PASSWORD_NORMALIZATION } from 'src/app/shared/consts/upgrade';
import { create_account_recovery_confirm_request } from 'src/app/shared/crypto/auth/recovery';
import { PrivateKeyringV1 } from 'src/app/shared/crypto/keyring/private';
import { searchRecoveryKeyFromFile } from 'src/app/shared/file-reader';
import { NanoValidators } from 'src/app/shared/nano-validators';
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 { styleChangedObserver } from 'src/app/shared/shared-observers';

@Component({
  selector: 'app-account-recovery-confirm',
  templateUrl: './account-recovery-confirm.component.html',
  styleUrls: ['./account-recovery-confirm.component.scss'],
})
export class AccountRecoveryConfirmComponent implements OnInit {
  public isOperationSuccess: boolean = false;
  public masterKey: Uint8Array;
  public currStep = 1;
  public stepRecovery = 1;
  public stepPassword = 2;
  public isPending: boolean = false;
  public passwordScore: number;
  public urlToken: string;
  public accountId: string;
  public signingSecretEc: Uint8Array;
  public isDarkTheme: boolean = true;

  public recoveryKeyGroup = this.fb.group({
    recoveryKey: ['', [Validators.required]],
  });

  public passwordGroup = this.fb.group({
    password: ['', [Validators.required]],
    password2: ['', [Validators.required]],
  });

  @ViewChild('recoveryKeyInput') recoveryKeyInput: ElementRef;

  constructor(
    private routerHandler: RouterHandler,
    private dialogService: DialogService,
    private serverApiService: ServerRestApiService,
    private fb: UntypedFormBuilder
  ) {
    this.isPending = true;
    let fragment = this.routerHandler.getRoute().fragment['recover-account'];
    if (fragment) {
      this.urlToken = fragment;
      this.serverApiService
        .accountRecoveryChallenge(this.urlToken)
        .then((response) => {
          this.accountId = response.account_id;
          this.signingSecretEc = base64.parse(response.signing_secret_ec);
          this.isPending = false;
        })
        .catch((err) => {
          console.log('wrong url fragment', err);
          this.dialogService.openAlertDialog(marker('Error'), marker('Wrong or broken url token.'));
          this.routerHandler.navigate(['/']);
        });
    } else {
      this.dialogService.openAlertDialog(marker('Error'), marker('Missing url token.'));
      this.routerHandler.navigate(['/']);
    }

    this.isDarkTheme = AppStorage.getItem('style_mode') == 'dark';
    styleChangedObserver.subscribe((style) => {
      this.isDarkTheme = style == 'dark';
    });
  }

  ngOnInit(): void {
    this.passwordGroup
      .get('password2')
      .addValidators([NanoValidators.controlEquals(this.passwordGroup.get('password'))]);
    this.passwordGroup
      .get('password')
      .addValidators([NanoValidators.passwordStrengthLow(() => this.passwordScore)]);

    this.passwordGroup.get('password').valueChanges.subscribe((e) => {
      if (this.passwordGroup.get('password2').touched) {
        this.passwordGroup.get('password2').updateValueAndValidity();
      }
    });
  }

  public uploadKey(event) {
    let files = event?.target?.files;
    if (files) {
      let file = files[0];
      searchRecoveryKeyFromFile(file)
        .then((key) => {
          this.recoveryKeyGroup.get('recoveryKey').setValue(base64.stringify(key));
          this.masterKey = key;
          this.recoveryKeyInput.nativeElement.focus();
        })
        .catch((err) => {
          console.error('can not find recovery key in the file', err);
          this.dialogService.openAlertDialog(
            marker('Error'),
            marker('Can not find recovery key in the file')
          );
        });
    }
  }

  public parseRecoveryKey() {
    try {
      this.masterKey = base64.parse(this.recoveryKeyGroup.get('recoveryKey').value);
      this.currStep = this.stepPassword;
    } catch (e) {
      this.dialogService.openAlertDialog(marker('Error'), marker('Code is invalid or broken.'));
    }
  }

  public backToRecoverytStep() {
    this.currStep = this.stepRecovery;
  }

  public passwordStrength(score) {
    this.passwordScore = score;
    this.passwordGroup.get('password').updateValueAndValidity();
  }

  public submit() {
    this.isPending = true;

    create_account_recovery_confirm_request(
      PrivateKeyringV1,
      this.urlToken,
      this.accountId,
      this.signingSecretEc,
      this.masterKey,
      this.passwordGroup.get('password').value,
      USE_PASSWORD_NORMALIZATION
    )
      .then((result) => {
        this.serverApiService
          .accountRecoverConfirm(result)
          .then(() => {
            this.dialogService.openAlertDialog(
              marker('Success'),
              marker('Password change was succesful')
            );
            this.routerHandler.navigate(['/login']);
          })
          .catch((err) => {
            console.log('acc confirm err', err);
            this.dialogService.openAlertDialog(
              marker('Error'),
              marker('Error happened during the operation')
            );
          });
      })
      .catch((err) => {
        console.error('recovery confirm error', err);
        this.dialogService.openAlertDialog(
          marker('Error'),
          marker('Error happened during the operation')
        );
      })
      .finally(() => {
        this.isPending = false;
      });
  }
}
