<template>
  <div>
    <q-input
      ref="input"
      v-model="displayDate"
      class="x--small-input x-datetime"
      :readonly="readonly"
      :mask="inputMask"
      filled
      dense
      borderless
      v-bind="$attrs"
      :rules="rules"
      v-on="$listeners"
    >
      <template #append>
        <q-icon v-if="isDateView" name="event" class="x-control-button">
          <q-popup-proxy
            ref="qDateProxy"
            transition-show="scale"
            transition-hide="scale"
            :breakpoint="700"
          >
            <div style="display: flex">
              <q-date
                v-model="displayDate"
                :mask="mask"
                :minimal="minimal"
                @input="closePopup"
              />
              <!-- <q-time v-model="displayDate" :mask="mask" format24h /> -->
            </div>
          </q-popup-proxy>
        </q-icon>
      </template>
    </q-input>
  </div>
</template>

<style lang="sass" scoped>
.x-control-button
  background: rgba(210, 210, 216, 0.9)
  border-radius: 4px
  cursor: pointer
  position: absolute
  right: 8px
  opacity: 0
  transition: opacity .2s
  z-index: 88
  pointer-events: none

.x-datetime:not(.q-field--disabled):hover .x-control-button
  opacity: 1
  pointer-events: auto


.q-menu.scroll
  overflow: hidden !important
</style>

<script lang="ts">
import Component from 'vue-class-component';
import Vue from 'vue';
import isEmpty from 'lodash/isEmpty';
import isDate from 'lodash/isDate';
import {
  convertDateFormat,
  isCorrectDate,
  parseDateFromString,
} from '@/utils/format-date';
import { QPopupProxy, QInput } from 'quasar';
import { DateFormat } from '@constants/utils/format-date';
import { Prop, Watch } from 'vue-property-decorator';

export enum FormGeneratorDateType {
  none = 'none',
  time = 'time',
  date = 'date',
  datetime = 'datetime',
}

function isEmptyAndNotDate(value: unknown) {
  return !isDate(value) && isEmpty(value);
}

@Component
export default class ArmDatepicker extends Vue {
  @Prop({ default: 'date' }) type: FormGeneratorDateType;
  @Prop() format: string;
  @Prop({ type: Boolean }) readonlyAsText: boolean;
  @Prop({ type: Boolean }) endOfDay: boolean;
  @Prop({ type: Boolean, default: false }) minimal: boolean;
  @Prop({ type: Boolean, default: false }) focus: boolean;

  private get rules() {
    return [() => (this.required ? !this.hasError || this.errorMessage : true)];
  }

  /**
   * Value for data from parent component
   */
  @Prop() private value: string;

  @Prop({ type: Boolean, default: false }) private readonly: boolean;
  @Prop({ type: Boolean, default: false }) private required: boolean;

  @Prop({ type: Boolean, default: false }) private noLabels: boolean;

  @Prop({ type: String, default: '' }) private label: string;

  @Prop() private color: boolean;

  @Prop() readonly validationError: boolean;
  @Prop() readonly validationMessage: string;

  private internalErrorMessage = this.$t(
    'base.validation.required.date'
  ) as string;

  /**
   * Date from input field passed manually
   */
  public displayDate: string | null = null;

  /**
   * Converts date to ISO format to display on datepicker modal window
   */

  @Watch('displayDate')
  onManualInput(displayDate: any, oldVal: any) {
    // if (!oldVal) {
    //   return;
    // }
    if (!oldVal && !displayDate) {
      // not initialized yet
      return;
    }

    // no check for empty value
    if (!displayDate && !this.required) {
      this.$emit('input', '');

      return;
    }

    if (displayDate?.length < 10) {
      return;
    }

    if (oldVal && isEmptyAndNotDate(displayDate) && this.required) {
      this.internalErrorMessage = this.$t(
        'base.validation.required.date'
      ) as string;

      return;
    }

    const formatted = parseDateFromString(displayDate, this.pattern);
    const isError = !isCorrectDate(formatted);
    const isoString = convertDateFormat(formatted, '', DateFormat.backend);
    const formattedToEndOfDay = parseDateFromString(displayDate  + ' 23:59:59.999', 'DD.MM.YYYY HH:mm:ss.SSS');

    this.internalErrorMessage = isError
      ? (this.$t('base.validation.invalid.date') as string)
      : '';

    if (!isError) {
      this.$emit(
        'input',
        this.format 
        ? convertDateFormat(this.endOfDay ? formattedToEndOfDay : formatted, '', this.format)
        : isoString
      );
    }
  }

  @Watch('value', { immediate: true })
  private onValueChange() {
    this.syncDisplayDate();
  }

  private mounted() {
    this.syncDisplayDate();
    if (this.focus) {
      (this.$refs.input as QInput)?.focus();
      (this.$refs.input as QInput)?.blur();
    }
  }

  get internalHasError(): boolean {
    return this.internalErrorMessage !== '';
  }

  syncDisplayDate() {
    this.displayDate = this.getDisplayDate();
  }

  get mask() {
    return this.pattern;
  }

  get inputMask() {
    return this.mask?.replace(/[a-z]/gi, '#');
  }

  get pattern() {
    switch (this.type) {
      case FormGeneratorDateType.datetime:
        return DateFormat.datetime;
      case FormGeneratorDateType.date:
        return DateFormat.date;
      case FormGeneratorDateType.time:
        return DateFormat.time;
    }
    return DateFormat.time;
  }

  get isDateView(): boolean {
    return [
      FormGeneratorDateType.date,
      FormGeneratorDateType.datetime,
    ].includes(this.type);
  }

  get isTimeView(): boolean {
    return [
      FormGeneratorDateType.time,
      FormGeneratorDateType.datetime,
    ].includes(this.type);
  }

  getDisplayDate() {
    if (this.isDateView) {
      if (isEmptyAndNotDate(this.value)) {
        return '';
      }
      let date =
        this.format && typeof this.value === 'string'
          ? parseDateFromString(this.value, this.format)
          : parseDateFromString(this.value, this.pattern);

      if (!this.format && !isCorrectDate(date)) {
        date = parseDateFromString(this.value, DateFormat.backend);
      }

      return isCorrectDate(date)
        ? convertDateFormat(date, '', this.pattern)
        : this.value;
    }

    return this.value;
  }

  get hasError(): boolean {
    if (this.validationError !== void 0) {
      return this.validationError;
    }

    return this.internalHasError;
  }

  get errorMessage(): string {
    if (this.validationMessage !== void 0) {
      return this.validationMessage;
    }

    return this.internalErrorMessage;
  }

  private closePopup() {
    (this.$refs.qDateProxy as QPopupProxy).hide();
  }
}
</script>
