import os
from pathlib import Path
from subprocess import run
from sys import argv
from time import time_ns

from rich.console import Console
from rich.table import Table

here = Path(__file__).parent

ignored_tasks = []

compare_with = ""
if len(argv) > 1:
    compare_with = Path(argv[1]).read_text(encoding="utf-8").strip()
    compare_with = {
        (line.split(",")[0], float(line.split(",")[1]), int(line.split(",")[2]))
        for line in compare_with.splitlines()[1:]
    }
    print(compare_with)


def avg(numbers: list[float]):
    return sum(numbers) / len(numbers)


end = 0
start = 0

if not Path("timings.log").exists():
    start = time_ns()
    result = run(
        ["just", "schedule-hell", here.parent / "out.mp4", "--duration 5", "--resolution 320"],
        capture_output=True,
        env=os.environ | {"RUST_LOG": "debug", "RUST_BACKTRACE": "full"},
    )
    end = time_ns()

    Path("timings.log").write_bytes(result.stdout + result.stderr)

timings = [
    line.split(" took ")
    for line in Path("timings.log").read_text(encoding="utf-8").splitlines()
    if " took " in line
]


def parse_duration(duration_string: str) -> float:
    if " " in duration_string:
        return sum(parse_duration(part) for part in duration_string.split(" "))
    try:
        figure = float(duration_string.strip("msµ"))
    except ValueError:
        return None

    if "µs" in duration_string:
        return figure * 1e-3
    if "ms" in duration_string:
        return figure
    if "s" in duration_string:
        return figure * 1e3
    else:
        return figure

    raise ValueError(f"Duration string {duration_string!r} has unsupported unit")


timings = [
    (label.split("] ")[1], parse_duration(timing))
    for label, timing in timings
    if parse_duration(timing)
]

per_function: dict[str, list[float]] = {function: [] for function, _ in timings}

for function, timing in timings:
    per_function[function].append(timing)

averages: list[tuple[str, float, int]] = [
    (function, avg(timings), len(timings)) for function, timings in per_function.items()
] + [
    ("_Total_", (end - start) / 1e6, 1),
]

averages.sort(key=lambda item: item[1])

header = ["Tâche", "Durée [ms]", "#"]

if compare_with:
    formatted_results = []
    for function, timing_after, count_after in averages:
        if function not in {function for function, _, _ in compare_with}:
            continue
        timing_before = next(
            (timing for fn, timing, _ in compare_with if fn == function),
            None,
        )
        count_before = next(
            (count for fn, _, count in compare_with if fn == function),
            None,
        )
        if timing_before is None or count_before is None:
            continue
        if function in ignored_tasks:
            continue

        formatted_results.append(
            [
                function,
                f"{timing_after:.3f}",
                f"{timing_before:.3f}",
                (
                    f"{timing_after - timing_before:+.3f}"
                    if f"{timing_after - timing_before:.3f}" != "-0.000"
                    else "±0"
                ),
                f"{count_after}",
                f"{count_before}",
                (
                    f"{count_after - count_before:+}"
                    if count_after != count_before
                    else "±0"
                ),
            ]
        )

    header = [
        "Tâche",
        "Durée [ms]",
        "Durée [ms] avant",
        "Différence [±ms]",
        "# après",
        "# avant",
        "Différence",
    ]
else:
    formatted_results = [
        [function, f"{timing:.3f}", f"{count}"] for function, timing, count in averages
    ]


def to_csv(lists: list[list[str]]):
    return "\r\n".join(
        ",".join(cell.replace(",", "_") for cell in line) for line in lists
    )


table = Table(*header)
for row in formatted_results:
    table.add_row(*row)
Console().print(table)

Path("results.csv").write_text(
    to_csv(
        [
            header,
            *[
                [task, *things]
                for task, *things in formatted_results
                if task not in ignored_tasks
            ],
        ]
    ),
    encoding="utf8",
)
