import { formatTimestamp } from '@/analyst/utilities'
import { Colors } from '@blueprintjs/colors'
import { Classes } from '@blueprintjs/core'
import { Cross, Tick } from '@blueprintjs/icons'
import { css, cx } from '@emotion/css'
import type { Exercise } from '@inject/graphql/fragment-types'
import useExercisesSubscription from '@inject/graphql/utils/useExercisesSubscription'
import type { FC } from 'react'
import { useMemo } from 'react'
import Table from '../Table'
import type { Column, Row } from '../Table/typing'
import ExerciseButtons from './ExerciseButtons'
import type { SelectingDetails } from './types'

const verticallyCentered = css`
  vertical-align: middle;
`

const hideOnSmallScreen = css`
  @media (max-width: 60rem) {
    display: none;
  }
`

const selected = css`
  background-color: ${Colors.BLUE3}1a !important;
  color: ${Colors.BLUE1};
  box-shadow: 0 0 0 1px ${Colors.BLUE3} !important;

  .${Classes.DARK} & {
    background-color: ${Colors.BLUE3}33 !important;
    color: ${Colors.BLUE5};
  }
`
const running = css`
  background-color: ${Colors.GREEN3}1a !important;
  color: ${Colors.GREEN1};
  box-shadow: 0 0 0 1px ${Colors.GREEN3} !important;

  .${Classes.DARK} & {
    background-color: ${Colors.GREEN3}33 !important;
    color: ${Colors.GREEN5};
  }
`

type ExerciseListProps = {
  filter?: (exercise: Exercise) => boolean
  isSelected?: (exercise: Exercise) => boolean
  className?: string
} & (
  | {
      type: 'selecting'
      details: (exercise: Exercise) => SelectingDetails
    }
  | { type: 'managing'; details?: never }
)

const ExerciseList: FC<ExerciseListProps> = ({
  filter,
  isSelected,
  details,
  type,
  className,
}) => {
  const [{ data, fetching: loading }] = useExercisesSubscription()

  const exercises = useMemo(
    () => (filter ? data?.exercises.filter(filter) : data?.exercises) || [],
    [data?.exercises, filter]
  )

  const columns: Column<Exercise>[] = useMemo(() => {
    const columns: Column<Exercise>[] = [
      {
        id: 'name',
        name: 'Name',
        style: { textAlign: 'left' },
        renderValue: exercise => exercise.name,
        className: verticallyCentered,
      },
      {
        id: 'definition',
        name: 'Definition',
        style: { textAlign: 'left' },
        renderValue: exercise =>
          exercise.definition?.name || exercise.definition?.id,
        className: verticallyCentered,
      },
      {
        id: 'teams',
        name: 'Teams',
        style: { textAlign: 'right', width: '8ch' },
        renderValue: exercise => exercise.teams.length,
        className: verticallyCentered,
      },
      {
        id: 'started-at',
        name: 'Started at',
        style: { textAlign: 'right', width: '20ch' },
        renderValue: exercise =>
          exercise.exerciseStart ? (
            formatTimestamp(exercise.exerciseStart)
          ) : (
            <Cross color={Colors.RED3} />
          ),
        className: cx(verticallyCentered, hideOnSmallScreen),
      },
      {
        id: 'finished',
        name: 'Finished',
        style: { textAlign: 'center', width: '10ch' },
        renderValue: exercise =>
          exercise.finished ? (
            <Tick color={Colors.GREEN3} />
          ) : (
            <Cross color={Colors.RED3} />
          ),
        className: cx(verticallyCentered, hideOnSmallScreen),
      },
      {
        id: 'actions',
        name: 'Actions',
        style: {
          width: type === 'managing' ? '20ch' : '14ch',
          textAlign: 'right',
        },
        renderValue: exercise => (
          <ExerciseButtons
            isSelected={isSelected?.(exercise)}
            exercise={exercise}
            {...(type === 'selecting'
              ? { type: 'selecting', details: details(exercise) }
              : {
                  type: 'managing',
                  runningAny: exercises.some(e => e.running),
                })}
          />
        ),
        className: verticallyCentered,
      },
    ]

    return columns
  }, [details, exercises, isSelected, type])

  const rows: Row<Exercise>[] = useMemo(() => {
    const rows: Row<Exercise>[] = exercises.map(exercise => ({
      id: exercise.id,
      value: exercise,
      className: cx({
        [selected]: isSelected?.(exercise),
        [running]: exercise.running,
      }),
    }))

    return rows
  }, [exercises, isSelected])

  return (
    <Table<Exercise>
      columns={columns}
      className={className}
      rows={rows}
      loading={loading}
      noDataStateProps={{
        title: 'No exercises',
        description: 'There are no exercises to display',
      }}
    />
  )
}

export default ExerciseList
