import { computed, defineComponent, h, PropType, ref, watch } from 'vue'

import { CFormInput } from '../form/'
import { CTableFoot, CTableHead, CTableHeaderCell, CTableRow } from '../table/'

import {
  getColumnKey,
  getColumnLabel,
  getColumnGroups,
  getColumns,
  getColumnSorterState,
  getColumnValues,
  getTableHeaderCellProps,
  getTableHeaderCellStyles,
} from './utils'

import type { Column, ColumnFilter, ColumnFilterValue, Item, Sorter, SorterValue } from './types'

const CSmartTableHead = defineComponent({
  name: 'CSmartTableHead',
  props: {
    as: {
      type: String,
      default: 'head',
    },
    columnFilter: [Boolean, Object] as PropType<boolean | ColumnFilter>,
    columnFilterValue: Object as PropType<ColumnFilterValue>,
    columnSorter: [Boolean, Object] as PropType<boolean | Sorter>,
    columns: {
      type: Array as PropType<(Column | string)[]>,
      default: () => [],
    },
    items: {
      type: Array as PropType<Item[]>,
      default: () => [],
    },
    scopedSlots: Object,
    selectable: Boolean,
    selectAll: [Boolean, Object] as PropType<boolean | { external?: boolean }>,
    selectedAll: [Boolean, String],
    showGroups: {
      type: Boolean,
      default: true,
    },
    sorterState: {
      type: Array as PropType<SorterValue[]>,
      default: () => [],
    },
  },
  emits: ['customFilterChange', 'filterInput', 'filterChange', 'selectAllChecked', 'sortClick'],
  setup(props, { slots, emit }) {
    const selectedAll = ref()
    const seleactAllCheckboxRef = ref<HTMLInputElement>()
    const columns = computed(() => getColumns(props.columns))
    const groups = computed(() => getColumnGroups(props.columns))

    watch(
      () => props.selectedAll,
      () => {
        selectedAll.value = props.selectedAll
      },
      {
        immediate: true,
      }
    )

    watch([selectedAll, seleactAllCheckboxRef], () => {
      if (seleactAllCheckboxRef.value && props.selectedAll === true) {
        seleactAllCheckboxRef.value.indeterminate = false
        seleactAllCheckboxRef.value.checked = true
        return
      }

      if (seleactAllCheckboxRef.value && props.selectedAll === 'indeterminate') {
        seleactAllCheckboxRef.value.checked = false
        seleactAllCheckboxRef.value.indeterminate = true
        return
      }

      if (seleactAllCheckboxRef.value) {
        seleactAllCheckboxRef.value.indeterminate = false
        seleactAllCheckboxRef.value.checked = false
      }
    })

    const columnSorterIcon = (column: Column | string) => {
      if (getColumnSorterState(getColumnKey(column), props.sorterState) === 0) {
        return h(
          'span',
          { class: 'opacity-25 float-end me-1' },
          slots.sortingIcon && slots.sortingIcon()
        )
      }

      if (getColumnSorterState(getColumnKey(column), props.sorterState) === 'asc') {
        return h(
          'span',
          { class: 'float-end me-1' },
          slots.sortingIconAscending && slots.sortingIconAscending()
        )
      }

      if (getColumnSorterState(getColumnKey(column), props.sorterState) === 'desc') {
        return h(
          'span',
          { class: 'float-end me-1' },
          slots.sortingIconDescending && slots.sortingIconDescending()
        )
      }

      return
    }

    return () =>
      h(
        props.as === 'head' ? CTableHead : CTableFoot,
        {},
        {
          default: () => [
            props.showGroups &&
              groups.value &&
              groups.value.length > 0 &&
              groups.value.map((row) => [
                h(CTableRow, {}, () => [
                  props.selectable && h(CTableHeaderCell),
                  row.map((cell) =>
                    h(
                      CTableHeaderCell,
                      {
                        colspan: cell.colspan,
                        ...getTableHeaderCellProps(cell),
                      },
                      () => cell.label
                    )
                  ),
                ]),
              ]),
            h(
              CTableRow,
              {},
              {
                default: () => [
                  props.selectable &&
                    h(
                      CTableHeaderCell,
                      {},
                      () =>
                        props.selectAll &&
                        h('input', {
                          class: 'form-check-input',
                          type: 'checkbox',
                          ref: seleactAllCheckboxRef,
                          onClick: () => {
                            selectedAll.value = selectedAll.value !== 'reset' ? 'reset' : ''
                            emit('selectAllChecked')
                          },
                        })
                    ),
                  columns.value.map((column, index: number) => {
                    const isSortable =
                      props.columnSorter &&
                      (typeof column === 'object'
                        ? column.sorter === undefined
                          ? true
                          : column.sorter
                        : true)
                    return h(
                      CTableHeaderCell,
                      {
                        ...getTableHeaderCellProps(column),
                        style: getTableHeaderCellStyles(column, props.columnSorter),
                        ...(isSortable && {
                          tabindex: 0,
                          onClick: () => emit('sortClick', getColumnKey(column), index),
                          onKeydown: (event: KeyboardEvent) => {
                            if (event.key === 'Enter') {
                              emit('sortClick', getColumnKey(column), index)
                            }

                            if (event.key === 'ArrowUp') {
                              event.preventDefault()
                              emit('sortClick', getColumnKey(column), index, 'asc')
                            }

                            if (event.key === 'ArrowDown') {
                              event.preventDefault()
                              emit('sortClick', getColumnKey(column), index, 'desc')
                            }
                          },
                        }),
                      },
                      {
                        default: () => [
                          h(
                            'div',
                            {
                              class: 'd-inline',
                            },
                            props.scopedSlots &&
                              props.scopedSlots[getColumnKey(column)] &&
                              typeof props.scopedSlots[`${getColumnKey(column)}Header`] === 'function'
                              ? props.scopedSlots[`${getColumnKey(column)}Header`]({
                                  label: getColumnLabel(column),
                                })
                              : getColumnLabel(column)
                          ),
                          props.columnSorter &&
                            (typeof column === 'object'
                              ? typeof column.sorter === 'undefined'
                                ? true
                                : column.sorter
                              : true) &&
                            columnSorterIcon(column),
                        ],
                      }
                    )
                  }),
                ],
              }
            ),
            props.columnFilter &&
              h(
                CTableRow,
                {},
                {
                  default: () => [
                    props.selectable && h(CTableHeaderCell),
                    columns.value.map((column: Column | string) => {
                      return h(
                        CTableHeaderCell,
                        {
                          ...getTableHeaderCellProps(column),
                        },
                        {
                          default: () =>
                            (
                              typeof column === 'object'
                                ? column.filter === undefined
                                  ? true
                                  : column.filter
                                : true
                            )
                              ? typeof column !== 'string' && typeof column.filter === 'function'
                                ? column.filter(
                                    getColumnValues(props.items, getColumnKey(column)),
                                    (value: any) => {
                                      emit('customFilterChange', getColumnKey(column), value)
                                    }
                                  )
                                : h(CFormInput, {
                                    size: 'sm',
                                    onInput: (event: Event) => {
                                      emit(
                                        'filterInput',
                                        getColumnKey(column),
                                        (event.target as HTMLInputElement).value
                                      )
                                    },
                                    onChange: (event: Event) => {
                                      emit(
                                        'filterChange',
                                        getColumnKey(column),
                                        (event.target as HTMLInputElement).value
                                      )
                                    },
                                    'aria-label': `column name: '${getColumnLabel(
                                      column
                                    )}' filter input`,
                                    ...(props.columnFilterValue &&
                                      props.columnFilterValue[getColumnKey(column)] && {
                                        value: props.columnFilterValue[getColumnKey(column)],
                                      }),
                                  })
                              : '',
                        }
                      )
                    }),
                  ],
                }
              ),
          ],
        }
      )
  },
})

export { CSmartTableHead }
