<template>
  <q-input
    v-model="dateTime"
    filled
    :readonly="readonly"
    :label="label"
    :placeholder="placeholder"
    :rules="customRules"
    :clearable="clearable"
    v-bind="attrs"
    @clear="dateTime = ''"
  >
    <template #append>
      <q-icon v-if="'date' || type == 'datetime'" name="mdi-calendar" class="cursor-pointer">
        <q-popup-proxy ref="qDateProxy" transition-show="scale" transition-hide="scale">
          <q-date v-model="date" mask="YYYY-MM-DD">
            <div class="row items-center justify-end">
              <q-btn v-close-popup label="Schließen" color="primary" flat />
            </div>
          </q-date>
        </q-popup-proxy>
      </q-icon>
      <q-icon
        v-if="type == 'time' || type == 'datetime'"
        name="mdi-clock-outline"
        class="cursor-pointer"
      >
        <q-popup-proxy ref="qTimeProxy" transition-show="scale" transition-hide="scale">
          <q-time v-model="time" mask="HH:mm">
            <div class="row items-center justify-end">
              <q-btn v-close-popup label="Schließen" color="primary" flat />
            </div>
          </q-time>
        </q-popup-proxy>
      </q-icon>
    </template>
  </q-input>
</template>

<script lang="ts">
import { computed, defineComponent, PropType } from 'vue';
import { date as q_date } from 'quasar';
import { stringIsDate, stringIsTime, stringIsDateTime, Validator } from 'src/utils/validators';

export default defineComponent({
  name: 'IsoDateInput',
  props: {
    modelValue: { type: Object as PropType<Date | undefined>, default: undefined },
    type: {
      type: String,
      default: 'date',
      validator: (value: string) => ['date', 'time', 'datetime'].indexOf(value) !== -1,
    },
    label: { type: String, default: 'Datum' },
    readonly: Boolean,
    rules: {
      type: Array as PropType<Validator[]>,
      default: () => [],
    },
  },
  emits: { 'update:modelValue': (date?: Date) => !!date || !date },
  setup(props, { emit, attrs }) {
    const customRules = computed(() => [
      props.type == 'date' ? stringIsDate : props.type == 'time' ? stringIsTime : stringIsDateTime,
      ...props.rules,
    ]);

    const clearable = computed(() =>
      customRules.value.every((r) => (<Validator>r)(undefined) === true)
    );

    const placeholder = computed(() => {
      switch (props.type) {
        case 'date':
          return 'YYYY-MM-DD';
        case 'time':
          return 'HH:mm';
        case 'datetime':
          return 'YYYY-MM-DD HH:mm';
      }
      throw 'Invalid type given';
    });

    const date = computed({
      get: () => q_date.formatDate(props.modelValue, 'YYYY-MM-DD'),
      set: (v: string) => {
        const d = modifyDate(v);
        if (d) emit('update:modelValue', d);
      },
    });

    const time = computed({
      get: () => q_date.formatDate(props.modelValue, 'HH:mm'),
      set: (v: string) => {
        const d = modifyTime(v);
        if (d) emit('update:modelValue', d);
      },
    });

    const dateTime = computed({
      get: () => (props.modelValue ? q_date.formatDate(props.modelValue, placeholder.value) : ''),
      set: (v: string) => {
        if (!v) emit('update:modelValue', undefined);
        switch (props.type) {
          case 'date':
            date.value = v;
            break;
          case 'time':
            time.value = v;
            break;
          case 'datetime':
            const split = v.split(' ').filter((c) => c !== '');
            if (split.length == 2) {
              const d = modifyTime(split[1], modifyDate(split[0]));
              if (d) emit('update:modelValue', d);
            }
            break;
        }
      },
    });

    function modifyTime(v: string, d: Date | undefined = props.modelValue) {
      if (d && /^\d\d:\d\d$/.test(v)) {
        const split = v.split(':');
        return q_date.adjustDate(d, { hours: +split[0], minutes: +split[1] });
      }
    }

    function modifyDate(v: string, d: Date | undefined = props.modelValue) {
      if (!d) d = new Date();
      if (/^\d{4}-\d\d-\d\d$/.test(v)) {
        const split = v.split('-');
        return q_date.adjustDate(d, {
          year: +split[0],
          month: +split[1],
          date: +split[2],
        });
      }
    }

    return {
      attrs,
      clearable,
      customRules,
      date,
      dateTime,
      placeholder,
      time,
    };
  },
});
</script>