import type { LinkType } from '@/components/LinkButton'
import { ButtonGroup, Divider } from '@blueprintjs/core'
import { css } from '@emotion/css'
import type { ActionLogSimple } from '@inject/graphql/fragment-types'
import {
  Fragment,
  useCallback,
  useEffect,
  useLayoutEffect,
  useMemo,
  useRef,
  useState,
  type FC,
} from 'react'
import InjectMessage from '../InjectMessage'
import ScrollDownButton from './ScrollDownButton'
import SeeAllUnreadButton from './SeeAllUnreadButton'

const view = css`
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  margin-top: 1rem;
  gap: 1rem;
`

const bottom = css`
  position: absolute;
  bottom: 1rem;
  right: 1rem;
  display: flex;
  justify-content: flex-end;
`

const unreadLogsDivider = css`
  display: flex;
  gap: 0.5rem;
  margin: 0.5rem 2rem;
`

const divider = css`
  flex: 1;
  align-self: center;
`

const ListRenderer: FC<{
  actionLogs: ActionLogSimple[]
  exerciseId: string
  teamId: string
  channelId: string
  inInstructor: boolean
  getFullscreenLink: (actionLogId: string) => LinkType
  scrollToLast?: boolean
}> = ({
  actionLogs,
  exerciseId,
  teamId,
  channelId,
  inInstructor,
  getFullscreenLink,
  scrollToLast,
}) => {
  const actionLogsLengthPrev = useRef<number>(actionLogs.length)

  const getFirstUnreadId = useCallback(
    () => actionLogs.find(actionLog => !actionLog.readReceipt)?.id,
    [actionLogs]
  )
  /*
   * not using useMemo to have control over when to update the state
   * (see useScroll.ts)
   */
  const [firstUnreadId, setFirstUnreadId] = useState<string | undefined>(
    getFirstUnreadId()
  )

  const lastUnreadId = useMemo(() => {
    const last = actionLogs.at(-1)
    return last?.readReceipt ? undefined : last?.id
  }, [actionLogs])

  const unreadLogsStartRef = useRef<HTMLDivElement | null>(null)
  const lastUnreadLogRef = useRef<HTMLDivElement | null>(null)

  // scroll to bottom when rendered, or when changing teams or channels
  useEffect(() => {
    const ref = document.getElementById('contentView') as HTMLDivElement
    if (ref) {
      ref.scrollTo({ top: ref.scrollHeight, behavior: 'instant' })
    }
  }, [actionLogs])

  /*
   * Logs with readReceipt === undefined should be rendered as unread
   * the whole time the same channel is open for the same teams.
   * However, actionLog.readReceipt will update as soon as the InjectMessage
   * is rendered.
   *
   * The following effects prevent the update of actionLog.readReceipt
   * from rendering the actionLog as read.
   */

  useLayoutEffect(() => {
    setFirstUnreadId(getFirstUnreadId())
    // do not reset when actionLogs change
  }, [channelId, teamId])

  useEffect(() => {
    if (actionLogs.length !== actionLogsLengthPrev.current) {
      if (firstUnreadId === undefined) setFirstUnreadId(getFirstUnreadId())

      if (scrollToLast) {
        lastUnreadLogRef.current?.scrollIntoView({
          behavior: 'smooth',
          inline: 'nearest',
        })
      }
    }
    actionLogsLengthPrev.current = actionLogs.length
  }, [actionLogs, firstUnreadId, getFirstUnreadId, scrollToLast])

  return (
    <div className={view}>
      {actionLogs.map(actionLog => (
        <Fragment key={actionLog.id}>
          {/*
           * causes problems with scrolling if the last unread is also
           * the first, so I decided not to render the divider at all
           * in this case
           */}
          {actionLog.id === firstUnreadId && (
            <div ref={unreadLogsStartRef} className={unreadLogsDivider}>
              <Divider className={divider} />
              <div>Unread:</div>
              <Divider className={divider} />
            </div>
          )}
          {lastUnreadId === actionLog.id && <div ref={lastUnreadLogRef} />}
          <InjectMessage
            exerciseId={exerciseId}
            teamId={teamId}
            actionLog={actionLog}
            fullscreenLink={getFullscreenLink(actionLog.id)}
            inInstructor={inInstructor}
          />
        </Fragment>
      ))}
      {actionLogs.length > 0 && <div style={{ height: '4rem' }} />}
      <div className={bottom}>
        <ButtonGroup>
          <ScrollDownButton
            actionLogsLength={actionLogs.length}
            teamId={teamId}
            channelId={channelId}
          />
          <SeeAllUnreadButton
            firstUnreadId={firstUnreadId}
            unreadLogsStartRef={unreadLogsStartRef}
          />
        </ButtonGroup>
      </div>
    </div>
  )
}

export default ListRenderer
