import useMilestoneStates from '@/analyst/dataHooks/useMilestoneStates'
import useMilestones from '@/analyst/dataHooks/useMilestones'
import Filters from '@/components/Filters'
import SortableTable from '@/components/SortableTable'
import type { Column, Row, ValueType } from '@/components/SortableTable/typing'
import { Checkbox, Switch } from '@blueprintjs/core'
import type { Team } from '@inject/graphql/fragments/Team.generated'
import { useContext, useState } from 'react'
import ExerciseContext from '../ExerciseContext'
import useFormatTimestamp from '../useFormatTimestamp'
import { compareDates } from '../utilities'

interface MilestoneTableColumn extends Column {
  getValue: (team: Team) => ValueType
}

const MilestoneTable = () => {
  const { exercise } = useContext(ExerciseContext)
  const milestoneStates = useMilestoneStates()
  const milestones = useMilestones()
  const formatTimestamp = useFormatTimestamp()

  const formatValue = (value: ValueType) => {
    if (value === null) return 'not reached'
    if (typeof value === 'string') return value
    if (typeof value === 'number') {
      if (value === 0) return 'first'
      if (value === Infinity) return 'not reached'
      return `+ ${new Date(value).toISOString().substring(11, 19)}`
    }
    if (typeof value === 'boolean') return value ? 'yes' : 'no'
    return formatTimestamp(value.toISOString())
  }

  const [displayMilestone, setDisplayMilestone] = useState(
    milestones.map((_milestone, i) => i < 5)
  )

  const displayedMilestones = milestones.filter(
    (_milestone, i) => displayMilestone[i]
  )

  const [isTimeRelative, setIsTimeRelative] = useState(false)

  const milestoneFirstReachedTime: { [milestoneId: string]: number } = {}

  milestones.forEach(milestone => {
    const firstReachedState = milestoneStates
      .filter(milestoneState => milestoneState.milestone.id === milestone.id)
      .sort((a, b) => {
        if (!a.reached && !b.reached) return 0
        if (a.reached && !b.reached) return -1
        if (!a.reached && b.reached) return 1

        return compareDates(
          new Date(a.timestampReached || ''),
          new Date(b.timestampReached || '')
        )
      })
      .at(0)

    milestoneFirstReachedTime[milestone.id] = firstReachedState
      ? new Date(firstReachedState.timestampReached || '').getTime()
      : Infinity
  })

  const columns: MilestoneTableColumn[] = [
    {
      id: 'team',
      name: 'Team',
      style: { width: '20%' },
      getValue: (team: Team) => team.name,
    },
    ...displayedMilestones.map(milestone => ({
      id: milestone.id,
      name: milestone.name,
      style: { width: `${(100 - 20) / displayedMilestones.length}%` },
      getValue: (team: Team) => {
        const state = milestoneStates
          .filter(
            milestoneState =>
              milestoneState.milestone.id === milestone.id &&
              milestoneState.teamIds?.includes(team.id)
          )
          .at(0)

        if (isTimeRelative) {
          if (!state || !state.reached) return Infinity
          return (
            new Date(state.timestampReached || '').getTime() -
            milestoneFirstReachedTime[state.milestone.id]
          )
        }

        return state && state.reached
          ? new Date(state.timestampReached || '')
          : null
      },
    })),
  ]

  const rows: Row[] = exercise.teams.map(team => ({
    id: team.id,
    columns,
    values: columns.map(column => column.getValue(team)),
  }))

  const filters = (
    <>
      {milestones.map((milestone, i) => (
        <Checkbox
          key={milestone.id}
          label={milestone.name}
          checked={displayMilestone[i]}
          onChange={() =>
            setDisplayMilestone(prev => [
              ...prev.slice(0, i),
              !prev[i],
              ...prev.slice(i + 1),
            ])
          }
        />
      ))}
    </>
  )

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between' }}>
        <Filters
          content={filters}
          position='bottom-left'
          onSelectAll={() => setDisplayMilestone(prev => prev.map(() => true))}
          onDeselectAll={() =>
            setDisplayMilestone(prev => prev.map(() => false))
          }
        />
        <Switch
          label='Show time relative to the first team to reach the milestone'
          alignIndicator='right'
          checked={isTimeRelative}
          onChange={() => setIsTimeRelative(prev => !prev)}
        />
      </div>
      <div style={{ flex: 1 }}>
        <SortableTable
          columns={columns}
          rows={rows}
          formatValue={formatValue}
        />
      </div>
    </div>
  )
}

export default MilestoneTable
