import { ScaleLinear } from 'd3-scale'
import React from 'react'
import { GestureResponderEvent } from 'react-native'
import { Line, Text } from 'react-native-svg'
import { colorsV2 } from '../../Colors'
import { DataStatus } from '../../types/types'
import { TopRoundedBar } from './../TopRoundedBar'
import { Size } from './useFigure'

export type barStyleFn<T> = (i: number, item: T) => BarStyle

export interface BarStyle {
  fill?: string
  minHeight?: number
}

/**
 * An "X" centered at x,y
 */
const Cross: React.FC<{ size: number; x: number; y: number }> = ({
  size,
  x,
  y,
}) => (
  <>
    <Line
      x1={x - size / 2}
      x2={x + size / 2}
      y1={y}
      y2={y - size}
      stroke={colorsV2.metals.metal0}
      strokeWidth={size / 4}
    />
    <Line
      x1={x - size / 2}
      x2={x + size / 2}
      y1={y - size}
      y2={y}
      stroke={colorsV2.metals.metal0}
      strokeWidth={size / 4}
    />
  </>
)

/**
 * BarPlot Bar. Can be striped or replaced with "X"
 */
const Bar: React.FC<{
  x: number
  width: number
  height: number
  contentHeight: number
  onPress?: (event: GestureResponderEvent) => void
  fill?: string
  status: DataStatus
}> = ({ x, width, height, contentHeight, onPress, fill, status }) =>
  status === 'missing' ? (
    <Cross size={width} x={x} y={contentHeight} />
  ) : (
    <TopRoundedBar
      x={x}
      y={contentHeight - height}
      width={width}
      height={height}
      fill={
        status === 'partial' ? 'url(#striped)' : fill ?? colorsV2.metals.metal0
      }
      r={width}
      onPress={(e) => {
        onPress?.(e)
      }}
    />
  )

/**
 * Standard set of bars
 */
export function BarPlot<T>({
  data,
  size,
  scaleX,
  scaleY,
  valueExtractor,
  statusExtractor,
  barStyle,
  barWidth,
  onPressBar,
}: {
  data: T[]
  size: Size
  scaleX: ScaleLinear<number, number>
  scaleY: ScaleLinear<number, number>
  valueExtractor: (v: T) => number
  statusExtractor?: (item: T) => DataStatus
  barStyle?: BarStyle | barStyleFn<T>
  barWidth: number
  onPressBar?: (event: GestureResponderEvent, v: T, i: number) => void
}): React.ReactElement {
  return (
    <>
      {data.map((v, i) => {
        const style =
          barStyle != null
            ? typeof barStyle === 'function'
              ? barStyle(i, v)
              : barStyle
            : {}

        const scaledValue = scaleY(valueExtractor(v))
        const scaledX = scaleX(i)

        if (scaledValue != null && scaledX != null) {
          const height = Math.max(
            size.height - scaledValue,
            style.minHeight ?? 0
          )
          const x = scaledX
          const status = statusExtractor ? statusExtractor(v) : 'full'
          return (
            <Bar
              key={i}
              x={x}
              width={barWidth}
              height={height}
              fill={style.fill}
              status={status}
              contentHeight={size.height}
              onPress={(e) => onPressBar?.(e, v, i)}
            />
          )
        } else {
          return null
        }
      })}
    </>
  )
}
