"""Auto-generated example: ResultImage: Over Time Slider."""

from typing import Any

import bencher as bch
from datetime import datetime, timedelta
import math
import numpy as np
from PIL import Image, ImageDraw


def _polygon_points(radius, sides, start_angle=0.0):
    points = []
    for ang in np.linspace(0, 360, sides + 1):
        angle = math.radians(start_angle + ang)
        points.append([math.sin(angle) * radius, math.cos(angle) * radius])
    return points


def _draw_polygon_image(points, color, linewidth, size=200, offset=(0, 0)):
    img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
    draw = ImageDraw.Draw(img)
    ox, oy = offset
    scaled = [((p[0] + 1) * size / 2 + ox, (1 - p[1]) * size / 2 + oy) for p in points]
    draw.line(scaled, fill=color, width=int(linewidth))
    return img


class PolygonRenderer(bch.ParametrizedSweep):
    """Renders polygon images with configurable sides, radius, and color."""

    sides = bch.IntSweep(default=3, bounds=(3, 7), doc="Number of polygon sides")
    radius = bch.FloatSweep(default=0.6, bounds=(0.2, 1.0), doc="Polygon radius")
    color = bch.StringSweep(["red", "green", "blue"], doc="Line color")
    polygon = bch.ResultImage(doc="Rendered polygon image")
    area = bch.ResultVar("u^2", doc="Polygon area")

    _start_angle = 0.0
    _offset = (0, 0)

    def __call__(self, **kwargs: Any) -> Any:
        self.update_params_from_kwargs(**kwargs)
        points = _polygon_points(self.radius, self.sides, start_angle=self._start_angle)
        img = _draw_polygon_image(points, self.color, linewidth=3, offset=self._offset)
        filepath = bch.gen_image_path("polygon")
        img.save(filepath, "PNG")
        self.polygon = str(filepath)
        self.area = (self.sides * (2 * self.radius * math.sin(math.pi / self.sides)) ** 2) / (
            4 * math.tan(math.pi / self.sides)
        )
        return super().__call__()


def example_result_image_over_time(run_cfg: bch.BenchRunCfg | None = None) -> bch.Bench:
    """ResultImage: Over Time Slider."""
    run_cfg = run_cfg or bch.BenchRunCfg()
    run_cfg.over_time = True
    benchable = PolygonRenderer()
    bench = benchable.to_bench(run_cfg)
    _base_time = datetime(2000, 1, 1)
    colors = ["red", "green", "blue"]
    offsets = [(0, 0), (15, -10), (-10, 15)]
    for i, radius in enumerate([0.3, 0.6, 0.9]):
        benchable.radius = radius
        benchable.color = colors[i]
        benchable._start_angle = i * 30.0
        benchable._offset = offsets[i]
        run_cfg.clear_cache = True
        run_cfg.clear_history = i == 0
        bench.plot_sweep(
            "Image Over Time",
            input_vars=["sides"],
            result_vars=["polygon"],
            run_cfg=run_cfg,
            time_src=_base_time + timedelta(seconds=i),
        )

    return bench


if __name__ == "__main__":
    bch.run(example_result_image_over_time, save=True, level=3)
