import {
  defineComponent, type Ref, ref, type PropType, watch, computed,
} from 'vue'
import ARKCheckbox from '../checkbox/ARKCheckbox.vue'
import LineLoader from '../line-loader/ARKLineLoader.vue'
import { copyTooltip, highlight } from '../../helpers'
import type { AllCheckState, SelectSlotParams } from './types'

const highlightText = (text: string, search?: string) => {
  if (!search) return text
  return highlight(text, search, '<span class="ark-ui-select-highlight">$&</span>')
}

export const DEFAULT_SHOW_ITEMS_COUNT = 6

export default function defineTemplate<T extends { id: string, name: string}>() {
  return defineComponent({
    name: 'SelectTemplate',
    props: {
      allCheckState: {
        type: [String, Boolean] as PropType<AllCheckState>,
        default: undefined,
      },
      clear: {
        type: Function as PropType<() => void>,
        required: true,
      },
      customHighlightSearch: {
        type: String,
        default: undefined,
      },
      disabled: {
        type: Boolean,
        required: true,
      },
      errors: {
        type: [Array, String] as PropType<string[] | string>,
        required: true,
      },

      /**
       * Опция копирования значения
       * Копирует только самое первое значение, это значит
       * что для мультиселектов всегда будет копироваться первое значение
       */
      isWithCopy: {
        type: Boolean,
        default: false,
      },

      isLoadingNext: {
        type: Boolean,
        required: true,
      },
      isLoadingPrev: {
        type: Boolean,
        required: true,
      },
      isOpened: {
        type: Boolean,
        required: true,
      },
      isSelected: {
        type: Function as PropType<(i: T) => boolean>,
        required: true,
      },
      items: {
        type: Array as PropType<T[]>,
        required: true,
      },
      itemSlot: {
        type: Function as PropType<(item: T, params: SelectSlotParams<T>) => JSX.Element>,
      },
      leftSlot: {
        type: Function as PropType<(item: T[]) => JSX.Element>,
        default: undefined,
      },
      modelValue: {
        type: Array as PropType<T[]>,
        required: true,
      },
      placeholder: {
        type: String,
      },
      resetable: {
        type: Boolean,
        required: true,
      },
      root: {
        type: Object as PropType<Ref<any>>,
        required: true,
      },
      search: {
        type: String,
      },
      setSearch: {
        type: Function as PropType<(s: string) => void>,
      },
      select: {
        type: Object as PropType<Ref<any>>,
        required: true,
      },
      size: {
        type: String as PropType<'M'|'S'>,
      },
      title: {
        type: String,
      },
      toggleAll: {
        type: Function as PropType<() => void>,
        default: undefined,
      },
      toggleItem: {
        type: Function as PropType<(i: T) => void>,
        required: true,
      },
      toggleOpened: {
        type: Function as PropType<() => void>,
        required: true,
      },
      topItems: {
        type: Array as PropType<T[]>,
        required: true,
      },
      triggerDown: {
        type: Object as PropType<Ref<any>>,
        required: true,
      },
      triggerUp: {
        type: Object as PropType<Ref<any>>,
        required: true,
      },
      tableIconType: {
        type: String,
      },
      isSingle: {
        type: Boolean,
        required: true,
      },
      appearance: {
        type: String as PropType<'filter'|'form'>,
        default: 'filter',
      },
      additionalItems: {
        type: Array as PropType<T[]>,
      },
      showItemsCount: {
        type: Number,
        default: DEFAULT_SHOW_ITEMS_COUNT,
      },
      description: {
        type: String,
        default: '',
      },
      isRequired: {
        type: Boolean,
        default: false,
      },
      hideSearch: {
        type: Boolean,
        default: false,
      },
      showDescriptionId: {
        type: Boolean,
        required: true,
      },
    },
    setup(props) {
      return () => {
        const tableIconType = props.tableIconType || 'search'
        const isFormAppearance = props.isSingle && props.appearance === 'form'

        const setSelector = () => `ark-ui-select
            ${props.size || 'M'}
            ${props.isOpened ? 'is-opened' : ''}
            ${props.disabled ? 'is-disabled' : ''}
            ${props.isWithCopy ? 'with-copy' : ''}
            ${props.errors.length ? 'with-errors' : ''}
            ${props.modelValue.length > 0 && isFormAppearance && props.resetable ? 'selected-resetable' : ''}`

        const toggleOpened = () => {
          if (props.disabled) return
          props.toggleOpened()
        }

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

          copyTooltip(props.modelValue[0]?.name, event.clientX + 10, event.clientY - 30)
        }

        const isFocus: Ref<HTMLInputElement | null> = ref(null)

        const inputSearchFocus = () => {
          if (isFocus.value) {
            isFocus.value.focus()
          }
        }

        watch(() => props.modelValue, (value) => {
          if (!value.length && !props.isOpened && props.setSearch) props.setSearch('')
        })

        const render = (item: T) => {
          if (props.itemSlot) {
            return props.itemSlot(item, {
              isSelected: props.isSelected,
              toggleItem: props.toggleItem,
            })
          }

          return (
            <div
              key={item.id}
              class={`ark-ui-select-item ${props.isSelected(item) ? 'is-selected' : ''}`}
              onClick={(e: Event) => { e.stopPropagation(); props.toggleItem(item) }}
            >
              { !props.isSingle && <ARKCheckbox modelValue={props.isSelected(item)} onValueChange={() => ({})}/> }
              <div>
                <span v-html={highlightText(item.name, props.customHighlightSearch ?? props.search) }/>
                <div class='ark-ui-select-item-description-id'>{props.showDescriptionId && item.id}</div>
              </div>
            </div>
          )
        }

        const isEmpty = computed(
          () => !props.isLoadingNext
            && !props.isLoadingPrev
            && ![props.items, props.topItems, props.additionalItems]
              .some((item) => item?.length),
        )

        return (
          <div onClick={copy}>
            { props.title && <div class="ark-ui-select-title">{ props.title }{ props.isRequired ? '*' : '' }</div> }
            <div
              class={setSelector()}
              ref={props.select}
              onClick={inputSearchFocus}
            >
              <div class="ark-ui-select-head" onClick={toggleOpened}>
                { props.modelValue.length > 0 && !isFormAppearance && (
                  <div class="ark-ui-select-head-chips">
                    <div class="ark-ui-select-head-value">{ props.modelValue.length }</div>
                    { !props.disabled && <div class="ark-ui-select-head-chips-clear" onClick={(e: Event) => { e.stopPropagation(); props.clear() }}/> }
                  </div>
                ) }
                { props.placeholder && !(isFormAppearance && props.modelValue.length > 0)
                  && !(props.modelValue.length > 0 && props.title) && (
                  <div class="ark-ui-select-head-placeholder">{ props.placeholder }</div>
                ) }
                { isFormAppearance && props.isSingle && props.modelValue.length > 0 && [
                  props.leftSlot?.(props.modelValue),
                  <div class="ark-ui-select-head-value">{ props.modelValue[0].name }</div>,
                  props.resetable && !props.disabled && <div class="ark-ui-select-head-clear" onClick={props.clear}/>,
                ] }
                <div class="ark-ui-select-head-controls">
                  { props.resetable && props.modelValue.length > 0 && <div class="ark-ui-select-clear"/> }
                  { !props.disabled && <div class={`ark-ui-select-arrow table-icon-type-${tableIconType}`}/>}
                </div>
              </div>
              <div class="ark-ui-select-dropdown" style={props.isOpened ? 'display: block;' : 'display: none;'}>
                { props.search !== undefined && !props.hideSearch && (

                  <div class="ark-ui-select-dropdown-search">
                    <input type="text"
                      value={props.search}
                      onInput={(v: Event) => { if (props.search !== undefined && props.setSearch) props.setSearch((v.target as HTMLFormElement).value) }}
                      placeholder="Поиск"
                      ref={isFocus}
                    />

                    <svg onClick={() => { if (props.search !== undefined && props.setSearch) props.setSearch('') }} width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                      {/* eslint-disable-next-line max-len */}
                      <path d="M4.14672 4.14645C4.34198 3.95118 4.65857 3.95118 4.85383 4.14645L8.00027 7.29289L11.1467 4.14645C11.342 3.95118 11.6586 3.95118 11.8538 4.14645C12.0491 4.34171 12.0491 4.65829 11.8538 4.85355L8.70738 8L11.8538 11.1464C12.0491 11.3417 12.0491 11.6583 11.8538 11.8536C11.6586 12.0488 11.342 12.0488 11.1467 11.8536L8.00027 8.70711L4.85383 11.8536C4.65857 12.0488 4.34198 12.0488 4.14672 11.8536C3.95146 11.6583 3.95146 11.3417 4.14672 11.1464L7.29317 8L4.14672 4.85355C3.95146 4.65829 3.95146 4.34171 4.14672 4.14645Z" fill="#A3A7B9"/>
                    </svg>
                  </div>

                ) }
                <div v-show={!isEmpty.value} class="ark-ui-select-items-list-wrapper">
                  <div class="ark-ui-select-loader-wrapper">
                    { props.isLoadingPrev && <LineLoader/> }
                  </div>
                  <div class="ark-ui-select-items-list" ref={props.root} style={`max-height: ${props.showItemsCount * 40}px`}>
                    <div class="ark-ui-pagination-trigger ark-ui-pagination-trigger-up" ref={props.triggerUp}/>

                    { props.allCheckState !== undefined && (
                      <div
                        class="ark-ui-select-item"
                        onClick={(e: Event) => { e.stopPropagation(); props.toggleAll?.() }}
                      >
                        <ARKCheckbox
                          modelValue={props.allCheckState === true}
                          class={props.allCheckState === 'multiple' ? 'ark-ui-select-multiple-checkbox' : ''}

                          onValueChange={() => ({})}
                        />

                        <div>
                          <span>Выбрать все</span>
                        </div>
                      </div>
                    ) }

                    { !props.isSingle && props.topItems.map((item) => render(item)) }
                    { props.additionalItems && props.additionalItems.filter((item) => props.isSingle || !props.topItems.find((i) => i.id === item.id)).map((item) => render(item)) }
                    { props.items.filter((item) => props.isSingle || !props.topItems.find((i) => i.id === item.id)).map((item) => render(item)) }
                    <div class="ark-ui-pagination-trigger ark-ui-pagination-trigger-down" ref={props.triggerDown}/>
                  </div>
                  <div class="ark-ui-select-loader-wrapper">
                    { props.isLoadingNext && <LineLoader/> }
                  </div>
                </div>
                <div v-show={isEmpty.value} class="ark-ui-select-empty-block">По вашему запросу ничего не найдено</div>
              </div>
            </div>

            { !props.disabled && (
              <>
                { typeof props.errors === 'string' && props.errors.length > 0
                  ? <div class="ark-ui-title ark-ui-select-error">{ props.errors }</div>
                  : Array.isArray(props.errors) && props.errors.length > 0
                    ? props.errors.map((error) => <div class="ark-ui-title ark-ui-select-error">{ error }</div>)
                    : props.description
                      ? <div class="ark-ui-title ark-ui-description">{ props.description }</div>
                      : '' }
              </>
            ) }
          </div>
        )
      }
    },
  })
}
