/* eslint-disable array-callback-return */
/* eslint-disable no-useless-escape */
import {DataUtil} from '../_utils/index'

export interface IPasswordMeterOptions {
  minLength: number
  checkUppercase: boolean
  checkLowercase: boolean
  checkDigit: boolean
  checkChar: boolean
  scoreHighlightClass: string
}

export interface IPasswordMeterQueries {
  componentName: string
  instanseQuery: string
  inputQuery: string
  visibilityQuery: string
  highlightQuery: string
}

const defaultPasswordMeterOptions = {
  minLength: 8,
  checkUppercase: true,
  checkLowercase: true,
  checkDigit: true,
  checkChar: true,
  scoreHighlightClass: 'active',
}

const defaultPasswordMeterQueires: IPasswordMeterQueries = {
  componentName: 'password-meter',
  instanseQuery: '[data-kt-password-meter]',
  inputQuery: 'input[type]',
  visibilityQuery: '[data-kt-password-meter-control="visibility"]',
  highlightQuery: '[data-kt-password-meter-control="highlight"]',
}

class PasswordMeterComponent {
  element: HTMLElement
  inputElement: HTMLInputElement | null
  visibilityElement: HTMLElement | null
  highlightElement: HTMLElement | null
  options: IPasswordMeterOptions
  queries: IPasswordMeterQueries
  score: number
  checkSteps: number

  constructor(
    _element: HTMLElement,
    _options: IPasswordMeterOptions,
    _queries: IPasswordMeterQueries
  ) {
    this.element = _element
    this.options = Object.assign(defaultPasswordMeterOptions, _options)
    this.queries = _queries
    this.score = 0
    this.checkSteps = 5

    // Elements
    this.inputElement = this.element.querySelector(this.queries.inputQuery)
    this.visibilityElement = this.element.querySelector(this.queries.visibilityQuery)
    this.highlightElement = this.element.querySelector(this.queries.highlightQuery)

    // Event Handlers
    this.handlers()

    DataUtil.set(this.element, this.queries.componentName, this)
  }

  private handlers(): void {
    if (this.inputElement) {
      this.inputElement.addEventListener('input', () => {
        this.check()
      })
    }

    if (this.visibilityElement) {
      this.visibilityElement.addEventListener('click', () => {
        this.visitbility()
      })
    }
  }

  private visitbility() {
    if (this.visibilityElement && this.inputElement) {
      const visibleIcon = this.visibilityElement.querySelector(
        'i:not(.d-none), .svg-icon:not(.d-none)'
      )

      const hiddenIcon = this.visibilityElement.querySelector('i.d-none, .svg-icon.d-none')

      const typeAttr = this.inputElement.getAttribute('type') || ''

      if (typeAttr === 'password') {
        this.inputElement.setAttribute('type', 'text')
      } else {
        this.inputElement.setAttribute('type', 'password')
      }

      visibleIcon?.classList.add('d-none')
      hiddenIcon?.classList.remove('d-none')

      this.inputElement.focus()
    }
  }

  private checkScore(): number {
    return 0
  }

  private checkLength(): boolean {
    if (this.inputElement) {
      return this.inputElement.value.length >= this.options.minLength // 20 score
    }

    return false
  }

  private checkLowerCase(): boolean {
    const val = this.inputElement ? this.inputElement.value : ''
    return /[a-z]/.test(val) // 20 score
  }

  private checkUppercase(): boolean {
    const val = this.inputElement ? this.inputElement.value : ''
    return /[A-Z]/.test(val) // 20 score
  }

  private checkDigit(): boolean {
    const val = this.inputElement ? this.inputElement.value : ''
    return /[0-9]/.test(val) // 20 score
  }

  private checkChar(): boolean {
    const val = this.inputElement ? this.inputElement.value : ''
    return /[~`!#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g.test(val) // 20 score
  }

  private getCheckScore(): number {
    let count = 1
    if (this.options.checkUppercase) {
      count++
    }

    if (this.options.checkLowercase) {
      count++
    }

    if (this.options.checkDigit) {
      count++
    }

    if (this.options.checkChar) {
      count++
    }

    this.checkSteps = count
    return 100 / this.checkSteps
  }

  private highlight() {
    const items = this.highlightElement
      ? [].slice.call(this.highlightElement.querySelectorAll('div'))
      : []
    const total = items.length
    let index = 0
    const checkScore = this.getCheckScore()
    const score = this.getScore()

    items.map((item: HTMLElement) => {
      index++
      if (checkScore * index * (this.checkSteps / total) <= score) {
        item.classList.add('active')
      } else {
        item.classList.remove('active')
      }
    })
  }

  ///////////////////////
  // ** Public API  ** //
  ///////////////////////
  public reset = () => {
    this.score = 0
    this.highlight()
  }

  public getScore() {
    return this.score
  }

  public check() {
    let score = 0
    const checkScore = this.getCheckScore()
    if (this.checkLength()) {
      score = score + checkScore
    }

    if (this.options.checkUppercase && this.checkLowerCase()) {
      score = score + checkScore
    }

    if (this.options.checkLowercase && this.checkUppercase()) {
      score = score + checkScore
    }

    if (this.options.checkDigit && this.checkDigit()) {
      score = score + checkScore
    }

    if (this.options.checkChar && this.checkChar()) {
      score = score + checkScore
    }

    this.score = score
    this.highlight()
  }

  // Static methods
  public static getInstance = (
    el: HTMLElement,
    componentName: string = defaultPasswordMeterQueires.componentName
  ) => {
    const passwordMeter = DataUtil.get(el, componentName)
    if (passwordMeter) {
      return passwordMeter
    }

    return null
  }

  public static createInstances = (
    selector: string = defaultPasswordMeterQueires.instanseQuery,
    options: IPasswordMeterOptions = defaultPasswordMeterOptions,
    queries: IPasswordMeterQueries = defaultPasswordMeterQueires
  ) => {
    const elements = document.body.querySelectorAll(selector)
    elements.forEach((el) => {
      const item = el as HTMLElement
      let passwordMeter = PasswordMeterComponent.getInstance(item)
      if (!passwordMeter) {
        passwordMeter = new PasswordMeterComponent(item, options, queries)
      }
    })
  }

  public static createInsance = (
    selector: string = defaultPasswordMeterQueires.instanseQuery,
    options: IPasswordMeterOptions = defaultPasswordMeterOptions,
    queries: IPasswordMeterQueries = defaultPasswordMeterQueires
  ): PasswordMeterComponent | undefined => {
    const element = document.body.querySelector(selector)
    if (!element) {
      return
    }
    const item = element as HTMLElement
    let passwordMeter = PasswordMeterComponent.getInstance(item)
    if (!passwordMeter) {
      passwordMeter = new PasswordMeterComponent(item, options, queries)
    }
    return passwordMeter
  }

  public static bootstrap = (selector: string = defaultPasswordMeterQueires.instanseQuery) => {
    PasswordMeterComponent.createInstances(selector)
  }

  public static reinitialization = (
    selector: string = defaultPasswordMeterQueires.instanseQuery
  ) => {
    PasswordMeterComponent.createInstances(selector)
  }
}
export {PasswordMeterComponent, defaultPasswordMeterOptions, defaultPasswordMeterQueires}