import { h, createContext, type FunctionComponent } from 'preact'
import { useCallback, useContext } from 'preact/hooks'
import cn from 'classnames'
import { camelCase } from 'lowline'

import s from './table.module.scss'

export type onSortByFunction = (column: string | null) => void | Promise<void>

const TableContext = createContext<{ sortBy: (e: Event) => void; sortedBy: [string, boolean?] } | null>(null)

type TableProps = {
  className?: string
  defaultSort?: string
  onSortBy?: onSortByFunction
  sortedBy?: string
}

export const Table: FunctionComponent<TableProps> = ({
  children,
  className,
  defaultSort = 'id',
  onSortBy,
  sortedBy,
}) => {
  const sortBy = useCallback(
    (e: Event) => {
      e.preventDefault()

      // @ts-ignore
      const { sortBy } = e.currentTarget.dataset

      const newSortBy = sortBy === sortedBy ? '-' + sortBy : sortBy

      onSortBy?.(newSortBy === defaultSort ? null : newSortBy)
    },
    [onSortBy, sortedBy],
  )

  sortedBy ??= defaultSort

  const desc = sortedBy.startsWith('-')

  return (
    <TableContext.Provider
      value={{
        sortBy,
        sortedBy: [desc ? sortedBy.slice(1) : sortedBy, desc],
      }}
    >
      <table className={cn(s.table, className)}>{children}</table>
    </TableContext.Provider>
  )
}

export const Td: FunctionComponent<{
  className?: string
  buttons?: boolean
  minimize?: boolean
}> = ({ children, className, buttons, minimize }) => (
  <td className={cn(className, buttons && s.buttons, minimize && s.minimize)}>
    {buttons ? <div>{children}</div> : children}
  </td>
)

export const Th: FunctionComponent<{
  children: string
  className?: string
  scope?: 'col' | 'row' | 'colgroup' | 'rowgroup'
  sort?: string | boolean
}> = ({ children, className, scope, sort }) => {
  const column = typeof sort === 'string' ? sort : camelCase(children)

  const { sortBy, sortedBy } = useContext(TableContext)!

  return (
    <th className={cn(s.th, className)} scope={scope}>
      {sort ? (
        <a
          href='javascript:;'
          onClick={sortBy}
          data-sort-by={column}
          className={cn({ [s.current]: column === sortedBy[0], [s.desc]: column === sortedBy[0] && sortedBy[1] })}
        >
          {children}
          <div className={s.arrows} />
        </a>
      ) : (
        children
      )}
    </th>
  )
}
