"""Maak verstrekte synthetische E49-bestanden; geen weer- of meetdownload.
Python 3.13.1, NumPy 2.4.0; alle tijden vaste UTC+1, seed uit config.
CSV-machinenotatie heeft een punt; de cursus toont een decimale komma.
"""
import csv
import json
import math
from datetime import datetime, timedelta, timezone
from pathlib import Path
import numpy as np


def maak(config):
    rng = np.random.default_rng(config["seed"])
    tz = timezone(timedelta(hours=1))
    start = datetime(2021, 3, 8, tzinfo=tz)
    clouds = [.35, .24, .95, .82, .6, .3, .7]
    week = []
    for h in range(168):
        d, u = divmod(h, 24)
        licht = max(0, math.sin(math.pi*(u+.5-7)/11))
        if not 7 <= u+.5 <= 18:
            licht = 0
        irr = 720*clouds[d]*licht
        tout = 5+4*math.sin(2*math.pi*(u+.5-9)/24)
        tout += [-1, -2, 1, 2, 0, -1, 1][d]
        wind = 350+180*math.sin(2*math.pi*h/37)
        # Middelpunten van uren; tussen uren stukconstant.
        week.append({"tijd": (start+timedelta(hours=h)).isoformat(),
            "buiten_C": round(tout, 6), "straling_W_m2": round(irr, 6),
            "pv12_W": round(1400*irr/1000*.97, 6),
            "pv48_W": round(4200*irr/1000*.97, 6),
            "wind48_W": round(wind, 6),
            "b12_C": 12, "b48_C": 15,
            "nft_opname_L_d": 3.6, "nft_verdamping_L_d": .7})
    # 219 historische doel-dagen + de 7 weekdagen. Bij ieder doel is
    # de prognose om 20:00 op de vorige dag beschikbaar. Het gerealiseerde
    # label hieronder is een apart, transparant synthetisch dagdatamodel.
    first = datetime(2020, 8, 1, tzinfo=tz)
    archief, vorig_D, vorig_P = [], [], []
    for i in range((start-first).days+7):
        dag = first+timedelta(days=i)
        seizoen = math.cos(2*math.pi*(dag.timetuple().tm_yday-200)/365)
        T = 11+8*seizoen+rng.normal(0, 2)
        sun = max(.05, 2.4+1.8*seizoen+rng.normal(0, .8))
        if dag >= start:
            r = week[24*(dag-start).days:24*((dag-start).days+1)]
            T = np.mean([a["buiten_C"] for a in r])
            sun = sum(a["pv48_W"] for a in r)/(4200*.97)
        tf = T+rng.normal(0, 1.8)
        sf = max(.05, sun+rng.normal(0, .65))
        D = 5.4+.3*max(12-T, 0)+.018*max(3-T, 0)**2
        D += rng.normal(0, .18)
        P = 4.2*.97*sun
        # Bij het planmoment gisteren 20:00 is gisteren nog niet volledig.
        # De laatst volledig gekende kalenderdag is doel-dag minus twee.
        archief.append({"plan_tijd": (dag-timedelta(hours=4)).isoformat(),
            "doel_dag": dag.date().isoformat(),
            "prognose_T_C": round(tf, 6),
            "prognose_zonuren": round(sf, 6),
            "gerealiseerd_T_C": round(float(T), 6),
            "gerealiseerde_zonuren": round(float(sun), 6),
            "vraag_ref_kWh": round(D, 6), "pv48_kWh": round(P, 6),
            "laatste_complete_vraag_kWh": round(vorig_D[-2], 6) if i >= 2 else "",
            "laatste_complete_pv48_kWh": round(vorig_P[-2], 6) if i >= 2 else ""})
        vorig_D.append(D)
        vorig_P.append(P)
    return week, archief


def schrijf_csv(pad, rijen):
    with pad.open("w", encoding="utf-8", newline="") as f:
        w = csv.DictWriter(f, list(rijen[0]), lineterminator="\n")
        w.writeheader()
        w.writerows(rijen)


if __name__ == "__main__":
    root = Path(__file__).resolve().parent
    c = json.loads((root/"config.json").read_text(encoding="utf-8"))
    week, archief = maak(c)
    schrijf_csv(root/"week_uur.csv", week)
    schrijf_csv(root/"forecast_archief.csv", archief)
    print(len(week), "weekuren;", len(archief), "doel-dagen; UTC+1 vast")
