import { Polygon, Path, SVG } from '@svgdotjs/svg.js'
import { CONSTANTS } from '../../../constants/constant'

interface ShapePadding {
  paddingX: number
  paddingY: number
}

interface NodeSize {
  width: number
  height: number
}

// 节点形状类
export default class Shape {
  private node: any // TODO: Add proper type
  private mindMap: any // TODO: Add proper type

  constructor(node: any) {
    this.node = node
    this.mindMap = node.mindMap
  }

  // 形状需要的padding
  getShapePadding(width: number, height: number, paddingX: number, paddingY: number): ShapePadding {
    const shape = this.node.getShape()
    const defaultPaddingX = 15
    const defaultPaddingY = 5
    const actWidth = width + paddingX * 2
    const actHeight = height + paddingY * 2
    const actOffset = Math.abs(actWidth - actHeight)

    switch (shape) {
      case CONSTANTS.SHAPE.ROUNDED_RECTANGLE:
        return {
          paddingX: height > width ? (height - width) / 2 : 0,
          paddingY: 0
        }
      case CONSTANTS.SHAPE.DIAMOND:
        return {
          paddingX: width / 2,
          paddingY: height / 2
        }
      case CONSTANTS.SHAPE.PARALLELOGRAM:
        return {
          paddingX: paddingX <= 0 ? defaultPaddingX : 0,
          paddingY: 0
        }
      case CONSTANTS.SHAPE.OUTER_TRIANGULAR_RECTANGLE:
        return {
          paddingX: paddingX <= 0 ? defaultPaddingX : 0,
          paddingY: 0
        }
      case CONSTANTS.SHAPE.INNER_TRIANGULAR_RECTANGLE:
        return {
          paddingX: paddingX <= 0 ? defaultPaddingX : 0,
          paddingY: 0
        }
      case CONSTANTS.SHAPE.ELLIPSE:
        return {
          paddingX: paddingX <= 0 ? defaultPaddingX : 0,
          paddingY: paddingY <= 0 ? defaultPaddingY : 0
        }
      case CONSTANTS.SHAPE.CIRCLE:
        return {
          paddingX: actHeight > actWidth ? actOffset / 2 : 0,
          paddingY: actHeight < actWidth ? actOffset / 2 : 0
        }
      default:
        return {
          paddingX: 0,
          paddingY: 0
        }
    }
  }

  // 创建形状节点
  createShape(): Path | Polygon | null {
    const shape = this.node.getShape()
    let node: Path | Polygon | null = null

    // 矩形
    if (shape === CONSTANTS.SHAPE.RECTANGLE) {
      node = this.createRect()
    } else if (shape === CONSTANTS.SHAPE.DIAMOND) {
      // 菱形
      node = this.createDiamond()
    } else if (shape === CONSTANTS.SHAPE.PARALLELOGRAM) {
      // 平行四边形
      node = this.createParallelogram()
    } else if (shape === CONSTANTS.SHAPE.ROUNDED_RECTANGLE) {
      // 圆角矩形
      node = this.createRoundedRectangle()
    } else if (shape === CONSTANTS.SHAPE.OCTAGONAL_RECTANGLE) {
      // 八角矩形
      node = this.createOctagonalRectangle()
    } else if (shape === CONSTANTS.SHAPE.OUTER_TRIANGULAR_RECTANGLE) {
      // 外三角矩形
      node = this.createOuterTriangularRectangle()
    } else if (shape === CONSTANTS.SHAPE.INNER_TRIANGULAR_RECTANGLE) {
      // 内三角矩形
      node = this.createInnerTriangularRectangle()
    } else if (shape === CONSTANTS.SHAPE.ELLIPSE) {
      // 椭圆
      node = this.createEllipse()
    } else if (shape === CONSTANTS.SHAPE.CIRCLE) {
      // 圆
      node = this.createCircle()
    }
    return node
  }

  // 获取节点减去节点边框宽度、hover节点边框宽度后的尺寸
  private getNodeSize(): NodeSize {
    const borderWidth = this.node.getBorderWidth()
    let { width, height } = this.node
    width -= borderWidth
    height -= borderWidth
    return {
      width,
      height
    }
  }

  // 创建路径节点
  private createPath(pathStr: string) {
    const { customCreateNodePath } = this.mindMap.opt
    if (customCreateNodePath) {
      return SVG(customCreateNodePath(pathStr))
    }
    return new Path().plot(pathStr)
  }

  // 创建多边形节点
  private createPolygon(points: number[][]) {
    const { customCreateNodePolygon } = this.mindMap.opt
    if (customCreateNodePolygon) {
      return SVG(customCreateNodePolygon(points))
    }
    return new Polygon().plot(points.flat())
  }

  // 创建矩形
  private createRect(): Path {
    const { width, height } = this.getNodeSize()
    const borderRadius = this.node.style.merge('borderRadius')
    const pathStr = `
      M${borderRadius},0
      L${width - borderRadius},0
      C${width - borderRadius},0 ${width},${0} ${width},${borderRadius}
      L${width},${height - borderRadius}
      C${width},${height - borderRadius} ${width},${height} ${width - borderRadius
      },${height}
      L${borderRadius},${height}
      C${borderRadius},${height} ${0},${height} ${0},${height - borderRadius}
      L${0},${borderRadius}
      C${0},${borderRadius} ${0},${0} ${borderRadius},${0}
      Z
    `
    return this.createPath(pathStr) as Path
  }

  // 创建菱形
  private createDiamond(): Polygon {
    const { width, height } = this.getNodeSize()
    const halfWidth = width / 2
    const halfHeight = height / 2
    const points = [
      [halfWidth, 0],
      [width, halfHeight],
      [halfWidth, height],
      [0, halfHeight]
    ]
    return this.createPolygon(points) as Polygon
  }

  // 创建平行四边形
  private createParallelogram(): Polygon {
    let { paddingX } = this.node.getPaddingVale()
    paddingX = paddingX || this.node.shapePadding.paddingX
    const { width, height } = this.getNodeSize()
    const points = [
      [paddingX, 0],
      [width, 0],
      [width - paddingX, height],
      [0, height]
    ]
    return this.createPolygon(points) as Polygon
  }

  // 创建圆角矩形
  private createRoundedRectangle(): Path {
    const { width, height } = this.getNodeSize()
    const halfHeight = height / 2
    const pathStr = `
      M${halfHeight},0
      L${width - halfHeight},0
      A${height / 2},${height / 2} 0 0,1 ${width - halfHeight},${height} 
      L${halfHeight},${height}
      A${height / 2},${height / 2} 0 0,1 ${halfHeight},${0}
    `
    return this.createPath(pathStr) as Path
  }

  // 创建八角矩形
  private createOctagonalRectangle(): Polygon {
    const w = 5
    const { width, height } = this.getNodeSize()
    const points = [
      [0, w],
      [w, 0],
      [width - w, 0],
      [width, w],
      [width, height - w],
      [width - w, height],
      [w, height],
      [0, height - w]
    ]
    return this.createPolygon(points) as Polygon
  }

  // 创建外三角矩形
  private createOuterTriangularRectangle(): Polygon {
    let { paddingX } = this.node.getPaddingVale()
    paddingX = paddingX || this.node.shapePadding.paddingX
    const { width, height } = this.getNodeSize()
    const points = [
      [paddingX, 0],
      [width - paddingX, 0],
      [width, height / 2],
      [width - paddingX, height],
      [paddingX, height],
      [0, height / 2]
    ]
    return this.createPolygon(points) as Polygon
  }

  // 创建内三角矩形
  private createInnerTriangularRectangle(): Polygon {
    let { paddingX } = this.node.getPaddingVale()
    paddingX = paddingX || this.node.shapePadding.paddingX
    const { width, height } = this.getNodeSize()
    const points = [
      [0, 0],
      [width, 0],
      [width - paddingX / 2, height / 2],
      [width, height],
      [0, height],
      [paddingX / 2, height / 2]
    ]
    return this.createPolygon(points) as Polygon
  }

  // 创建椭圆
  private createEllipse(): Path {
    const { width, height } = this.getNodeSize()
    const halfWidth = width / 2
    const halfHeight = height / 2
    const pathStr = `
      M${halfWidth},0
      A${halfWidth},${halfHeight} 0 0,1 ${halfWidth},${height} 
      M${halfWidth},${height} 
      A${halfWidth},${halfHeight} 0 0,1 ${halfWidth},${0} 
    `
    return this.createPath(pathStr) as Path
  }

  // 创建圆
  private createCircle(): Path {
    const { width, height } = this.getNodeSize()
    const halfWidth = width / 2
    const halfHeight = height / 2
    const pathStr = `
      M${halfWidth},0
      A${halfWidth},${halfHeight} 0 0,1 ${halfWidth},${height} 
      M${halfWidth},${height} 
      A${halfWidth},${halfHeight} 0 0,1 ${halfWidth},${0} 
    `
    return this.createPath(pathStr) as Path
  }
}

// 形状列表
export const shapeList: string[] = [
  CONSTANTS.SHAPE.RECTANGLE,
  CONSTANTS.SHAPE.DIAMOND,
  CONSTANTS.SHAPE.PARALLELOGRAM,
  CONSTANTS.SHAPE.ROUNDED_RECTANGLE,
  CONSTANTS.SHAPE.OCTAGONAL_RECTANGLE,
  CONSTANTS.SHAPE.OUTER_TRIANGULAR_RECTANGLE,
  CONSTANTS.SHAPE.INNER_TRIANGULAR_RECTANGLE,
  CONSTANTS.SHAPE.ELLIPSE,
  CONSTANTS.SHAPE.CIRCLE
]