import {
  relativeTime,
  useRelativeTime,
} from '@/clientsettings/vars/relativeTime'
import ExitButton from '@/components/ExitButton'
import type { LinkType } from '@/components/LinkButton'
import LinkButton from '@/components/LinkButton'
import type { Section } from '@/components/Sidebar'
import Sidebar from '@/components/Sidebar'
import useHideButton from '@/components/Sidebar/useHideButton'
import Status from '@/components/Status'
import type { IconName } from '@blueprintjs/core'
import { Button } from '@blueprintjs/core'
import { css } from '@emotion/css'
import useEmailsEnabled from '@inject/graphql/utils/useEmailsEnabled'
import useToolsEnabled from '@inject/graphql/utils/useToolsEnabled'
import CenteredSpinner from '@inject/shared/components/CenteredSpinner'
import type { FC, PropsWithChildren } from 'react'
import { Suspense, useContext, useMemo } from 'react'
import { generatePath, matchPath, useLocation } from 'react-router-dom'
import { useParams } from '../../router'
import ExerciseContext from '../ExerciseContext'
import ExerciseSelector from '../ExerciseSelector'
import SVGContext from '../SVGContext'
import { EmailSelection } from '../utilities'

const limitedHeight = css`
  max-height: 70vh;
  overflow-y: auto;
`

type PathType = {
  link: LinkType
  icon: IconName
  text: string
}

const NavigationBar: FC<PropsWithChildren> = ({ children }) => {
  const { pathname } = useLocation()
  const { exerciseId } = useParams('/analyst/:exerciseId')

  const emailsEnabled = useEmailsEnabled({
    variables: { exerciseId },
    skip: !exerciseId,
  })
  const toolsEnabled = useToolsEnabled({
    variables: { exerciseId },
    skip: !exerciseId,
  })
  const { hide, node: hideButton } = useHideButton()

  const { exercise } = useContext(ExerciseContext)

  const relativeTimeVar = useRelativeTime()

  const TimeSwitch = () => (
    <Button
      icon='time'
      alignText='left'
      fill
      minimal
      text={!hide && `Use ${relativeTimeVar ? 'absolute' : 'relative'} time`}
      onClick={() => relativeTime(!relativeTimeVar)}
      style={{ whiteSpace: 'nowrap' }}
    />
  )

  const paths: PathType[] = []
  paths.push({
    link: ['/analyst/:exerciseId', { params: { exerciseId } }],
    icon: 'control',
    text: 'Dashboard',
  })
  paths.push({
    link: ['/analyst/:exerciseId/milestones', { params: { exerciseId } }],
    icon: 'flag',
    text: 'Milestones',
  })
  if (emailsEnabled) {
    paths.push({
      link: [
        '/analyst/:exerciseId/emails/:tab',
        { params: { exerciseId, tab: EmailSelection.SENT } },
      ],
      icon: 'envelope',
      text: 'Emails',
    })
  }
  if (toolsEnabled) {
    paths.push({
      link: ['/analyst/:exerciseId/tools', { params: { exerciseId } }],
      icon: 'console',
      text: 'Tools',
    })
  }

  const sections: Section[] = [
    {
      node: (
        <Status
          key='header'
          small={hide}
          exerciseRunning={exercise?.running || false}
          showTime
        />
      ),
    },
    {
      name: 'Options',

      node: (
        <>
          {hideButton}
          <ExerciseSelector
            className={limitedHeight}
            buttonProps={{
              icon: 'open-application',
              alignText: 'left',
              fill: true,
              minimal: true,
              text: !hide && 'Select an exercise',
            }}
          />
          {/* if the exercise hasn't started yet, the time should be shown relative to the start of time */}
          {exerciseId && exercise.exerciseStart && <TimeSwitch />}
          <ExitButton hideLabel={hide} />
        </>
      ),
    },

    ...(exerciseId
      ? [
          {
            name: 'Pages',
            node: (
              <>
                {paths.map(path => (
                  <LinkButton
                    key={path.text}
                    link={path.link}
                    button={{
                      fill: true,
                      minimal: true,
                      alignText: 'left',
                      icon: path.icon,
                      text: !hide && path.text,
                      active:
                        matchPath(
                          {
                            path: generatePath(
                              path.link[0].toString(),
                              path.link[1]?.params
                            ),
                            // allow subpaths for all but the Dashboard page
                            end: path.text === 'Dashboard',
                          },
                          pathname
                        ) !== null,
                    }}
                  />
                ))}
              </>
            ),
          },
        ]
      : []),
  ]

  const SVGContextValue = useMemo(() => ({ dependencies: [hide] }), [hide])

  return (
    <div style={{ height: '100%', display: 'flex' }}>
      <Sidebar position='left' sections={sections} hideNames={hide} showLogo />

      <div
        style={{
          overflowX: 'hidden',
          overflowY: 'auto',
          flex: 1,
          padding: '0.5rem',
        }}
      >
        {exerciseId ? (
          <SVGContext.Provider value={SVGContextValue}>
            <Suspense fallback={<CenteredSpinner />}>{children}</Suspense>
          </SVGContext.Provider>
        ) : (
          children
        )}
      </div>
    </div>
  )
}

export default NavigationBar
