import {
  computed,
  defineComponent, type PropType, ref, type Ref,
} from 'vue'
import useClickOutside from '../../composables/use-click-outside'
import defineTemplate from './template'
import type { AllCheckState, SelectSlotParams } from './types'

import './styles.scss'

export interface DefaultSelectMultipleExposed {
  isOpened: boolean
}

export const defineMultipleDefaultSelect = <T extends {id: string, name: string}> () => defineComponent({
  props: {
    /**
     * Функционал 'Выбрать все'
     */
    canCheckAll: {
      type: Boolean,
      default: false,
    },

    /**
       * Пользовательская установка значения **подсветки** \
       */
    customHighlightSearch: {
      type: Function as PropType<(value: string) => string>,
      default: undefined,
    },

    modelValue: {
      type: Array as PropType<T[]>,
      default: () => ([]),
    },
    title: {
      type: String,
    },
    placeholder: {
      type: String,
    },
    /**
     * Скрытие поиска
     */
    hideSearch: {
      type: Boolean,
      default: true,
    },
    onValueChange: {
      type: Function as PropType<(value: T[]) => void>,
      required: true,
    },
    items: {
      type: Array as PropType<T[]>,
      required: true,
    },
    itemSlot: {
      type: Function as PropType<(item: T, params: SelectSlotParams<T>) => JSX.Element>,
    },
    disabled: {
      type: Boolean,
      default: false,
    },
    resetable: {
      type: Boolean,
      default: true,
    },
    errors: {
      type: Array as PropType<string[]>,
      default: () => [],
    },
    size: {
      type: String as PropType<'M'|'S'>,
    },
    showItemsCount: {
      type: Number,
      default: 6,
    },
    showDescriptionId: {
      type: Boolean,
      default: false,
    },
  },

  setup(props, app) {
    const isOpened = ref(false)
    const search = ref('')
    const root = ref(null) as unknown as Ref<HTMLElement>
    const select = ref(null) as unknown as Ref<HTMLElement>
    const triggerDown = ref(null) as unknown as Ref<HTMLElement>
    const triggerUp = ref(null) as unknown as Ref<HTMLElement>

    const topItems: Ref<T[]> = ref([])
    const items = computed(() => {
      let result = props.items

      if (search.value) {
        result = props.items.filter(({ name }) => name.toLowerCase().includes(search.value.toLowerCase()))
      }

      return result
    })

    topItems.value = [...props.modelValue]
    const isSelected = (item: T) => Boolean(props.modelValue.find((i) => i.id === item.id))
    const allCheckState = computed<AllCheckState>(() => {
      if (!props.canCheckAll) return undefined

      if (props.modelValue.length) {
        if (items.value.length === props.modelValue.length) {
          return true
        }

        return 'multiple'
      }

      return false
    })

    const toggleAll = () => {
      if (allCheckState.value === undefined) return

      props.onValueChange(allCheckState.value === 'multiple' || !allCheckState.value ? items.value : [])
    }

    const toggleItem = (item: T) => {
      if (isSelected(item)) {
        const i = props.modelValue.find((i) => i.id === item.id)
        if (!i) return
        const newValue = [...props.modelValue]
        newValue.splice(newValue.indexOf(i), 1)

        if (props.onValueChange) props.onValueChange(newValue)
      } else if (props.onValueChange) props.onValueChange([...props.modelValue, item])
    }

    useClickOutside(select, () => {
      isOpened.value = false
      topItems.value = [...props.modelValue]
    })

    const clear = () => {
      if (props.onValueChange) props.onValueChange([])
    }

    app.expose({ isOpened })

    const toggleOpened = () => {
      isOpened.value = !isOpened.value
      topItems.value = [...props.modelValue]
    }

    const SelectTemplate = defineTemplate<T>()

    return (): JSX.Element => {
      const templateProps = {
        allCheckState: allCheckState.value,
        clear,
        disabled: props.disabled,
        errors: props.errors,
        isLoadingNext: false,
        isLoadingPrev: false,
        isOpened: isOpened.value,
        isSelected,
        items: items.value,
        itemSlot: props.itemSlot,
        modelValue: props.modelValue,
        placeholder: props.placeholder,
        resetable: props.resetable,
        root,
        select,
        title: props.title,
        toggleAll,
        toggleItem,
        toggleOpened,
        topItems: topItems.value,
        triggerUp,
        triggerDown,
        tableIconType: 'arrow',
        isSingle: false,
        size: props.size,
        showItemsCount: props.showItemsCount,
        showDescriptionId: props.showDescriptionId,
        hideSearch: props.hideSearch,
        search: search.value,
        setSearch: (s: string) => { search.value = s },
        customHighlightSearch: props.customHighlightSearch?.(search.value),
      }

      return <SelectTemplate {...templateProps}/>
    }
  },
})

export default defineMultipleDefaultSelect<{id: string, name: string}>()
