import useTools from '@/analyst/dataHooks/useTools'
import Filters from '@/components/Filters'
import { Checkbox, Collapse, Divider } from '@blueprintjs/core'
import { css } from '@emotion/css'
import useEmailsEnabled from '@inject/graphql/utils/useEmailsEnabled'
import type { Dispatch, FC } from 'react'
import { useCallback, useContext, useMemo, useState } from 'react'
import ActionLog from '../ActionLog'
import ExerciseContext from '../ExerciseContext'
import HelpIcon from '../HelpIcon'
import { ACTION_TYPES } from '../utilities'
import Detail from './Detail'
import FilterContext from './FilterContext'
import OverviewPlot from './OverviewPlot'
import type {
  selectedReducerActionProps,
  selectedReducerStateProps,
} from './selectedReducer'

const wrapper = css`
  flex: 1;
  overflow: auto;
  display: flex;
  flex-direction: column;
`

const options = css`
  display: flex;
  justify-content: space-between;
`

const plot = (teamsCount: number) => css`
  height: ${4 * teamsCount + 20}vh;
  overflow: hidden;
`

const footer = css`
  flex: 1;
  display: flex;
  overflow: auto;
  min-height: 20rem;

  @media (max-width: 80rem) {
    flex-direction: column;
  }
`

const footerElement = css`
  flex: 1;
  overflow: auto;
  min-height: 20rem;
  display: flex;
  max-height: 70vh;
`

const padded = css`
  /* the size of a checkbox is 16x16 px, the border line should be centered to it */
  margin-left: 7.5px;
  border-left: 1px solid lightgrey;
  padding-left: 9.5px;
`

const HELP_TEXT = `- to zoom, select an area in the graph using the left mouse button\
 and pull it over the part of the graph you would like to see
- clicking on an event will display details about it
- clicking on an event will highlight other similar events in the following fashion:
  - selecting an event of type ACTION will highlight events of the same action-type\
 (INJECT, COMMAND, NOTIFICATION)
    - selecting an event of type COMMAND will highlight only events of the same tool-type
  - selecting an event of type MILESTONE will highlight the same milestone in all teams
  - selecting an event of type EMAIL will highlight emails from the same email thread
  - selecting an INJECT LINE will highlight all inject lines
- clicking on the selected event will reset the selection`

interface OverviewProps {
  selectedState: selectedReducerStateProps
  selectedDispatch: Dispatch<selectedReducerActionProps>
}

const Overview: FC<OverviewProps> = ({ selectedState, selectedDispatch }) => {
  const { exercise, exerciseConfig } = useContext(ExerciseContext)
  const tools = useTools()
  const emailsEnabled = useEmailsEnabled({
    variables: { exerciseId: exercise.id },
  })

  // data types filtering
  const [displayActionLogs, setDisplayActionLogs] = useState(true)
  const [displayMilestones, setDisplayMilestones] = useState(true)
  const [displayEmailThreads, setDisplayEmailThreads] = useState(true)
  // action types filtering
  const [displayActionType, setDisplayActionType] = useState(
    ACTION_TYPES.map(() => true)
  )
  // emails filtering
  const [displayEmailsSent, setDisplayEmailsSent] = useState(true)
  const [displayEmailsReceived, setDisplayEmailsReceived] = useState(true)
  const [displayEmailsBetweenTeams, setDisplayEmailsBetweenTeams] =
    useState(true)
  // categories filtering
  const [displayCategories, setDisplayCategories] = useState(true)
  const [displayInjectCategories, setDisplayInjectCategories] = useState(true)
  const [displayEmailCategories, setDisplayEmailCategories] = useState(true)
  // tools filtering
  const [displayTool, setDisplayTool] = useState(tools.map(() => true))

  const filterContextValue = useMemo(
    () => ({
      displayActionLogs,
      displayMilestones,
      displayEmailThreads,
      displayActionType,
      displayEmailsSent,
      displayEmailsReceived,
      displayEmailsBetweenTeams,
      displayCategories,
      displayInjectCategories,
      displayEmailCategories,
      displayTool,
    }),
    [
      displayActionLogs,
      displayActionType,
      displayEmailThreads,
      displayEmailsReceived,
      displayEmailsSent,
      displayEmailsBetweenTeams,
      displayMilestones,
      displayCategories,
      displayInjectCategories,
      displayEmailCategories,
      displayTool,
    ]
  )

  const toolFilters = useMemo(
    () =>
      tools.map((tool, i) => (
        <Checkbox
          key={tool.id}
          label={tool.name}
          checked={displayTool[i]}
          onChange={() =>
            setDisplayTool(prev => [
              ...prev.slice(0, i),
              !prev[i],
              ...prev.slice(i + 1),
            ])
          }
        />
      )),
    [displayTool, tools]
  )

  const actionTypeFilters = useMemo(
    () =>
      ACTION_TYPES.map((actionType, i) => (
        <div key={actionType}>
          <Checkbox
            label={actionType}
            checked={displayActionType[i]}
            onChange={() =>
              setDisplayActionType(prev => [
                ...prev.slice(0, i),
                !prev[i],
                ...prev.slice(i + 1),
              ])
            }
          />
          {actionType === 'TOOL' && (
            <Collapse isOpen={displayActionType[i]}>
              <div className={padded}>{toolFilters}</div>
            </Collapse>
          )}
        </div>
      )),
    [displayActionType, toolFilters]
  )

  const emailFilters = useMemo(
    () => (
      <>
        <Checkbox
          label='received'
          checked={displayEmailsReceived}
          onChange={() => setDisplayEmailsReceived(prev => !prev)}
        />
        <Checkbox
          label='sent'
          checked={displayEmailsSent}
          onChange={() => setDisplayEmailsSent(prev => !prev)}
        />
        {exerciseConfig.emailBetweenTeams && (
          <Checkbox
            label='between teams'
            checked={displayEmailsBetweenTeams}
            onChange={() => setDisplayEmailsBetweenTeams(prev => !prev)}
          />
        )}
      </>
    ),
    [
      displayEmailsBetweenTeams,
      displayEmailsReceived,
      displayEmailsSent,
      exerciseConfig.emailBetweenTeams,
    ]
  )

  const categoryFilters = useMemo(
    () => (
      <>
        <Checkbox
          label='inject'
          checked={displayInjectCategories}
          onChange={() => setDisplayInjectCategories(prev => !prev)}
        />
        <Checkbox
          label='email'
          checked={displayEmailCategories}
          onChange={() => setDisplayEmailCategories(prev => !prev)}
        />
      </>
    ),
    [displayEmailCategories, displayInjectCategories]
  )

  const filters = useMemo(
    () => (
      <>
        <Checkbox
          label='actions'
          checked={displayActionLogs}
          onChange={() => setDisplayActionLogs(prev => !prev)}
        />
        <Collapse isOpen={displayActionLogs}>
          <div className={padded}>{actionTypeFilters}</div>
        </Collapse>
        <Checkbox
          label='milestones'
          checked={displayMilestones}
          onChange={() => setDisplayMilestones(prev => !prev)}
        />
        {emailsEnabled && (
          <>
            <Checkbox
              label='emails'
              checked={displayEmailThreads}
              onChange={() => setDisplayEmailThreads(prev => !prev)}
            />
            <Collapse isOpen={displayEmailThreads}>
              <div className={padded}>{emailFilters}</div>
            </Collapse>
          </>
        )}
        <Checkbox
          label='auto injects'
          checked={displayCategories}
          onChange={() => setDisplayCategories(prev => !prev)}
        />
        <Collapse isOpen={displayCategories}>
          <div className={padded}>{categoryFilters}</div>
        </Collapse>
      </>
    ),
    [
      actionTypeFilters,
      categoryFilters,
      displayActionLogs,
      displayCategories,
      displayEmailThreads,
      displayMilestones,
      emailFilters,
      emailsEnabled,
    ]
  )

  const setAllDisplayStates = useCallback((state: boolean) => {
    setDisplayActionLogs(state)
    setDisplayActionType(prev => prev.map(() => state))
    setDisplayTool(prev => prev.map(() => state))

    setDisplayMilestones(state)

    setDisplayEmailThreads(state)
    setDisplayEmailsReceived(state)
    setDisplayEmailsSent(state)
    setDisplayEmailsBetweenTeams(state)

    setDisplayCategories(state)
    setDisplayInjectCategories(state)
    setDisplayEmailCategories(state)
  }, [])

  return (
    <div className={wrapper}>
      <div className={options}>
        <HelpIcon text={HELP_TEXT} />
        <Filters
          content={filters}
          position='bottom-right'
          onSelectAll={() => {
            setAllDisplayStates(true)
          }}
          onDeselectAll={() => {
            setAllDisplayStates(false)
          }}
        />
      </div>

      <div className={plot(exercise.teams.length)}>
        <FilterContext.Provider value={filterContextValue}>
          <OverviewPlot
            selectedState={selectedState}
            selectedDispatch={selectedDispatch}
          />
        </FilterContext.Provider>
      </div>

      <Divider />

      <div className={footer}>
        <div className={footerElement}>
          <Detail
            selectedState={selectedState}
            displayInjectCategories={displayInjectCategories}
            displayEmailCategories={displayEmailCategories}
          />
        </div>
        <Divider />
        <div className={footerElement}>
          <ActionLog selectedDispatch={selectedDispatch} />
        </div>
      </div>
    </div>
  )
}

export default Overview
