<script lang="tsx">
import {
  computed,
  defineComponent,
  onBeforeMount,
  ref,
  watch,
  type PropType, type Ref,
} from 'vue'
import useClickOutside from '../../composables/use-click-outside'
import Button from '../buttons/DefaultButton.vue'
import { type FilterInterface } from './FilterInterfaces'
import { filterFabric, TextSearchFilter, type IFilter } from './Filters'

/**
 * Компонент вертикальных фильтров
 */
export default defineComponent({
  props: {
    /**
     * Состояние фильтр-бара (показать/скрыть)
     */
    isActive: {
      type: Boolean,
      default: true,
    },
    /**
     * Включение/выключение функционала умных фильтров
     */
    isSmartFilters: {
      type: Boolean,
      default: false,
    },
    /**
     * Заголовок фильтр-бара
     */
    label: {
      type: String,
      default: 'Фильтр',
    },
    /**
     * Массив фильтров класса FilterInterface
     */
    filters: {
      type: Array as PropType<FilterInterface[]>,
      required: true,
    },
    /**
     * Колбэк-функция закрытия фильтр-бара
     */
    onClose: {
      type: Function as PropType<() => void>,
      default: () => () => {
        // do nothing
      },
    },
    /**
     * Колбэк-функция применения фильтров с параметром типа ParamsType
     * @example { [code: string]: string | string[] }
     */
    onApply: {
      type: Function as PropType<(v?: Record<string, string|string[]>) => void>,
      default: () => () => {
        // do nothing
      },
    },
  },
  setup(props, context) {
    const filters: Ref<IFilter[]> = ref(props.filters.map((item) => filterFabric(item)))
    watch(() => props.filters, (newFilters) => {
      filters.value = newFilters.map((item) => filterFabric(item))
    })

    const textSearchFilter: TextSearchFilter | undefined = filters.value.find((item) => item instanceof TextSearchFilter) as TextSearchFilter
    const activeFiltersCount = ref(0)
    const root: Ref<HTMLDivElement | null> = ref(null)
    const body: Ref<HTMLDivElement | null> = ref(null)

    const params = computed(() => filters.value.reduce((acc, filter) => {
      Object.entries(filter.getQueryParams()).forEach(([k, v]) => {
        const val = Array.isArray(v) ? v.map((v) => String(v)) : String(v)

        acc[k] = acc[k]
          ? [
            ...(Array.isArray(acc[k]) ? acc[k] : [acc[k]]),
            ...(Array.isArray(val) ? val : [val]),
          ] as string[]
          : val
      })
      return acc
    }, {} as Record<string, string|string[]>))

    const isFilterSet = computed(() => Boolean(Object.keys(params.value).length) || (textSearchFilter && textSearchFilter.hasValues()))

    const updateActiveFiltersCount = () => {
      activeFiltersCount.value = filters.value.filter((f) => f.hasValues()).length
    }

    const onApply = () => {
      if (textSearchFilter) {
        textSearchFilter.save()
      }

      updateActiveFiltersCount()
      props.onApply(params.value)
      props.onClose()
    }

    const reset = () => {
      filters.value.forEach((filter) => {
        if (filter.removeValues) {
          filter.removeValues()
        }
      })

      updateActiveFiltersCount()
      props.onApply(params.value)
    }

    const setSmartFilters = () => {
      if (!props.isSmartFilters) return
      filters.value.forEach((filter) => {
        if (filter.setParams) filter.setParams(params.value)
      })
    }

    watch(params, setSmartFilters)

    onBeforeMount(() => {
      setSmartFilters()
      updateActiveFiltersCount()
    })

    useClickOutside(body, props.onClose, root)
    context.expose({ activeFiltersCount, reset })

    return () => (
      <div ref={root} class={`ark-ui-filterbar ${props.isActive ? 'is-active' : ''}`}>
        <div class="ark-ui-filterbar-slide">
          <div ref={body} class="ark-ui-filterbar-body-wrap">
            <div class="ark-ui-filterbar-header">
              <div class="ark-ui-filterbar-title">{props.label}</div>
              <div class="ark-ui-filterbar-close" onClick={props.onClose}></div>
            </div>
            <div class="ark-ui-filterbar-body">
              {filters.value.map((filter) => (
                <div class="ark-ui-filterbar-filter-item">{filter.render()}</div>
              ))}
            </div>
            {isFilterSet.value && (
              <div class="ark-ui-filterbar-footer">
                <Button
                  label='Сбросить фильтры'
                  type='secondary'
                  onClick={reset}
                />

                <Button
                  label='Применить'
                  onClick={onApply}
                />
              </div>
            )}
          </div>
        </div>
      </div>
    )
  },
})
</script>

<style lang="scss" scoped>
@import './styles.scss';
</style>
