<template>
  <FormWrapper class="space-input" v-bind="formProps" ref="elementRef">
    <input
      class="grow h600 mask-input"
      :class="{ disabled: disabled }"
      :placeholder="placeholder"
      :disabled="disabled"
      @input="changeHandler"
      @focus="$emit('focus')"
      :type="type"
      @keydown.enter="submit"
      v-focus-directive="focus"
      v-max-value-directive="maxValue"
      v-numeric-directive="numeric"
      v-max-length-directive="maxLength"
      v-digits-directive="digits"
    />
    <div class="input-icon">
      <slot />
    </div>
    <div class="icon input-icon" v-if="icon">
      <SpIcon :name="icon" />
    </div>
  </FormWrapper>
</template>

<script lang="ts">
import {
  defineComponent,
  onBeforeUnmount,
  onMounted,
  reactive,
  ref,
  toRefs,
  watch,
} from "vue";
import { NumericDirective } from "@/directives/numeric";
import { MaxValueDirective } from "@/directives/max-value";
import { DigitsDirective } from "@/directives/digits";
import { MaxLengthDirective } from "@/directives/max-length";
import { FocusDirective } from "@/directives/focus";
import FormWrapper from "../FormWrapper.vue";
import FormMixin from "@/mixins/FormMixin";
import IMask, { InputMask } from "imask";

export default defineComponent({
  mixins: [FormMixin],
  emits: ["update:modelValue", "focus"],
  props: {
    modelValue: {
      type: [String, Number, Object],
      required: true,
    },
    numeric: {
      type: Boolean,
      default: false,
    },
    digits: {
      type: Boolean,
      default: false,
    },
    maxLength: {
      type: [Number, Boolean],
      default: false,
    },
    maxValue: {
      type: [Number, Boolean],
      default: false,
    },
    mask: {
      type: [String, Number, Object],
    },
    formatted: {
      type: Boolean,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
  },
  components: { FormWrapper },
  directives: {
    NumericDirective,
    MaxValueDirective,
    DigitsDirective,
    MaxLengthDirective,
    FocusDirective,
  },
  setup(props, { emit }) {
    const elementRef = ref<any>(null);
    const currentValue = ref<string | null>(null);
    const iMask = ref<InputMask<any>>(null);

    const initMask = (maskOptions: any): void => {
      const el = elementRef.value.$el.querySelector(
        ".mask-input"
      ) as HTMLInputElement;
      iMask.value = IMask(el, maskOptions);

      iMask.value.on("accept", () => {
        if (props.formatted) {
          currentValue.value = iMask.value.value;
        } else {
          currentValue.value = iMask.value.unmaskedValue;
        }

        emit("update:modelValue", currentValue.value);
      });
    };

    const changeHandler = (event: any): void => {
      if (props.disabled) return;
      if (!props.mask) {
        currentValue.value = event.target.value;
        emit("update:modelValue", event.target.value);
      }
    };

    const setValues = (): void => {
      const newVal =
        props.modelValue === null || typeof props.modelValue === "undefined"
          ? ""
          : props.modelValue.toString();
      currentValue.value = newVal;
      if (props.mask) {
        iMask.value.value = newVal;
        iMask.value.updateValue();
      } else {
        const el = elementRef.value.$el.querySelector(
          ".mask-input"
        ) as HTMLInputElement;

        el.value = newVal;
      }
    };

    watch(
      () => props.modelValue,
      () => {
        setValues();
      }
    );
    onMounted(() => {
      if (props.mask) {
        initMask(props.mask);
      }
      if (props.modelValue) {
        setValues();
      }
    });

    onBeforeUnmount(() => {
      if (iMask.value) {
        iMask.value.destroy();
      }
    });

    return {
      changeHandler,
      props,
      elementRef,
    };
  },
});
</script>

<style scoped lang="scss">
.space-input {
  input {
    background-color: var(--background);
    border: 1px solid var(--border-color);
    padding: var(--form-side-padding);
    border-radius: var(--form-border-radius);
    color: var(--text-color);
    pointer-events: var(--pointer-events);
    height: var(--height);
    transition: var(--transition);
    width: 100%;

    &::placeholder {
      color: var(--form-placeholder-color);
    }

    &:focus {
      --border-color: var(--form-border-color-focus);
      box-shadow: var(--form-box-shadow);
    }
  }

  .input-icon {
    pointer-events: none;
    position: absolute;
    top: 50%;
    right: var(--form-side-padding);
    transform: translateY(-50%);
  }

  &.disabled {
    input {
      pointer-events: none;
    }
  }
}
</style>
