import { SVGPathData } from 'svg-pathdata'
import arcToBezier from 'svg-arc-to-cubic-bezier'

const typeMap = {
  1: 'Z',
  2: 'M',
  4: 'H',
  8: 'V',
  16: 'L',
  32: 'C',
  64: 'S',
  128: 'Q',
  256: 'T',
  512: 'A',
}

/**
 * 简单解析SVG路径
 * @param d SVG path d属性
 */
export const parseSvgPath = (d: string) => {
  const pathData = new SVGPathData(d)

  const ret = pathData.commands.map(item => {
    return { ...item, type: typeMap[item.type] }
  })
  return ret
}

export type SvgPath = ReturnType<typeof parseSvgPath>

/**
 * 解析SVG路径，并将圆弧（A）类型的路径转为三次贝塞尔（C）类型的路径
 * @param d SVG path d属性
 */
export const toPoints = (d: string) => {
  const pathData = new SVGPathData(d)
  
  const points = []
  for (const item of pathData.commands) {
    const type = typeMap[item.type]

    if (item.type === 2 || item.type === 16) {
      points.push({
        x: item.x,
        y: item.y,
        relative: item.relative,
        type,
      })
    }
    if (item.type === 32) {
      points.push({
        x: item.x, 
        y: item.y,
        curve: {
          type: 'cubic',
          x1: item.x1,
          y1: item.y1,
          x2: item.x2,
          y2: item.y2,
        },
        relative: item.relative,
        type,
      })
    }
    else if (item.type === 128) {
      points.push({
        x: item.x, 
        y: item.y,
        curve: {
          type: 'quadratic',
          x1: item.x1,
          y1: item.y1,
        },
        relative: item.relative,
        type,
      })
    }
    else if (item.type === 512) {
      const lastPoint = points[points.length - 1]
      if (!['M', 'L', 'Q', 'C'].includes(lastPoint.type)) continue

      const cubicBezierPoints = arcToBezier({
        px: lastPoint.x as number,
        py: lastPoint.y as number,
        cx: item.x,
        cy: item.y,
        rx: item.rX,
        ry: item.rY,
        xAxisRotation: item.xRot,
        largeArcFlag: item.lArcFlag,
        sweepFlag: item.sweepFlag,
      })
      for (const cbPoint of cubicBezierPoints) {
        points.push({
          x: cbPoint.x, 
          y: cbPoint.y,
          curve: {
            type: 'cubic',
            x1: cbPoint.x1,
            y1: cbPoint.y1,
            x2: cbPoint.x2,
            y2: cbPoint.y2,
          },
          relative: false,
          type: 'C',
        })
      }
    }
    else if (item.type === 1) {
      points.push({ close: true, type })
    }
    else continue
  }
  return points
}

export const getSvgPathRange = (path: string) => {
  try {
    const pathData = new SVGPathData(path)
    const xList = []
    const yList = []
    for (const item of pathData.commands) {
      const x = ('x' in item) ? item.x : 0
      const y = ('y' in item) ? item.y : 0
      xList.push(x)
      yList.push(y)
    }
    return {
      minX: Math.min(...xList),
      minY: Math.min(...yList),
      maxX: Math.max(...xList),
      maxY: Math.max(...yList),
    }
  }
  catch {
    return {
      minX: 0,
      minY: 0,
      maxX: 0,
      maxY: 0,
    }
  }
}

export type SvgPoints = ReturnType<typeof toPoints>