import useMilestoneStates from '@/analyst/dataHooks/useMilestoneStates'
import useMilestones from '@/analyst/dataHooks/useMilestones'
import Filters from '@/components/Filters'
import Table from '@/components/Table'
import type { Column, Row } from '@/components/Table/typing'
import { stringSortingFunction } from '@/components/Table/utils'
import { Checkbox, Switch } from '@blueprintjs/core'
import type { Team } from '@inject/graphql/fragment-types'
import { useContext, useState } from 'react'
import ExerciseContext from '../ExerciseContext'
import useFormatTimestamp from '../useFormatTimestamp'
import { compareDates } from '../utilities'

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

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

  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: Column<Team>[] = [
    {
      id: 'team',
      name: 'Team',
      style: { width: '20%' },
      renderValue: (team: Team) => team.name,
      sortingFunction: (a, b) => stringSortingFunction(a.name, b.name),
    },
    ...milestones.map(milestone => ({
      id: milestone.id,
      name: milestone.displayName,
      display: displayMilestone[milestones.indexOf(milestone)],
      renderValue: (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 'not reached'
          const value =
            new Date(state.timestampReached || '').getTime() -
            milestoneFirstReachedTime[milestone.id]
          if (value === 0) return 'first'
          return `+ ${new Date(value).toISOString().substring(11, 19)}`
        }

        const value = state && state.reached ? state.timestampReached : null
        if (value === null) return 'not reached'
        return formatTimestamp(value)
      },
      sortingFunction: (a: Team, b: Team) => {
        const stateA = milestoneStates
          .filter(
            milestoneState =>
              milestoneState.milestone.id === milestone.id &&
              milestoneState.teamIds?.includes(a.id)
          )
          .at(0)

        const stateB = milestoneStates
          .filter(
            milestoneState =>
              milestoneState.milestone.id === milestone.id &&
              milestoneState.teamIds?.includes(b.id)
          )
          .at(0)

        if (!stateA || !stateA.reached) return 1
        if (!stateB || !stateB.reached) return -1

        return (
          new Date(stateA.timestampReached || '').getTime() -
          new Date(stateB.timestampReached || '').getTime()
        )
      },
    })),
  ]

  const rows: Row<Team>[] = exercise.teams.map(team => ({
    id: team.id,
    value: team,
  }))

  const filters = (
    <>
      {milestones.map((milestone, i) => (
        <Checkbox
          key={milestone.id}
          label={milestone.displayName}
          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 }}>
        <Table<Team> columns={columns} rows={rows} />
      </div>
    </div>
  )
}

export default MilestoneTable
