#!/usr/bin/env python3

import argparse
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime as dt
import json
import sys
import numpy as np

def adjust_spacing(arr, minimum_spacing):
    min_val = min(arr)
    mid_val = mid(arr)

    if min_val <= 5:
        idx = arr.index(min_val)
        min_val = 5
        arr[idx] = min_val

    if (mid_val - min_val) < minimum_spacing:
        idx = arr.index(mid_val)
        mid_val = min_val + minimum_spacing
        arr[idx] = mid_val

    arr = np.array(arr)
    reversed = sorted(arr, reverse=True)
    adjusted = reversed[0:1]
    for num in reversed[1:]:
        diff = adjusted[-1] - minimum_spacing
        adjusted.append(num if num < diff else diff)

    respaced = list(np.array(adjusted)[np.argsort(np.argsort(-arr))])

    return respaced

def mid(tuple_of_three):
    sorted_values = sorted(tuple_of_three)
    return sorted_values[1]

def annotate_callout(ctx, percent, text_y, color):
    ctx.annotate(f'{percent:0.2f}%',
                 xycoords=('axes fraction', 'data'),
                 textcoords='axes fraction',
                 xy=(1, percent),
                 xytext=(0.97, text_y),
                 fontsize=12,
                 backgroundcolor=color,
                 bbox=dict(boxstyle='round', edgecolor=color, facecolor=color, pad=0.4))

# Create an argument parser
parser = argparse.ArgumentParser(description="Generate a line chart from JSON data and save it as an SVG file.")
parser.add_argument("--output", required=True, help="Output SVG filename")
parser.add_argument("--title", required=True, help="Chart title")

# Parse the command-line arguments
args = parser.parse_args()

fontName = 'Avenir Next'

hsmall = {
    'family': fontName,
    'size': 8,
    'weight': 'light' }
hmedium = {
    'family':fontName,
    'size': 12,
    'weight': 'light' }
htitle = {
    'family':fontName,
    'size': 26,
    'weight': 'light' }
hsubtitle = {
    'family':fontName,
    'size': 14 }

title = args.title
output_filename = args.output
time_limit_days_ago = 10
width = 12
height = 7

# Read JSON data from stdin
try:
    data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print("Error parsing JSON input:", e)
    sys.exit(1)

# Sort data by datetime
data.sort(key=lambda x: x["datetime"])

today = dt.datetime.utcnow()
time_limit = today - dt.timedelta(days = time_limit_days_ago)

results = filter(lambda x: x["datetime"] > time_limit.isoformat(), data)
data = list(results)

# Extract percentage values from fn, line, and region
fn_percentages = [float(node["fn"].split()[0].replace("%", "")) for node in data]
ln_percentages = [float(node["line"].split()[0].replace("%", "")) for node in data]

percentages = [fn_percentages, ln_percentages]

# Convert datetime strings to datetime objects
datetimes = [dt.datetime.fromisoformat(node["datetime"][:-6]) for node in data]
line_colors = ["#106A77","#50486C"]
labels = ["Function","Line"]

# Create a time series plot
latest = (fn_percentages[-1], ln_percentages[-1])

perc_max = max(max(fn_percentages), max(ln_percentages))
perc_max = min(100, perc_max + 10)
perc_min = min(min(fn_percentages), min(ln_percentages))
perc_min = max(0, perc_min - 10)

perc_range = (perc_max / 100) - (perc_min / 100)
normalised = [(perc - perc_min) / perc_range for perc in latest]
text_y = [(perc / 100) for perc in adjust_spacing(normalised, 10)]

with plt.style.context('dark_background'):
    plt.rcParams['font.family'] = fontName
    plt.rcParams['font.size'] = 8
    plt.figure(figsize=(width, height))

    plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%b %d"))
    plt.gca().xaxis.set_major_locator(mdates.DayLocator(interval=1))

    for i in [0,1]:
        plt.plot(datetimes, percentages[i], label=labels[i], linewidth=2, color=line_colors[i])
        annotate_callout(plt, latest[i], text_y[i], line_colors[i])

    plt.xlabel(f"Last {time_limit_days_ago} Days", **hsubtitle)
    plt.ylabel("Coverage %",**hsmall)
    plt.title(f"{title}", **htitle)

    plt.ylim([max(0, perc_min - 10), min(100, perc_max + 10)])

    plt.legend(frameon=False)

    plt.grid(which="Major", color="#444")
    plt.grid(which="Minor", color="#333")
    plt.box(False)

    # Save the plot directly as SVG without converting text to paths
    plt.savefig(output_filename, format="svg")

# Optionally, display a message indicating that the SVG file has been saved
print(f"Line chart saved as {output_filename}")
