<template>
  <div class="form-group password-box" :class="{hidden: !dataPasswordVisible}">
    <label v-if="label" class="form-label" :for="id">
      {{ label }}
      <span v-if="$attrs.required !== undefined" class="form-required">*</span>
    </label>
    <div class="input-group">
      <input
        class="form-control"
        :id="id"
        ref="password"
        :class="{ 'is-invalid': hasError }"
        :type="dataType"
        v-bind="$attrs"
        v-on="inputListeners"
        :data-toggle-password-visibility="isPassword"
      >
      <span class="input-group-append" v-if="passwordVisible">
        <button
          class="btn btn-secondary"
          :title="isPasswordVisible? 'Hide password':'Show password'"
          :aria-label="isPasswordVisible? 'Hide password':'Show password'"
          type="button"
          @click="togglePasswordVisibility"
        >
          <eb-icon v-if="isPasswordVisible" type="eye-off"/>
          <eb-icon v-else type="eye"/>
        </button>
      </span>
    </div>

    <div v-if="showStrengthMeter || strengthMeterOnly">
      <div class="progress progress-xs">
        <div
          :class="`progress-bar bg-${strengthMeterClass}`"
          role="progressbar"
          :style="`width: ${passwordStrength}%`"
          :aria-valuenow="passwordStrength"
          aria-valuemin="0"
          aria-valuemax="100"
        ></div>
      </div>
      <div class="clearfix">
        <div class="float-left">
          <strong>{{passwordStrength ? passwordStrength : 0 }}%</strong>
          <span>&nbsp;&nbsp;{{suggestion}}</span>
        </div>
        <div class="float-right">
          <small class="text-muted">{{ passwordCount }}</small>
        </div>
      </div>
    </div>

    <div v-if="hasError" class="invalid-feedback d-block">
      <slot name="invalid-feedback">{{ getError }}</slot>
    </div>
  </div>
</template>

<script>
import EbIcon from '../eb-icon/eb-icon';
import { unloadScript, loadScript } from '../../../helpers';
import ErrorMixin from '../../../mixins/error-mixin';
const ZXCVBN_SRC = '//cdnjs.cloudflare.com/ajax/libs/zxcvbn/4.4.2/zxcvbn.js';

export default {
  name: 'EbPasswordInput',

  components: { EbIcon },

  mixins: [ErrorMixin],

  inheritAttrs: false,

  model: {
    event: 'input'
  },

  props: {
    id: {
      type: String,
      default() {
        return `text-password-input-${this._uid}`;
      }
    },
    passwordVisible: {
      type: Boolean,
      default: false
    },
    type: {
      type: String,
      default: 'password'
    },
    label: String,
    secureLength: {
      type: Number,
      default: 7
    },
    badge: {
      type: Boolean,
      default: true
    },
    showStrengthMeter: {
      type: Boolean,
      default: false
    },
    strengthMeterOnly: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      dataPasswordVisible: this.isPassword && this.passwordVisible,
      dataType: this.type,
      password: null,
      zxcvbn: null
    };
  },
  watch: {
    passwordVisible() {
      if (this.passwordVisible !== this.dataPasswordVisible) {
        this.togglePasswordVisibility();
      }
    },
    type() {
      this.dataType = this.type;
    },
    value(newValue) {
      if (this.strengthMeterOnly) {
        this.emitValue('input', newValue);
      }
    },
    passwordStrength(score) {
      this.$emit('score', score);
      this.$emit('feedback', zxcvbn(this.password).feedback);
    }
  },
  computed: {
    isPassword() {
      return this.type === 'password';
    },
    isPasswordVisible() {
      return this.isPassword && this.dataPasswordVisible;
    },
    inputListeners(evt) {
      return {
        input: evt => this.emitValue('input', evt.target.value),
        blur: evt => this.emitValue('blur', evt.target.value),
        focus: evt => this.emitValue('focus', evt.target.value)
      };
    },
    passwordStrength() {
      return this.password && (this.strengthMeterOnly || this.showStrengthMeter)
        ? this.zxcvbn(this.password).score * 25
        : null;
    },
    isSecure() {
      return this.password ? this.password.length >= this.secureLength : null;
    },
    isActive() {
      return this.password && this.password.length > 0;
    },
    passwordCount() {
      return (
        this.password &&
        (this.password.length > this.secureLength
          ? `${this.secureLength}+`
          : this.password.length)
      );
    },
    strengthMeterClass() {
      if (this.passwordStrength > 80) return 'green';
      if (this.passwordStrength > 60) return 'yellow';
      if (this.passwordStrength > 40) return 'orange';
      if (this.passwordStrength > 20) return 'red';
      if (this.passwordStrength > 0) return 'danger';

      return '';
    },
    suggestion() {
      if (this.passwordStrength > 80) return 'Perfect!';
      if (this.passwordStrength > 60)
        return 'Good! Consider adding a bit more pizzaz';
      if (this.passwordStrength > 40)
        return 'Weak, can be made better, why not add symbols';
      if (this.passwordStrength > 20)
        return 'Very weak, your password is easily guessable';
      if (this.passwordStrength > 0)
        return 'please consider using a combination of Letters, Symbols and Numbers';

      return '';
    }
  },

  methods: {
    togglePasswordVisibility() {
      const currentValue = this.$refs.password.value;
      this.dataPasswordVisible = !this.dataPasswordVisible;
      this.$emit(this.dataPasswordVisible ? 'show' : 'hide');
      this.dataType = this.dataPasswordVisible ? 'text' : 'password';

      this.$nextTick(() => {
        this.$refs.password.value = currentValue;
      });
    },
    emitValue(type, value) {
      this.$emit(type, value);
      this.password = value;
    },

    unloadZxcvbn() {
      unloadScript(ZXCVBN_SRC)
        .then(() => {
          this.zxcvbn = null;
        })
        .catch(() => {
          this.zxcvbn = null;
        });
    },

    loadZxcvbn() {
      // if (!isScriptLoaded(ZXCVBN_SRC)) {
      //   console.log('This is Loading', this.zxcvbn);
      //   this.zxcvbn = window.zxcvbn;
      //   return;
      // }

      loadScript(ZXCVBN_SRC)
        .then(() => {
          // Script is loaded, do something
          this.zxcvbn = window.zxcvbn;
        })
        .catch(() => {
          this.loadZxcvbn();
        });
    }
  },

  created() {
    if (this.showStrengthMeter || this.strengthMeterOnly) {
      this.unloadZxcvbn();
      this.loadZxcvbn();
    }
  },

  destroyed() {
    this.unloadZxcvbn();
  }
};
</script>

<style scoped>
.form-control.is-invalid,
input.is-invalid {
  border-color: #cd201f;
  padding-right: calc(1.6em + 0.75rem);
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='%23cd201f' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23cd201f' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E");
  background-repeat: no-repeat;
  background-position: center right calc(0.4em + 0.1875rem);
  background-size: calc(0.8em + 0.375rem) calc(0.8em + 0.375rem);
}

.el-table th div {
  padding-left: 0;
  padding-right: 0;
}

.cell > .form-group {
  margin-bottom: 0;
  vertical-align: bottom;
  padding-top: 0.75rem;
}
.password-box .input-icon-addon .eb-icon {
  cursor: pointer;
}

.password-box .progress {
  border-radius: 0 0 2px 2px;
}
</style>