import * as d3Shape from 'd3-shape'
import { Pressable, StyleProp, Text, View, ViewStyle } from 'react-native'
import { Path } from 'react-native-svg'

import { colors } from '../../Colors'
import { TextStyles } from '../../Styles'
import { useComponentLayout } from '../../hooks/useComponentLayout'
import { formatPercent } from '../../util'
import { AutoLayout } from '../AutoLayout'
import { Figure } from './useFigure'

export type DonutFigureItem = {
  key: string
  percentage: number
}

export type DonutFigureData = DonutFigureItem[]

interface Props {
  title: string
  data: DonutFigureData
  legendProps: {
    keyHeader: string
    valueHeader: string
    colors: Record<string, string>
  }
  selectedItem?: DonutFigureItem
  onSelectItem?: (item: DonutFigureItem) => void
}

export const DonutFigure: React.FC<Props> = ({
  title,
  data,
  legendProps,
  selectedItem,
  onSelectItem,
}) => {
  const [onLayout, layout] = useComponentLayout({
    width: 0,
    height: 0,
    x: 0,
    y: 0,
  })

  if (!layout) {
    return null
  }

  const padding = {
    top: layout.height / 2,
    right: 0,
    bottom: 0,
    left: layout.width / 2,
  }

  const getDonut = d3Shape
    .pie<DonutFigureItem>()
    .value((item) => item.percentage ?? 0)
    .padAngle(0.01)
    .sort(null)

  const size = layout.width / 2
  const thickness = 16

  const getSlice = d3Shape
    .arc<d3Shape.PieArcDatum<DonutFigureItem>>()
    .innerRadius(size - thickness)
    .outerRadius(size)

  return (
    <View
      style={{
        flexDirection: 'row',
        justifyContent: 'space-between',
        flex: 1,
      }}
    >
      <View
        style={{
          width: '50%',
          justifyContent: 'center',
        }}
      >
        <Figure pressable onLayout={onLayout} size={layout} padding={padding}>
          {getDonut(data).map((item, i) => {
            return (
              <Path
                d={getSlice(item) ?? ''}
                fill={legendProps.colors[item.data.key]}
                fillOpacity={
                  selectedItem && item.data.key !== selectedItem.key ? 0.4 : 1
                }
                key={i}
                onPress={() => onSelectItem?.(item.data)}
              />
            )
          })}
        </Figure>
        <View
          style={{
            position: 'absolute',
            top: 0,
            left: 0,
            right: 0,
            height: layout.height,
            justifyContent: 'center',
            alignItems: 'center',
          }}
          pointerEvents="none"
        >
          <Text
            style={{
              ...TextStyles.tiny,
              color: colors.offWhite,
            }}
          >
            {title}
          </Text>
        </View>
      </View>
      <View
        style={{
          width: '40%',
          justifyContent: 'center',
        }}
      >
        <AutoLayout gap={8}>
          {[
            <LegendRow
              headerRow
              key="header"
              value={legendProps.keyHeader}
              percentage={legendProps.valueHeader}
            />,
            ...data.map((item) => (
              <LegendRow
                key={item.key}
                value={item.key}
                percentage={formatPercent(item.percentage, 0, false)}
                legendColors={legendProps.colors}
                toneDown={selectedItem && item.key !== selectedItem.key}
                onPress={() => onSelectItem?.(item)}
              />
            )),
          ]}
        </AutoLayout>
      </View>
    </View>
  )
}

const LegendRow: React.FC<{
  value: string
  percentage: string
  headerRow?: boolean
  legendColors?: Record<string, string>
  toneDown?: boolean
  onPress?: () => void
  style?: StyleProp<ViewStyle>
}> = ({
  value,
  percentage,
  headerRow,
  legendColors,
  toneDown,
  onPress,
  style,
}) => (
  <Pressable onPress={onPress}>
    <View
      style={[
        {
          flexDirection: 'row',
          justifyContent: 'space-between',
        },
        style,
      ]}
    >
      <LegendColumn
        value={value}
        legend={!headerRow}
        heading={headerRow}
        toneDown={toneDown}
        legendColors={legendColors}
      />
      <LegendColumn
        value={percentage}
        heading={headerRow}
        toneDown={toneDown}
        legendColors={legendColors}
      />
    </View>
  </Pressable>
)

const LegendColumn: React.FC<{
  value: string
  legend?: boolean
  heading?: boolean
  toneDown?: boolean
  legendColors?: Record<string, string>
}> = ({ value, legend, heading, toneDown, legendColors }) => (
  <View
    style={{
      flexDirection: 'row',
      alignItems: 'center',
    }}
  >
    {legend && (
      <View
        style={{
          width: 8,
          height: 8,
          borderRadius: 8,
          backgroundColor: legendColors?.[value] ?? colors.white,
          marginTop: 3,
          marginRight: 8,
          opacity: toneDown ? 0.4 : 1,
        }}
      />
    )}
    <Text
      style={[
        heading
          ? {
              ...TextStyles.tiny,
              color: colors.offWhite,
            }
          : {
              ...TextStyles.bodyMedium,
              color: toneDown ? colors.metals.metal1 : colors.white,
            },
      ]}
    >
      {value}
    </Text>
  </View>
)
