"""
Converts a SPARQL query JSON explanation file to a flamegraph.
Usage: python explanation_to_flamegraph.py explanation.json flamegraph.svg
"""
import json
import subprocess
from argparse import ArgumentParser
from pathlib import Path
from shutil import which
from tempfile import NamedTemporaryFile

parser = ArgumentParser(
    prog='OxigraphFlamegraph',
    description='Builds a flamegraph from the Oxigraph query explanation JSON format',
    epilog='Text at the bottom of help')
parser.add_argument('json_explanation', type=Path)
parser.add_argument('flamegraph_svg', type=Path)
args = parser.parse_args()


def trace_line(label: str, value: float):
    return f"{label} {int(value * 1_000_000)}"


with args.json_explanation.open('rt') as fp:
    explanation = json.load(fp)
trace = []
if "parsing duration in seconds" in explanation:
    trace.append(trace_line("parsing", explanation['parsing duration in seconds']))
if "planning duration in seconds" in explanation:
    trace.append(trace_line("planning", explanation['planning duration in seconds']))
already_used_names = {}


def add_to_trace(node, path):
    path = f"{path};{node['name'].replace(' ', '`')}"
    if path in already_used_names:
        already_used_names[path] += 1
        path = f"{path}`{already_used_names[path]}"
    else:
        already_used_names[path] = 0
    samples = node['duration in seconds'] - sum(child['duration in seconds'] for child in node.get("children", ()))
    if int(samples * 1_000_000) > 0:
        trace.append(trace_line(path, samples))
    for i, child in enumerate(node.get("children", ())):
        add_to_trace(child, path)


add_to_trace(explanation["plan"], 'eval')
inferno = which('inferno-flamegraph')
flamegraph_pl = which('flamegraph.pl')
if inferno:
    args.flamegraph_svg.write_text(
        subprocess.run([inferno], input='\n'.join(trace), stdout=subprocess.PIPE, text=True).stdout)
elif flamegraph_pl:
    with NamedTemporaryFile('w+t') as fp:
        fp.write('\n'.join(trace))
        fp.flush()
        args.flamegraph_svg.write_text(
            subprocess.run([flamegraph_pl, fp.name], stdout=subprocess.PIPE, text=True).stdout)
else:
    raise Exception(
        'This script requires either the inferno-flamegraph from https://github.com/jonhoo/inferno either the flamegraph.pl script from https://github.com/brendangregg/FlameGraph to be installed and be in $PATH.')