import { type Moment } from 'moment'
import {
  defineComponent, type PropType, ref, type Ref, type ComputedRef, computed,
  Teleport,
} from 'vue'
import Calendar from '../calendars/calendar'
import useClickOutside from '../../../composables/use-click-outside'
import { copyTooltip } from '../../../helpers'
import './calendar-input.sass'

/**
 * Компонент представляет собой ввод даты (с календарем).
 * Обладает различными настраиваемыми свойствами: возможность отключения, очистки, отображения текста и пр.
 * <p>
 *   <a href="https://www.figma.com/file/Q4Z4CnFx4i0qhD5fbgnPpf/%F0%9F%92%BB-%D0%94%D0%B8%D0%B7%D0%B0%D0%B9%D0%BD-%D1%81%D0%B8%D1%81%D1%82%D0%B5%D0%BC%D0%B0-ARK-SPACE?type=design&node-id=6204%3A150335&mode=dev" target="_blank">Дизайн</a>
 * </p>
 */
export default defineComponent({
  props: {
    /**
     *  Отключен ли ввод.
     */
    isDisabled: {
      type: Boolean,
      default: false,
    },
    /**
     * Можно ли очистить значение поля ввода.
     * Добавляет кнопку "крестик".
     */
    isClearable: {
      type: Boolean,
      default: false,
    },
    /**
     * Отображается ли лейбл (название) над инпутом.
     */
    isShowLabel: {
      type: Boolean,
      default: true,
    },
    /**
     * Определяет, используется ли компонент внутри таблицы.
     */
    isForTable: {
      type: Boolean,
      default: false,
    },
    /**
     * Опция копирования значения
     */
    isWithCopy: {
      type: Boolean,
      default: false,
    },
    /**
     * Использовать `vue`шный `Teleport` для показа попапа календаря
     */
    isUseTeleport: {
      type: Boolean,
      default: false,
    },
    /**
     * Название поля, расположено над инпутом.
     */
    label: {
      type: String,
      default: '',
    },
    /**
     * Значение, отображаемое в поле ввода, если оно пусто.
     */
    placeholder: {
      type: String,
      default: '__.__.____',
    },
    /**
     * Массив строк с ошибками.
     */
    errors: {
      type: Array as PropType<string[]>,
      default: () => [],
    },
    /**
     * Строка, представляющая формат даты.
     */
    format: {
      type: String,
      default: 'DD.MM.YYYY',
    },
    /**
     * Значение поля ввода.
     */
    modelValue: {
      type: [Object, null] as PropType<Moment | null>,
      required: true,
    },
    /**
     * Определяет, является ли поле обязательным для заполнения.
     */
    isRequired: {
      type: Boolean,
      default: false,
    },
    /**
     * Описание поля ввода. Отображается под инпутом.
     */
    description: {
      type: String,
      default: '',
    },
    /**
     * Функция обратного вызова при изменении значения.
     */
    onValueChange: {
      type: Function as PropType<(v: Moment | null) => void>,
      required: true,
    },
  },

  setup(props) {
    const isShowCalendar: Ref<boolean> = ref(false)
    const formattedValue: ComputedRef<string> = computed(() => props.modelValue?.format(props.format) ?? '')
    const popupStyle = ref({})

    const calendarElement: Ref<HTMLElement | null> = ref(null)
    const inputElement: Ref<HTMLElement | null> = ref(null)

    const setDate = (val: Moment | null) => {
      if (props.onValueChange) {
        props.onValueChange(val)
      }
    }

    const copy = (event: MouseEvent) => {
      if (!props.isWithCopy) return

      copyTooltip(formattedValue.value, event.clientX + 10, event.clientY - 30)
    }

    const onClick = (event: MouseEvent) => {
      copy(event)

      if (props.isDisabled && !isShowCalendar.value) return
      isShowCalendar.value = !isShowCalendar.value

      if (props.isUseTeleport && inputElement.value) {
        const rect = inputElement.value.getBoundingClientRect()
        popupStyle.value = {
          top: `${rect.bottom + window.scrollY}px`,
          left: `${rect.left + window.scrollX}px`,
        }
      }
    }

    useClickOutside(calendarElement, () => { isShowCalendar.value = false })

    const renderPopupElement = () => (
      <div class="ark-ui-calendar-input-calendar-container" style={popupStyle.value}>

        { props.isForTable && (
          <div class="ark-ui-calendar-input-calendar-container-inputs">
            <input type="text" value={formattedValue.value} placeholder="__.__.____" disabled />

            { props.modelValue && (
              <div onClick={() => setDate(null)} class="ark-ui-calendar-input-calendar-container-clear" />
            ) }

          </div>
        ) }

        <Calendar date={props.modelValue} onSetDate={setDate} />
      </div>
    )

    return () => (
      <div
        ref={calendarElement}
        class={`ark-ui-calendar-input ${props.isDisabled ? 'disabled' : ''} ${props.isWithCopy ? 'withCopy' : ''} ${props.errors.length ? 'invalid' : ''}`}
        onClick={onClick}
      >

        { props.label && props.isShowLabel && (
          <div class="ark-ui-calendar-input-label">{ props.label }{ props.isRequired ? '*' : '' }</div>
        ) }

        { !props.isDisabled && (
          <div class='ark-ui-calendar-input-overlap' />
        ) }

        <div class={`ark-ui-calendar-input-wrap ${isShowCalendar.value ? 'is-opened' : ''} ${props.modelValue ? 'is-selected' : ''}`}>

          { props.isForTable && (
            <div class='ark-ui-calendar-input-element'>{ props.placeholder }</div>
          ) }

          { !props.isForTable && (
            <input
              ref={inputElement}
              type='text'
              class='ark-ui-calendar-input-element'
              readonly={props.isDisabled}
              value={formattedValue.value}
              placeholder={props.placeholder}
            />
          ) }

          { props.isClearable && props.modelValue
            ? <div onClick={() => setDate(null)} class='ark-ui-calendar-input-icon ark-ui-calendar-input-icon-clear' />
            : <div class='ark-ui-calendar-input-icon ark-ui-calendar-input-icon-calendar' />
          }
        </div>

        { !props.isDisabled && props.errors && props.errors.length > 0
          ? props.errors.map((error) => <div class='ark-ui-calendar-input-error'>{error}</div>)
          : props.description
            ? <div class="ark-ui-title ark-ui-description">{props.description}</div>
            : '' }

        { isShowCalendar.value && (<>
          {props.isUseTeleport ? (
            <Teleport to="body">
              {renderPopupElement()}
            </Teleport>
          ) : renderPopupElement()}
        </>) }
      </div>
    )
  },
})
