import React from 'react'
import { GestureResponderEvent, StyleProp, View, ViewStyle } from 'react-native'
import { Line } from 'react-native-svg'
import { colorsV2 } from '../../Colors'
import { DataStatus } from '../../types/types'
import { notEmpty } from '../../util'
import { BarPlot, BarStyle, barStyleFn } from './BarPlot'
import { StripedPattern } from './StripedPattern'
import { Figure, useFigure } from './useFigure'
import { LinePlot } from './LinePlot'
import { useComponentLayout } from '../../hooks/useComponentLayout'
import _ from 'lodash'
import { Shroud } from './Shroud'
import { AxisConfig, YAxis } from './Axis'

export function BarAndLineFigure<T>({
  barData,
  lineData,
  lineAxisConfig,
  barReverse,
  lineReverse,
  valueExtractor,
  statusExtractor,
  barStyle,
  barWidth,
  onPressBar,
  selectedBarIndex,
  disablePointerEvents,
  style,
  shroud,
}: {
  barData: T[]
  lineData: T[]
  lineAxisConfig?: AxisConfig
  barReverse: boolean
  lineReverse: boolean
  valueExtractor: (v: T) => number
  statusExtractor?: (item: T) => DataStatus
  barStyle?: BarStyle | barStyleFn<T>
  barWidth: number
  onPressBar?: (event: GestureResponderEvent, v: T, i: number) => void
  selectedBarIndex?: number
  disablePointerEvents?: boolean
  style?: StyleProp<ViewStyle>
  shroud: { start: number; end: number }
}): React.ReactElement {
  const lineStrokeWidth = 3
  const halfBarWidth = barWidth / 2
  const plotPadding = {
    left: halfBarWidth,
    right: halfBarWidth,
    top: 0,
    // Plot at the very top of the figure will not get clipped
    bottom: lineStrokeWidth / 2,
  }

  const plots = [
    { data: barData, reverse: barReverse },
    {
      data: lineData,
      reverse: lineReverse,
      axisBounds: lineAxisConfig.bounds,
    },
  ]

  const dataDomain = plots.map(({ data }) => {
    const allNonNullData = data.map(valueExtractor).filter(notEmpty)
    return [Math.min(...allNonNullData), Math.max(...allNonNullData)]
  })

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

  const { contentSize, padding, scaleX, scaleY } = useFigure({
    size: layout,
    dataLength: barData.length,
    dataSets: _.zip(plots, dataDomain).map(
      ([{ reverse, axisBounds }, [minDataValue, maxDataValue]]) => {
        const axisMax = axisBounds?.max ?? maxDataValue
        const axisMin = axisBounds?.min ?? 0
        return {
          domain: reverse ? [axisMax, axisMin] : [axisMin, axisMax],
        }
      }
    ),
    plotPadding,
  })

  return (
    <View
      style={[
        {
          flexDirection: 'row',
        },
        style,
        {},
      ]}
      pointerEvents={disablePointerEvents === true ? 'none' : 'auto'}
    >
      <YAxis
        scale={scaleY[1]}
        color={colorsV2.platform.apple}
        side={'left'}
        config={lineAxisConfig}
      />
      <Figure
        onLayout={onLayout}
        size={layout}
        patterns={<StripedPattern />}
        padding={padding}
      >
        <BarPlot
          data={barData}
          size={contentSize}
          scaleX={scaleX}
          scaleY={scaleY[0]}
          valueExtractor={valueExtractor}
          statusExtractor={statusExtractor}
          barStyle={barStyle}
          barWidth={barWidth}
          onPressBar={onPressBar}
        />
        <LinePlot
          data={lineData}
          scaleX={scaleX}
          scaleY={scaleY[1]}
          strokeColor={colorsV2.platform.apple}
          strokeWidth={lineStrokeWidth}
          valueExtractor={valueExtractor}
        />
        <Shroud
          size={layout}
          paddingHorizontal={halfBarWidth}
          scaleX={scaleX}
          start={shroud.start}
          end={shroud.end}
        />
        {selectedBarIndex != null ? (
          <Line
            x={scaleX(selectedBarIndex)}
            y1={0}
            y2={contentSize.width}
            stroke={colorsV2.white}
            strokeWidth={2}
          />
        ) : null}
      </Figure>
      <YAxis scale={scaleY[0]} side={'right'} color={colorsV2.offWhite} />
    </View>
  )
}
