import React, { ReactNode } from 'react'
import styled from 'styled-components'
import { ShapeStyle } from './types'

const defaultShapeStyle: Required<ShapeStyle> = {
  pattern: 'none',
  patternRotation: 45,
  patternWidth: 10,
  patternSpace: 5,
  fill: 'rgba(0,0,0,0.15)',
  stroke: 'gray',
  strokeWidth: 0.5,
  cornerRadius: 10,
}

interface BaseAreaAnnotationProps {
  shapeType?: 'rect' | 'circle' | 'custom' // Make it optional here
  children?: ReactNode
  pattern?: 'crossed' | 'hatched' | 'dotted' | 'none'
  textAnchor?: 'left' | 'center' | 'right'
  offset?: number | [number, number]
  fullSize?: [number, number]
  shapeStyle?: ShapeStyle
  size?: number | [number, number]
  rotation?: number
  customShape?: {
    x: number
    y: number
  }[]
}

export const AreaAnnotation = ({
  children,
  shapeType = 'circle',

  // rect or circle
  size = 5,
  rotation = 0,

  // custom
  customShape,

  // size of the parent container for relative sizing of the shape
  fullSize = [100, 100],

  textAnchor = 'center',
  offset = 0,

  shapeStyle = {},
}: BaseAreaAnnotationProps) => {
  const [h, v] = getOffset(offset)
  const currentShapeStyle = {
    ...defaultShapeStyle,
    ...shapeStyle,
  }

  const { pattern, patternWidth, patternSpace, patternRotation, fill } =
    currentShapeStyle
  const hatchId = Math.random().toString(36).substring(7)
  // Type guard to ensure customShape exists when needed
  if (shapeType === 'custom' && !customShape) {
    console.warn(
      'Custom shape type requires customShape prop. Falling back to circle.',
    )
    shapeType = 'circle'
  }

  // Extract rotation based on shape type
  const getRotation = () => {
    if (shapeType === 'custom') return 0
    return rotation ?? 0
  }
  // Calculate size based on shape type
  const getShapeSize = () => {
    if (shapeType === 'custom') return [0, 0]
    return getSize(size ?? 20, fullSize[0], fullSize[1])
  }

  const [sx, sy] = getShapeSize()
  rotation = getRotation()

  const getPatternFill = () => {
    switch (pattern) {
      case 'hatched':
        return `url(#hatched_${hatchId})`
      case 'dotted':
        return `url(#dotted_${hatchId})`
      case 'crossed':
        return `url(#crossed_${hatchId})`
      default:
        return fill
    }
  }

  const renderShape = () => {
    const shapeProps = {
      style: {
        ...currentShapeStyle,
        fill: getPatternFill(),
      } as React.CSSProperties,
    }

    switch (shapeType) {
      case 'circle':
        return (
          <ellipse
            rx={sx / 2}
            ry={sy / 2}
            transform={`rotate(${rotation})`}
            {...shapeProps}
          />
        )

      case 'rect':
        return (
          <rect
            rx={currentShapeStyle.cornerRadius}
            ry={currentShapeStyle.cornerRadius}
            x={-sx / 2}
            y={-sy / 2}
            width={sx}
            height={sy}
            transform={`rotate(${rotation})`}
            {...shapeProps}
          />
        )

      case 'custom':
        return (
          <path
            d={customShapeToPath(customShape!, fullSize[0], fullSize[1])}
            {...shapeProps}
          />
        )
    }
  }

  return (
    <AnnotationContainer className='annoContainer'>
      <AreaSvg
        width={Math.max(4, Math.abs(h))}
        height={Math.max(4, Math.abs(v))}
        style={{
          left: h >= 0 ? 0 : h,
          top: v >= 0 ? 0 : v,
        }}
      >
        <defs>
          <pattern
            id={`dotted_${hatchId}`}
            patternUnits='userSpaceOnUse'
            x={-Math.round(patternSpace / 2)}
            y={-Math.round(patternWidth / 2)}
            patternTransform={`rotate(${patternRotation - rotation} 0 0)`}
            width={patternWidth + patternSpace}
            height={patternWidth + patternSpace}
          >
            <circle
              cx={Math.round(patternWidth / 2)}
              cy={Math.round(patternWidth / 2)}
              r={Math.round(patternWidth / 2)}
              style={{ stroke: 'none', fill }}
            />
          </pattern>

          <pattern
            id={'hatched_' + hatchId}
            patternUnits='userSpaceOnUse'
            width={patternSpace + patternWidth}
            height={patternSpace + patternWidth}
            patternTransform={
              'rotate(' + (patternRotation - rotation) + ' 0 0)'
            }
          >
            <line
              x1='0'
              y1='0'
              x2={0}
              y2={patternSpace + patternWidth}
              style={{
                stroke: fill,
                strokeWidth: patternWidth,
              }}
            />
          </pattern>
          <pattern
            id={`crossed_${hatchId}`}
            patternUnits='userSpaceOnUse'
            width={patternWidth + patternSpace}
            height={patternWidth + patternSpace}
            patternTransform={`rotate(${patternRotation - rotation})`} // Removed '0 0'
          >
            <path
              d={createCrosshatchPath(patternWidth, patternSpace)}
              stroke={fill}
              strokeWidth={patternWidth}
              strokeOpacity={0.5} // Added explicit opacity
            />
          </pattern>
        </defs>
        {renderShape()}
      </AreaSvg>
      <ContentContainer
        style={{
          minWidth: 'max-content',
          left: h,
          top: v,
          transform: 'translate(-50%, -50%)',
          textAlign: textAnchor,
        }}
      >
        {children}
      </ContentContainer>
    </AnnotationContainer>
  )
}
const AnnotationContainer = styled.div`
  display: inline-block;
  line-height: 1em;
  position: absolute;
`

const ContentContainer = styled.div`
  position: absolute;
  line-height: 1em;
`

const AreaSvg = styled.svg`
  position: absolute;
  top: 0;
  left: 0;
  overflow: visible;
`
const createCrosshatchPath = (width: number, space: number) => {
  const tileSize = width + space

  return `M ${space / 2} 0 
          L ${space / 2} ${tileSize}
          M 0 ${space / 2} 
          L ${tileSize} ${space / 2}`
}

function percentageToPixel(percentage: number, total: number) {
  return (percentage * total) / 100
}

function customShapeToPath(
  customShape: {
    x: number
    y: number
  }[],
  width: number,
  height: number,
) {
  // use percentageToPixel
  return [
    customShape
      .map((point, index) => {
        var x = percentageToPixel(point.x, width)
        var y = percentageToPixel(point.y, height)
        return `${index === 0 ? 'M' : 'L'} ${x} ${y}`
      })
      .join(' '),
    'Z',
  ].join(' ')
}

function getOffset(offset: number | [number, number]) {
  if (Array.isArray(offset)) {
    return offset
  }
  return [offset, offset]
}

function getSize(
  size: number | [number, number],
  width: number,
  height: number,
) {
  if (Array.isArray(size)) {
    return [
      percentageToPixel(size[0], width),
      percentageToPixel(size[1], height),
    ]
  }

  return [percentageToPixel(size, width), percentageToPixel(size, width)]
  // return [(size * width) / 100, (size * height) / 100];
}

function getDirection(offset: [number, number]) {
  const [h, v] = offset

  if (h === 0 && v === 0) return 'center'
  if (h === 0) return v > 0 ? 'bottom' : 'top'
  if (v === 0) return h > 0 ? 'right' : 'left'

  if (h > 0) {
    return v > 0 ? 'bottom-right' : 'top-right'
  } else {
    return v > 0 ? 'bottom-left' : 'top-left'
  }
}

function getLinePoints(v: number, h: number) {
  const sx = h >= 0 ? 0 : Math.abs(h)
  const sy = v >= 0 ? 0 : Math.abs(v)
  const ex = h >= 0 ? h : 0
  const ey = v >= 0 ? v : 0
  return { sx, sy, ex, ey }
}
