import benchy, cairo, pixie, pixie/fileformats/svg {.all.}, pixie/paths {.all.}

type
  Fill = object
    shapes: seq[Polygon]
    transform: Mat3
    paint: Paint
    windingRule: WindingRule

  Benchmark = object
    name: string
    fills: seq[Fill]

var benchmarks: seq[Benchmark]

block: # Basic rect
  let path = newPath()
  path.rect(rect(0, 0, 900, 900))

  let
    shapes = path.commandsToShapes(true, 1)
    paint = newPaint(SolidPaint)
  paint.color = color(0, 0, 0, 1)

  benchmarks.add(Benchmark(
    name: "rect",
    fills: @[Fill(
    shapes: shapes,
    transform: mat3(),
    paint: paint,
    windingRule: NonZero
  )]))

block: # Rounded rect
  let path = newPath()
  path.roundedRect(rect(0, 0, 900, 900), 20, 20, 20, 20)

  let
    shapes = path.commandsToShapes(true, 1)
    paint = newPaint(SolidPaint)
  paint.color = color(0, 0, 0, 1)

  benchmarks.add(Benchmark(
    name: "roundedRect",
    fills: @[Fill(
    shapes: shapes,
    transform: mat3(),
    paint: paint,
    windingRule: NonZero
    )]))

block: # Heart
  let path = parsePath("""
      M 100,300
      A 200,200 0,0,1 500,300
      A 200,200 0,0,1 900,300
      Q 900,600 500,900
      Q 100,600 100,300 z
  """)

  let
    shapes = path.commandsToShapes(true, 1)
    paint = newPaint(SolidPaint)
  paint.color = color(0, 0, 0, 1)

  benchmarks.add(Benchmark(
    name: "Heart",
    fills: @[Fill(
    shapes: shapes,
    transform: mat3(),
    paint: paint,
    windingRule: NonZero
  )]))

block: # Tiger
  let
    data = readFile("tests/fileformats/svg/Ghostscript_Tiger.svg")
    parsed = parseSvg(data)

  var fills: seq[Fill]

  for (path, props) in parsed.elements:
    if props.display and props.opacity > 0:
      if props.fill != "none":
        let
          shapes = path.commandsToShapes(true, 1)
          paint = parseSomePaint(props.fill)
        fills.add(Fill(
          shapes: shapes,
          transform: props.transform,
          paint: paint,
          windingRule: props.fillRule
        ))

      if props.stroke != rgbx(0, 0, 0, 0) and props.strokeWidth > 0:
        let strokeShapes = strokeShapes(
          parseSomePath(path, false, props.transform.pixelScale),
          props.strokeWidth,
          props.strokeLineCap,
          props.strokeLineJoin,
          props.strokeMiterLimit,
          props.strokeDashArray,
          props.transform.pixelScale
        )
        let paint = newPaint(props.stroke)
        paint.color.a *= (props.opacity * props.strokeOpacity)
        fills.add(Fill(
          shapes: strokeShapes,
          transform: props.transform,
          paint: paint,
          windingRule: NonZero
        ))

  # benchmarks.add(fills)

block:
  for benchmark in benchmarks:
    let
      surface = imageSurfaceCreate(FORMAT_ARGB32, 900, 900)
      ctx = surface.create()

    timeIt "[cairo] " & benchmark.name:
      for fill in benchmark.fills:
        if fill.shapes.len > 0:
          ctx.newPath()
          for shape in fill.shapes:
            ctx.moveTo(shape[0].x, shape[0].y)
            for v in shape:
              ctx.lineTo(v.x, v.y)
          let
            color = fill.paint.color
            matrix = Matrix(
              xx: fill.transform[0, 0],
              yx: fill.transform[0, 1],
              xy: fill.transform[1, 0],
              yy: fill.transform[1, 1],
              x0: fill.transform[2, 0],
              y0: fill.transform[2, 1],
            )
          ctx.setSourceRgba(color.r, color.g, color.b, color.a)
          ctx.setMatrix(matrix.unsafeAddr)
          ctx.setFillRule(
            if fill.windingRule == NonZero:
              FillRuleWinding
            else:
              FillRuleEvenOdd
          )
          ctx.fill()

    # discard surface.writeToPng(("cairo_" & benchmark.name & ".png").cstring)

block:
  for benchmark in benchmarks:
    let image = newImage(900, 900)

    timeIt "[pixie] " & benchmark.name:
      for fill in benchmark.fills:
        if fill.shapes.len > 0:
          let p = newPath()
          for shape in fill.shapes:
            p.moveTo(shape[0])
            for v in shape:
              p.lineTo(v)
          image.fillPath(
            p,
            fill.paint,
            fill.transform,
            fill.windingRule
          )

    # image.writeFile("pixie_" & benchmark.name & ".png")