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,
    }
  }
}

*/

// 辅助：采样三次贝塞尔曲线
function sampleCubicBezier(
  x0: number, y0: number, x1: number, y1: number,
  x2: number, y2: number, x3: number, y3: number,
  samples = 20
): { x: number; y: number }[] {
  const points = [];
  for (let i = 0; i <= samples; i++) {
    const t = i / samples;
    const mt = 1 - t;
    const x = mt ** 3 * x0 + 3 * mt ** 2 * t * x1 + 3 * mt * t ** 2 * x2 + t ** 3 * x3;
    const y = mt ** 3 * y0 + 3 * mt ** 2 * t * y1 + 3 * mt * t ** 2 * y2 + t ** 3 * y3;
    points.push({ x, y });
  }
  return points;
}

// 辅助：采样二次贝塞尔曲线
function sampleQuadraticBezier(
  x0: number, y0: number, x1: number, y1: number,
  x2: number, y2: number, samples = 20
): { x: number; y: number }[] {
  const points = [];
  for (let i = 0; i <= samples; i++) {
    const t = i / samples;
    const mt = 1 - t;
    const x = mt ** 2 * x0 + 2 * mt * t * x1 + t ** 2 * x2;
    const y = mt ** 2 * y0 + 2 * mt * t * y1 + t ** 2 * y2;
    points.push({ x, y });
  }
  return points;
}

// 辅助：采样椭圆弧（基于 SVG 规范参数方程）
function sampleArc(
  x0: number, y0: number, rx: number, ry: number,
  xAxisRotation: number, largeArcFlag: boolean, sweepFlag: boolean,
  x: number, y: number, samples = 30
): { x: number; y: number }[] {
  const phi = (xAxisRotation * Math.PI) / 180;
  const cosPhi = Math.cos(phi);
  const sinPhi = Math.sin(phi);

  const dx = (x0 - x) / 2;
  const dy = (y0 - y) / 2;
  const x1p = cosPhi * dx + sinPhi * dy;
  const y1p = -sinPhi * dx + cosPhi * dy;

  let rxx = Math.abs(rx);
  let ryy = Math.abs(ry);
  const lambda = (x1p * x1p) / (rxx * rxx) + (y1p * y1p) / (ryy * ryy);
  if (lambda > 1) {
    rxx *= Math.sqrt(lambda);
    ryy *= Math.sqrt(lambda);
  }

  const sq = Math.sqrt(
    (rxx * rxx * (ryy * ryy) - rxx * rxx * (y1p * y1p) - ryy * ryy * (x1p * x1p)) /
    (rxx * rxx * (y1p * y1p) + ryy * ryy * (x1p * x1p))
  );
  const sign = largeArcFlag === sweepFlag ? -1 : 1;
  const cxp = sign * sq * ((rxx * y1p) / ryy);
  const cyp = sign * sq * ((-ryy * x1p) / rxx);

  const cx = cosPhi * cxp - sinPhi * cyp + (x0 + x) / 2;
  const cy = sinPhi * cxp + cosPhi * cyp + (y0 + y) / 2;

  const vectorAngle = (ux: number, uy: number, vx: number, vy: number) => {
    const dot = ux * vx + uy * vy;
    const len = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));
    let ang = Math.acos(Math.max(-1, Math.min(1, dot / len)));
    const cross = ux * vy - uy * vx;
    return cross < 0 ? -ang : ang;
  };

  const ux = (x1p - cxp) / rxx;
  const uy = (y1p - cyp) / ryy;
  const vx = (-x1p - cxp) / rxx;
  const vy = (-y1p - cyp) / ryy;

  let startAngle = vectorAngle(1, 0, ux, uy);
  let deltaAngle = vectorAngle(ux, uy, vx, vy);

  if (!sweepFlag && deltaAngle > 0) {
    deltaAngle -= 2 * Math.PI;
  } else if (sweepFlag && deltaAngle < 0) {
    deltaAngle += 2 * Math.PI;
  }

  const points: { x: number; y: number }[] = [];
  for (let i = 0; i <= samples; i++) {
    const t = i / samples;
    const angle = startAngle + t * deltaAngle;
    const xp = rxx * Math.cos(angle);
    const yp = ryy * Math.sin(angle);
    const px = cosPhi * xp - sinPhi * yp + cx;
    const py = sinPhi * xp + cosPhi * yp + cy;
    points.push({ x: px, y: py });
  }
  return points;
}

// 主函数
export const getSvgPathRange = (path: string) => {
  try {
    const pathData = new SVGPathData(path);
    let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
    let curX = 0, curY = 0;           // 当前点（上一命令终点）
    let startX = 0, startY = 0;        // 子路径起点（用于 Z）

    const updateBounds = (x: number, y: number) => {
      minX = Math.min(minX, x);
      minY = Math.min(minY, y);
      maxX = Math.max(maxX, x);
      maxY = Math.max(maxY, y);
    };

    const processPoints = (points: { x: number; y: number }[]) => {
      points.forEach(p => updateBounds(p.x, p.y));
    };

    for (const cmd of pathData.commands) {
      switch (cmd.type) {
        case SVGPathData.MOVE_TO:
          curX = cmd.x;
          curY = cmd.y;
          startX = curX;
          startY = curY;
          updateBounds(curX, curY);
          break;

        case SVGPathData.LINE_TO:
          curX = cmd.x;
          curY = cmd.y;
          updateBounds(curX, curY);
          break;

        case SVGPathData.HORIZ_LINE_TO:
          curX = cmd.x;
          updateBounds(curX, curY);
          break;

        case SVGPathData.VERT_LINE_TO:
          curY = cmd.y;
          updateBounds(curX, curY);
          break;

        case SVGPathData.CURVE_TO:
          {
            const points = sampleCubicBezier(
              curX, curY,
              cmd.x1, cmd.y1,
              cmd.x2, cmd.y2,
              cmd.x, cmd.y
            );
            processPoints(points);
            curX = cmd.x;
            curY = cmd.y;
          }
          break;

        case SVGPathData.SMOOTH_CURVE_TO:
          // 为简化，此处省略反射控制点的精确计算，可根据需要补充
          // 可直接使用采样近似或添加反射逻辑
          break;

        case SVGPathData.QUAD_TO:
          {
            const points = sampleQuadraticBezier(
              curX, curY,
              cmd.x1, cmd.y1,
              cmd.x, cmd.y
            );
            processPoints(points);
            curX = cmd.x;
            curY = cmd.y;
          }
          break;

        case SVGPathData.SMOOTH_QUAD_TO:
          // 省略
          break;

        case SVGPathData.ARC:
          {
            const points = sampleArc(
              curX, curY,
              cmd.rX, cmd.rY,
              cmd.xRot,
              cmd.lArcFlag, cmd.sweepFlag,
              cmd.x, cmd.y
            );
            processPoints(points);
            curX = cmd.x;
            curY = cmd.y;
          }
          break;

        case SVGPathData.CLOSE_PATH:
          curX = startX;
          curY = startY;
          updateBounds(curX, curY);
          break;
      }
    }

    if (minX === Infinity) {
      return { minX: 0, minY: 0, maxX: 0, maxY: 0 };
    }

    return { minX, minY, maxX, maxY };
  } catch {
    return { minX: 0, minY: 0, maxX: 0, maxY: 0 };
  }
};

export type SvgPoints = ReturnType<typeof toPoints>