'use client'

import { Fragment, useEffect, useMemo, useRef, useState } from 'react'
import { Temporal } from '@js-temporal/polyfill'

import Content from '/src/components/Content/Content'
import Legend from '/src/components/Legend/Legend'
import { PersonResponse } from '/src/config/api'
import { useTranslation } from '/src/i18n/client'
import { useStore } from '/src/stores'
import useSettingsStore from '/src/stores/settingsStore'
import { calculateAvailability, calculateTable, makeClass, relativeTimeFormat } from '/src/utils'

import styles from './AvailabilityViewer.module.scss'
import { usePalette } from '/hooks/usePalette'

interface AvailabilityViewerProps {
  times: string[]
  timezone: string
  people: PersonResponse[]
}

const AvailabilityViewer = ({ times, timezone, people }: AvailabilityViewerProps) => {
  const { t, i18n } = useTranslation('event')

  const timeFormat = useStore(useSettingsStore, state => state.timeFormat) ?? '12h'
  const highlight = useStore(useSettingsStore, state => state.highlight)
  const [filteredPeople, setFilteredPeople] = useState(people.map(p => p.name))
  const [tempFocus, setTempFocus] = useState<string>()
  const [focusCount, setFocusCount] = useState<number>()

  const wrapperRef = useRef<HTMLDivElement>(null)
  const [tooltip, setTooltip] = useState<{
    x: number
    y: number
    available: string
    date: string
    people: string[]
  }>()

  // Calculate table
  const { rows, columns } = useMemo(() =>
    calculateTable(times, i18n.language, timeFormat, timezone),
  [times, i18n.language, timeFormat, timezone])

  // Calculate availabilities
  const { availabilities, min, max } = useMemo(() =>
    calculateAvailability(times, people.filter(p => filteredPeople.includes(p.name))),
  [times, filteredPeople, people])

  // Create the colour palette
  const palette = usePalette(Math.max((max - min) + 1, 2))

  // Reselect everyone if the amount of people changes
  useEffect(() => {
    setFilteredPeople(people.map(p => p.name))
  }, [people.length])

  const heatmap = useMemo(() => columns.map((column, x) => <Fragment key={x}>
    {column ? <div className={styles.dateColumn}>
      {column.header.dateLabel && <label className={styles.dateLabel}>{column.header.dateLabel}</label>}
      <label className={styles.dayLabel}>{column.header.weekdayLabel}</label>

      <div
        className={styles.times}
        data-border-left={x === 0 || columns.at(x - 1) === null}
        data-border-right={x === columns.length - 1 || columns.at(x + 1) === null}
      >
        {column.cells.map((cell, y) => {
          if (y === column.cells.length - 1) return null

          if (!cell) return <div
            className={makeClass(styles.timeSpace, styles.grey)}
            key={y}
            title={t<string>('greyed_times')}
          />

          let peopleHere = availabilities.find(a => a.date === cell.serialized)?.people ?? []
          if (tempFocus) {
            peopleHere = peopleHere.filter(p => p === tempFocus)
          }

          return <div
            key={y}
            className={makeClass(
              styles.time,
              (focusCount === undefined || focusCount === peopleHere.length) && highlight && (peopleHere.length === max || tempFocus) && peopleHere.length > 0 && styles.highlight,
            )}
            style={{
              backgroundColor: (focusCount === undefined || focusCount === peopleHere.length) ? palette[tempFocus && peopleHere.length ? max : peopleHere.length] : 'transparent',
              ...cell.minute !== 0 && cell.minute !== 30 && { borderTopColor: 'transparent' },
              ...cell.minute === 30 && { borderTopStyle: 'dotted' },
            }}
            aria-label={peopleHere.join(', ')}
            onMouseEnter={e => {
              const cellBox = e.currentTarget.getBoundingClientRect()
              const wrapperBox = wrapperRef.current?.getBoundingClientRect() ?? { x: 0, y: 0 }
              setTooltip({
                x: Math.round(cellBox.x - wrapperBox.x + cellBox.width / 2),
                y: Math.round(cellBox.y - wrapperBox.y + cellBox.height) + 6,
                available: `${peopleHere.length} / ${filteredPeople.length} ${t('available')}`,
                date: cell.label,
                people: peopleHere,
              })
            }}
            onMouseLeave={() => setTooltip(undefined)}
          />
        })}
      </div>
    </div> : <div className={styles.columnSpacer} />}
  </Fragment>), [
    availabilities,
    columns,
    highlight,
    max,
    t,
    palette,
    tempFocus,
    focusCount,
    filteredPeople,
  ])

  return <>
    <Content>
      <Legend
        min={min}
        max={max}
        total={filteredPeople.length}
        palette={palette}
        onSegmentFocus={setFocusCount}
      />

      <span className={styles.info}>{t('group.info1')}</span>

      {people.length > 1 && <>
        <span className={styles.info}>{t('group.info2')}</span>
        <div className={styles.people}>
          {people.map(person =>
            <button
              type="button"
              className={makeClass(
                styles.person,
                filteredPeople.includes(person.name) && styles.personSelected,
              )}
              key={person.name}
              onClick={() => {
                setTempFocus(undefined)
                if (filteredPeople.includes(person.name)) {
                  setFilteredPeople(filteredPeople.filter(n => n !== person.name))
                } else {
                  setFilteredPeople([...filteredPeople, person.name])
                }
              }}
              onMouseOver={() => setTempFocus(person.name)}
              onMouseOut={() => setTempFocus(undefined)}
              title={relativeTimeFormat(Temporal.Instant.fromEpochSeconds(person.created_at), i18n.language)}
            >{person.name}</button>
          )}
        </div>
      </>}
    </Content>

    <div className={styles.wrapper} ref={wrapperRef}>
      <div>
        <div className={styles.heatmap}>
          {useMemo(() => <div className={styles.timeLabels}>
            {rows.map((row, i) =>
              <div className={styles.timeSpace} key={i}>
                {row && <label className={styles.timeLabel}>
                  {row.label}
                </label>}
              </div>
            )}
          </div>, [rows])}

          {heatmap}
        </div>

        {tooltip && <div
          className={styles.tooltip}
          style={{ top: tooltip.y, left: tooltip.x }}
        >
          <h3>{tooltip.available}</h3>
          <span>{tooltip.date}</span>
          {!!filteredPeople.length && <div>
            {tooltip.people.map(person => <span key={person}>{person}</span>)}
            {filteredPeople.filter(p => !tooltip.people.includes(p)).map(person =>
              <span key={person} data-disabled>{person}</span>
            )}
          </div>}
        </div>}
      </div>
    </div>
  </>
}

export default AvailabilityViewer
