# Independent recomputation from the raw API responses: complete UTC days, 2023-trained seasonal and year-round windows, evaluated on 2024 and 2025.
import gzip, json, os, sys, datetime as dt
from collections import defaultdict
raw = sys.argv[1]
vals = {}
for f in sorted(os.listdir(raw)):
    for rec in json.load(gzip.open(os.path.join(raw, f)))['data']:
        t = dt.datetime.strptime(rec['from'], '%Y-%m-%dT%H:%MZ')
        a = rec['intensity'].get('actual')
        if t.year < 2023 or t.year > 2025 or a is None: continue
        if t in vals and vals[t] != a: raise SystemExit('contradictory duplicate %s' % t)
        vals[t] = a
days = defaultdict(dict)
for t, a in vals.items():
    days[t.date()][t.hour * 2 + t.minute // 30] = a
complete = {d: [v[i] for i in range(48)] for d, v in days.items() if len(v) == 48}
season = lambda d: {12: 'DJF', 1: 'DJF', 2: 'DJF', 3: 'MAM', 4: 'MAM', 5: 'MAM', 6: 'JJA', 7: 'JJA', 8: 'JJA'}.get(d.month, 'SON')
win = lambda day, s: sum(day[s:s + 6]) / 6
def pick(ds):
    return min(range(43), key=lambda s: (sum(win(complete[d], s) for d in ds) / len(ds), s))
train = [d for d in complete if d.year == 2023]
sel = {k: pick([d for d in train if season(d) == k]) for k in ('DJF', 'MAM', 'JJA', 'SON')}
g = pick(train)
fmt = lambda s: '%02d:%02d' % (s // 2, 30 * (s % 2))
print('2023 complete days', len(train), 'windows', {k: fmt(v) for k, v in sel.items()}, 'global', fmt(g))
for y in (2024, 2025):
    ds = sorted(d for d in complete if d.year == y)
    mid = sum(win(complete[d], 0) for d in ds) / len(ds)
    sea = sum(win(complete[d], sel[season(d)]) for d in ds) / len(ds)
    glo = sum(win(complete[d], g) for d in ds) / len(ds)
    worse = sum(win(complete[d], sel[season(d)]) > win(complete[d], 0) for d in ds)
    print(y, 'days', len(ds), 'midnight %.6f seasonal %.6f global %.6f' % (mid, sea, glo), 'seasonal vs midnight %.6f%%' % (100 * (mid - sea) / mid), 'global vs midnight %.6f%%' % (100 * (mid - glo) / mid), 'worse days', worse)
