// Angular Core
import { Component, ElementRef, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { HttpErrorResponse } from '@angular/common/http';

// RxJs
import { Subscription, throwError } from 'rxjs';
import { catchError } from "rxjs/operators";

// Services
import { RegisterService } from '../../services/register/register.service';
import { LoginService } from '../../services/login/login.service';
import { SessionService } from 'src/app/services/session/session.service';
import { LocalStorageService } from 'src/app/services/localstorage/local-storage.service';
import { environment } from 'src/environments/environment';
import { DataTransmitterService } from 'src/app/services/dataTransmitter/data-transmitter.service';
import { UtilitiesService } from 'src/app/services/utilities/utilities.service';

@Component({
  standalone: false,
  selector: 'app-this.registerService',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.scss']
})
export class RegisterComponent implements OnInit, OnDestroy {

  newUserForm: any = FormGroup;
  submitted: boolean = false;
  color: string = 'red';
  isPasswordsNotMatch: boolean = false;
  enableCheckEqualMsg: boolean = false;
  checkEqualMsg: string = '';
  placeholderValue = 'Enter your DEA License Number';
  validateRegEx = /^(?=.*[a-zA-Z])(?=.*[0-9])[A-Za-z0-9]{9,9}$/;
  userNameMsg = 'DEA must have 9 characters only and must be alphanumeric';
  renderMe: boolean = false;
  loginInfo: any = {};
  classifications: any = [];
  classificationArray: any = [];
  specialties: any = [];
  specialityArray: any = [];
  previewUserData: any = {};
  showPassword: boolean = false;
  showConfirmPassword: boolean = false;
  validateUnameMsg: string = '';
  validatePwdMsg: string = "";
  imgUrl: string = environment.imageUrl;
  sitename!: string;
  sitenameListener!: Subscription;
  previewUserSubscribe!: Subscription;
  isPmsUser: boolean = false;
  isLoading: boolean = false;

  /**
  * Default config object
  * @type Object
  */
  config = {
    showMsg: false,
    errorMessage: ''
  };

  constructor(
    private formBuilder: FormBuilder,
    private router: Router,
    private registerService: RegisterService,
    private loginService: LoginService,
    private sessionService: SessionService,
    private el: ElementRef,
    private localStorageService: LocalStorageService,
    private dataTransmitter: DataTransmitterService,
    private utilitiesService:UtilitiesService
  ) {
    this.newUserForm = this.formBuilder.group({});
  }

  ngOnInit(): void {
    this.sitenameListener = this.dataTransmitter.sitename.subscribe((sitename) => {
      this.utilitiesService.updateLiveChat();
      this.sitename = sitename;
    });
    this.newUserForm = this.formBuilder.group({
      account_classification_id: ['', Validators.required],
      account_specialty_id: ['', Validators.required],
      is_hin: [''],
      user_name: ['', Validators.required],
      password: ['', Validators.required],
      confirm_password: ['', Validators.required],
      email_address: ['', [Validators.required, Validators.email, Validators.pattern(/^\S+@\S+\.\S+$/)]],
      legal_company_dba: ['', [Validators.required, Validators.maxLength(100)]],
      legal_phone: ['', Validators.required],
      learnt_through: [''],
      reg_purpose: [''],
      new_reg_demo: [''],
      new_reg_order_min_training: [''],
      signer_name: ['', Validators.required],
      termsconditions: [false, Validators.required],
    });
    this.isLoading = true;
    this.checkSession();
    this.formControlValueChanged();
    this.sessionService.logOut().subscribe({
        complete: () => {
            this.getClassifications();
        }
    });
  }

  formControlValueChanged() {
    const learnt_through = this.newUserForm.get('learnt_through');
    const reg_purpose = this.newUserForm.get('reg_purpose');
    const new_reg_demo = this.newUserForm.get('new_reg_demo');
    const new_reg_order_min_training = this.newUserForm.get('new_reg_order_min_training');
    this.newUserForm.get('account_classification_id').valueChanges.subscribe(
      (val: number) => {
        if (val == 1 || val == 2) {
          learnt_through.setValidators([Validators.required]);
          reg_purpose.setValidators([Validators.required]);
          new_reg_demo.setValidators([Validators.required]);
          new_reg_order_min_training.setValidators([Validators.required]);
        } else {
          learnt_through.clearValidators();
          reg_purpose.clearValidators(); 
          new_reg_demo.clearValidators();
          new_reg_order_min_training.clearValidators();
        }
        learnt_through.updateValueAndValidity();
        reg_purpose.updateValueAndValidity();
        new_reg_demo.updateValueAndValidity();
        new_reg_order_min_training.updateValueAndValidity();
      });

      this.newUserForm.get('confirm_password').valueChanges.subscribe(
        (val: string) => {
          const pwd1 = this.newUserForm.controls['password'].value;
          const pwd2 = val;
          if ((pwd1 !== null && pwd1 !== '' && typeof pwd1 !== 'undefined') &&
            (pwd2 !== null && pwd2 !== '' && typeof pwd2 !== 'undefined')) {
            this.enableCheckEqualMsg = true;
          } else {
            this.enableCheckEqualMsg = false;
          }
          if (pwd1 === pwd2) {
            this.checkEqualMsg = 'Passwords match!';
            this.isPasswordsNotMatch = false;
          } else {
            this.checkEqualMsg = 'Passwords do not match!';
            this.isPasswordsNotMatch = true;
          } 
        });
  }

  get newUserFormData() { return this.newUserForm.controls; }

  /**
   * Preparing Classification Array for further use in manageAccountClassification method.
   * @returns {undefined}
   */
  prepareClassificationArray() {
    this.classifications.forEach((value: any) => {
      this.classificationArray[value.id] = value.name;
    });
  };

  getClassificationsSubscribe!:Subscription;
  getSpecialtiesSubscribe!:Subscription;
  createNewUserSubscribe!:Subscription;
  isUserExistSubscribe!:Subscription;
  authenticateUserSubscribe!:Subscription;
 
  getClassifications() {
    this.getClassificationsSubscribe = this.registerService
      .getClassifications()
      .pipe(
        catchError(() => {
          return throwError(() => new Error('ups sommething happend'));
        })
      )
      .subscribe({
        next: (res: any) => {
          this.classifications = res.data;
          this.prepareClassificationArray();
        },
        error: (err: HttpErrorResponse) => {
          this.registerService.errorCallBack(err);
        },
        complete: () => { }
      });
  }

  /**
   * Gets specialities based on given classificationId
   * @param int classificationsId
   * 
   * @returns void
  */
  getSpecialities(classificationsId: number) {
    if (classificationsId !== undefined && classificationsId !== null) {
      this.specialties = []
      this.specialityArray = []
      this.newUserFormData.account_specialty_id.patchValue('');
      this.getSpecialtiesSubscribe = this.registerService
        .getSpecialties(classificationsId)
        .pipe(
          catchError(() => {
            return throwError(() => new Error('ups sommething happend'));
          })
        )
        .subscribe({
          next: (res: any) => {
            this.specialties = res.data;
            this.prepareSpecialityArray();
          },
          error: (err: HttpErrorResponse) => {
            this.registerService.errorCallBack(err);
          },
          complete: () => {

          }
        });
    }
  };

  /**
   * Preparing Speciality Array for further use in manageAccountClassification method.
   * @returns {undefined}
   */
  prepareSpecialityArray() {
    this.specialties.forEach((value: any) => {
      this.specialityArray[value.account_specialty_id] = value.as_name;
    });
  };

  validatePassword(p: string, status: boolean, field: string) {
    var passwordPattern = /(?=.*\d)(?=.*[A-Z,a-z]).{6,}/;
    if (p !== undefined && p !== '') {
      if (!passwordPattern.test(p.toString()) && status && p !== '') {
        this.validatePwdMsg = "Password must have minimum 6 characters and must be alphanumeric";
        this.newUserFormData.password.setErrors({ incorrect: true });
      } else {
        this.validatePwdMsg = "";
        this.newUserFormData.password.setErrors(null);
      }
    } else {
      this.newUserFormData.password.setErrors({ required: true });
      this.validatePwdMsg = "";
    }
  };

  validatePhoneNum(phone: any, status: boolean, field: string) {
    if (phone !== '' && phone !== null && phone !== undefined) {
      if ((!(/^\d{10}$/.test(phone.toString()) || /^\d{3}-?\d{3}-?\d{4}$/.test(phone.toString())))
        && status) {
        this.newUserFormData.legal_phone.setErrors({ incorrect: true });
      } else if (/^\d{10}$/.test(phone.toString()) === true && phone.length > 10) {
        this.newUserFormData.legal_phone.setErrors({ incorrect: true });
      } else {
        this.newUserFormData.legal_phone.setErrors(null);
      }
    } else {
      this.newUserFormData.legal_phone.setErrors({ required: true });
    }
  };

  checkPasswordStrength(pwd: string) {
    var score = this.test(pwd);
    if (score > 3) {
      this.color = 'green';
      return "Entered password is Excellent";
    }
    if (score === 3) {
      this.color = 'green';
      return "Entered password is Strong";
    } else if (score === 2) {
      this.color = 'yellow';
      return "Entered password is Good";
    } else if (score === 1) {
      this.color = 'red';
      return "Entered password is Weak";
    } else {
      return null;
    }

  };

  test(pass: string) {
    var tests = [/[0-9]/, /[a-z]/, /[A-Z]/, /[^A-Z-0-9]/i];
    if (pass === null || pass === '' || typeof pass === 'undefined')
      return -1;
    var s = 0;
    if (pass.length < 6 || pass === null || pass === undefined)
      return 0;
    for (var i in tests) {
      if (tests[i].test(pass))
        s++;
    }
    return s;
  };

  checkForEquals(pwd1: string, pwd2: string) {
    if ((pwd1 !== null && pwd1 !== '' && typeof pwd1 !== 'undefined') &&
      (pwd2 !== null && pwd2 !== '' && typeof pwd2 !== 'undefined')) {
      this.enableCheckEqualMsg = true;
    } else {
      this.enableCheckEqualMsg = false;
    }
    if (pwd1 === pwd2) {
      this.checkEqualMsg = 'Passwords match!';
      this.isPasswordsNotMatch = false;
    } else {
      this.checkEqualMsg = 'Passwords do not match!';
      this.isPasswordsNotMatch = true;
    }
    return this.checkEqualMsg;
  };

  private scrollToFirstInvalidControl() {
    const firstInvalidControl: HTMLElement = this.el.nativeElement.querySelector(
      "form .ng-invalid"
    );

    window.scroll({
      top: this.getTopOffset(firstInvalidControl),
      left: 0,
      behavior: "smooth"
    });
  }

  private getTopOffset(controlEl: HTMLElement): number {
    const labelOffset = 50;
    return controlEl.getBoundingClientRect().top + window.scrollY - labelOffset;
  }

  /**
   * Create New User
   * @returns {undefined}
   */
  newUserRegister() {

    this.submitted = true;
    let formObj = this.newUserForm.value;
    this.isUserExist(formObj.user_name);
    if (this.newUserForm.invalid === true) {
      this.scrollToFirstInvalidControl();
      return;
    }
    if(formObj.account_classification_id !== 1 && formObj.account_classification_id !== 2){
      delete formObj.learnt_through;
      delete formObj.reg_purpose
      delete formObj.new_reg_demo
      delete formObj.new_reg_order_min_training
    }
    formObj.account_specialty_id = formObj.account_specialty_id.toString();
    delete formObj.termsconditions;
    this.createNewUserSubscribe = this.registerService
      .createNewUser(formObj)
      .pipe(
        catchError(() => {
          return throwError(() => new Error('ups sommething happend'));
        })
      )
      .subscribe({
        next: () => {
          this.validateLogin(this.newUserFormData.user_name.value, this.newUserFormData.password.value);
          this.getUserSession();
        },
        error: (err: HttpErrorResponse) => {
          this.registerService.errorCallBack(err);
        },
        complete: () => { }
      });

  };

    /**
     * Preview user registration
     * @returns void
    */
    previewUserRegistration() {
        this.submitted = true;
        let formObj = this.newUserForm.value;
        if (formObj.password === "" || formObj.email_address === "") {
            return;
        }
        this.previewUserData = {
            'username': formObj.user_name,
            'password': formObj.password,
            'confirm_password': formObj.confirm_password,
            'email': formObj.email_address
        }
        this.previewUserSubscribe = this.registerService
          .updatePmsAuthInfo(this.previewUserData)
          .subscribe({
            next: () => {
              this.validateLogin(this.newUserFormData.user_name.value, this.newUserFormData.password.value);
              this.getUserSession();
            },
            error: (err: HttpErrorResponse) => {
              this.registerService.errorCallBack(err);
            },
            complete: () => { }
        });
    };

  /**
   * Select All functionality for Ques 2
   * @returns {undefined}
   */
  selectAll() {
    this.newUserFormData.reg_purpose.patchValue([
      "Shop Hard to Find Items", "Price Compare Negative/Low Reimbursement Items", "Save $10k+ Per Month", "Use PrimeRx Market as Primary Rx Source", ""
    ]);
  };



  isUserExist(UserName: string) {
    this.isPmsUser = false;
    this.isUserExistSubscribe = this.registerService
      .getUserInfo(UserName)
      .pipe(
        catchError((err: HttpErrorResponse) => {
          this.registerService.errorCallBack(err);
          return throwError(() => err);
        })
      )
      .subscribe({
        next: (res: any) => {
            let isUserExist = res.data && Object.keys(res.data).length > 0;
            if (isUserExist && !res.data.is_preview_mode) {
                this.validateUnameMsg = 'This DEA already has an account.  Please login or contact Customer Service';
                this.newUserFormData.user_name.setErrors({ incorrect: true });
            }
            /**
             * For PMS user if user has already started their initial registration
             * then display validation message and navigate to login page
             * otherwise PMS registration page
            */
            if (isUserExist && res.data.is_preview_mode && res.data.is_pms_registration_initiated) {
                this.validateUnameMsg = 'This DEA already has an account.  Please login or contact Customer Service';
                this.newUserFormData.user_name.setErrors({ incorrect: true });
                setTimeout( () => {
                    this.router.navigate(['/market/login']);
                }, 3000);
            }
            if (isUserExist && res.data.is_preview_mode && !res.data.is_pms_registration_initiated) {
                this.isPmsUser = true;
                this.newUserForm.patchValue({
                    user_name: res.data.username,
                    email_address: res.data.email
                });
            }
        },
        error: (err: HttpErrorResponse) => {
          this.registerService.errorCallBack(err);
        },
        complete: () => { }
      });
  };

  /**
   * Validates DEA/HIN License
   * 
   * @param userName
   * @param field
  */
  validateUserName(userName: string, field: any) {
    if (userName !== '') {
      this.validateUnameMsg = '';
      if (!this.validateRegEx.test(userName.toString())) {
        this.validateUnameMsg = this.userNameMsg;
        this.newUserFormData.user_name.setErrors({ incorrect: true });
      } else {
        this.isUserExist(userName);
        this.newUserFormData.user_name.setErrors(null);
      }
    } else {
      this.newUserFormData.user_name.setErrors({ required: true });
    }
  };

  /**
  * return session object as a promise
  * @returns {object.promise|$q@call;defer.promise}
  */

  getAuthUserPromise(deaNumber: string, password: string) {
    return new Promise((resolve) => {
      this.authenticateUserSubscribe = this.loginService.authenticateUser(deaNumber, password)
        .pipe(
          catchError(() => {
            return throwError(() => new Error('ups sommething happend'));
          })
        )
        .subscribe({
          next: (res: any) => {
            let response = res;
            resolve(response);
          },
          error: (err: HttpErrorResponse) => {
            location.reload();
          },
          complete: () => { }
        });
    })
  };

  /**
  * Method to authenticate user
  */
  validateLogin(deaNumber: string, password: string) {

    this.getAuthUserPromise(deaNumber, password).then((res: any) => {
      if (res) {
        this.loginInfo = res.data;
        this.setUserRoute();
      }
    }).catch(err => {
      this.loginService.errorCallBack(err);
    });

  };
  session: any = {};
  /**
   * Get user session and return defer promise
   * @returns {.$q@call;defer.promise}
   */
  checkSession() {
    return new Promise((resolve) => {
      var r = this.sessionService.get();
      r.then(() => {
        this.session = this.sessionService.getSession();
        if (this.session.is_preview_mode && !this.isPmsUser) {
            this.isPmsUser = true;
            this.newUserForm.patchValue({
                user_name: this.session.username,
                email_address: this.session.confirm_email
            });
        }
        this.isLoading = false;
        resolve(this.session);
      });
    }).catch(err => {
    })
  };

  /**
   * Check session and redirect the user if true
   * @returns {undefined}
   */
  getUserSession() {
    this.checkSession().then(() => {
      if (this.session.logged_in) {
        this.loginInfo.reg_step = this.session.reg_step;
        this.loginInfo.message = this.session.message;
        this.loginInfo.is_buyer = this.session.is_buyer;
        this.redirectUser();
      } else {
        this.renderMe = true;
        this.localStorageService.clear();
      }
    }).catch(err => {
      this.sessionService.errorCallBack(err);
    });
  };

  /**
   * Redirect user based to registration step, account type and error message
   * @returns {undefined}
   */
  redirectUser() {
    //redirect to specific url based on the registration step the user is in
    if (this.loginInfo.reg_step === 1) {
      if (this.loginInfo.message === 'Confirm Email Pending') {
        this.router.navigate(['/market/confirmEmail'])
      }
    }
  };
  authenticate: boolean = true;
  /**
  * Set redirect when authenticate is true else show error from response
  * @returns {undefined}
  */
  setUserRoute() {
    this.sessionService.reCheckSession();
    this.config.errorMessage = this.loginInfo.errorMessage;
    switch (this.loginInfo.message) {
      case "Active User":
      case "Confirm Email Pending":
        this.authenticate = true;
        this.redirectUser();
        break;
      case "Invalid Login details":
        this.authenticate = false;
        break;
    }
  };

  /**
   * Enable/Disable HIN By clicking checkbox
   * And update required values
   * 
   * @param checkValue
  */
  enableOrDisableHin(checkValue: boolean) {
    this.validateUnameMsg = '';
    this.newUserFormData.user_name.patchValue('')
    if (checkValue === true) {
      this.placeholderValue = 'Enter your HIN Number';
      this.validateRegEx = /^(?=.*[a-zA-Z])(?=.*[0-9])[A-Za-z0-9]{9,13}$/;
      this.userNameMsg = 'HIN must have minimum 9, maximum 13 characters and must be alphanumeric.';
    } else {
      this.placeholderValue = 'Enter your DEA License Number';
      this.validateRegEx = /^(?=.*[a-zA-Z])(?=.*[0-9])[A-Za-z0-9]{9,9}$/;
      this.userNameMsg = 'DEA must have 9 characters only and must be alphanumeric.';
    }
  };

  /**
   * Enable/Disable Password By clicking Eye icon
  */
  toggleShowPassword() {
    this.showPassword = !this.showPassword;
  };

  /**
   * Enable/Disable Confirm Password By clicking Eye icon
  */
  toggleShowConfirmPassword() {
    this.showConfirmPassword = !this.showConfirmPassword;
  };

  /**
   * Below method will set Account Classification of User to Medical Facility
   * If User selects Registering as "Pharmacy" and Business Type as Clinic/Medical Facility.
   *
   * @param {type} accountClassificationId
   * @param {type} accountSpecialityId
   * @returns {undefined}
   */
  manageAccountClassification(accountClassificationId: any, accountSpecialityId: any) {
    if (this.classificationArray[accountClassificationId] === 'Pharmacy'
      && (this.specialityArray[accountSpecialityId] === 'Clinic' || this.specialityArray[accountSpecialityId] === 'Medical Facility')) {
      this.newUserFormData.account_classification_id.patchValue(2); //i.e, Setting Account Classification as Medical Facility
      this.getSpecialities(2);
    }
  };

  /* Method introduced as part of TRX-7912
   * Resets form submission values
   *
   * @param string formName
   *
   * @return void
  */
  resetFormSubmit() {
    this.submitted = false;
  };

  ngOnDestroy(){
    this.getClassificationsSubscribe?.unsubscribe();
    this.getSpecialtiesSubscribe?.unsubscribe();
    this.createNewUserSubscribe?.unsubscribe();
    this.isUserExistSubscribe?.unsubscribe();
    this.authenticateUserSubscribe?.unsubscribe();
    this.sitenameListener.unsubscribe();
    this.previewUserSubscribe?.unsubscribe();
  }
}
