import { curveLinear } from 'd3-shape'
import { isInteger } from 'lodash'
import React from 'react'
import { Circle } from 'react-native-svg'

import { colors } from '../../Colors'
import { useComponentLayout } from '../../hooks/useComponentLayout'
import { LineData } from '../../types/LineData'
import { notEmpty } from '../../util'
import {
  scaleToTicks,
  YAxis,
  YAxisLabelPadding,
  YAxisWidth,
} from './ornaments/Axis'
import { Grid, gridPadding } from './ornaments/Grid'
import { LinePlot } from './plots/LinePlot'
import { Figure, useFigure } from './useFigure'

interface LineFigureProps {
  data: LineData[]
  strokeWidth?: number
  selection?: number
  labelHeight?: number
  minY?: number
  maxY?: number
  tickLabels?: 'left' | 'right'
  grid?: boolean
}

export const LineFigure: React.FC<LineFigureProps> = ({
  data,
  selection,
  strokeWidth = 2,
  minY,
  maxY,
  tickLabels,
  grid,
}) => {
  const circleRadius = strokeWidth * 2
  const plotPadding = {
    left: circleRadius,
    right: circleRadius + YAxisWidth,
    top: Math.max(circleRadius, gridPadding(grid)),
    bottom: Math.max(circleRadius, YAxisLabelPadding(tickLabels != null)),
  }

  const allValues = data
    .flatMap(({ yValues }) => yValues)
    .filter((v) => v != null)
  const minValue = Math.min(...[...allValues, minY].filter(notEmpty))
  const maxValue = Math.max(...[...allValues, maxY].filter(notEmpty))

  const [onLayout, layout] = useComponentLayout({
    width: 0,
    height: 0,
    x: 0,
    y: 0,
  })

  const figureProps = useFigure({
    size: layout,
    plotPadding,
    dataSets: [
      { domain: [minValue, maxValue], dataLength: data[0].yValues.length },
    ],
  })

  if (layout == null || figureProps == null) {
    return null
  }

  const { contentSize, padding, scaleX, scaleY } = figureProps

  const selectedValue = selection != null ? data[0].yValues[selection] : null

  const ticks = scaleToTicks(scaleY[0], {})

  return (
    <Figure onLayout={onLayout} size={layout} padding={padding}>
      {tickLabels === 'left' && (
        <YAxis
          translateX={0}
          ticks={ticks}
          color={colors.offWhite}
          side="left"
        />
      )}

      {grid && (
        <Grid
          translateX={tickLabels === 'left' ? YAxisWidth : 0}
          size={{
            width: layout.width - (tickLabels ? YAxisWidth : 0),
            height: contentSize.height,
          }}
          ticks={ticks}
        />
      )}

      {data.map((d, i) => (
        <LinePlot
          key={i}
          data={d.yValues}
          strokeColor={d.strokeColor}
          strokeWidth={strokeWidth}
          scaleX={scaleX[0]}
          scaleY={scaleY[0]}
          valueExtractor={(v) => v}
          curve={curveLinear}
        />
      ))}

      {selection != null &&
      selectedValue != null &&
      isInteger(selectedValue) &&
      isInteger(selection) ? (
        <Circle
          cx={scaleX[0](selection)}
          cy={scaleY[0](selectedValue)}
          r={circleRadius}
          fill="white"
        />
      ) : (
        <></>
      )}

      {tickLabels === 'right' && (
        <YAxis
          translateX={layout.width - YAxisWidth}
          ticks={ticks}
          color={colors.offWhite}
          side="right"
        />
      )}
    </Figure>
  )
}
