"""Synthetic raw export generator for 3 patients × 2 weeks × 5-min CGM data.

Produces 4 raw files in this directory:
  - synth_dexcom.csv       (Dexcom Clarity-like)
  - synth_libre.csv        (Libre LibreView-like)
  - synth_tandem.csv       (Tandem t:connect-like, includes pump basal/bolus/carb)
  - synth_medtronic.csv    (Medtronic CareLink-like)
"""

from __future__ import annotations
import csv
import math
import os
import random
from datetime import datetime, timedelta

random.seed(42)

HERE = os.path.dirname(os.path.abspath(__file__))
START = datetime(2026, 4, 1, 0, 0, 0)  # KST
DAYS = 14
INTERVAL_MIN = 5
SUBJECTS = ["SUBJ_01", "SUBJ_02", "SUBJ_03"]


def synth_glucose_series(subject_idx: int):
    """Realistic-ish 24h-cycling glucose with meals and noise."""
    points = []
    n = int(DAYS * 24 * 60 / INTERVAL_MIN)
    baseline = 130 + subject_idx * 8  # mg/dL
    amp = 35 + subject_idx * 5
    for i in range(n):
        ts = START + timedelta(minutes=i * INTERVAL_MIN)
        # Diurnal cycle (peak after meals)
        mod = math.sin(2 * math.pi * (i / (24 * 60 / INTERVAL_MIN)))
        meal_spike = 0
        hour = ts.hour + ts.minute / 60.0
        for meal_h, sp in [(7.5, 60), (12.5, 70), (18.5, 80)]:
            d = abs(hour - meal_h)
            if d < 2:
                meal_spike += sp * math.exp(-((d / 0.6) ** 2))
        noise = random.gauss(0, 8)
        glu = baseline + amp * mod + meal_spike + noise
        # Occasional hypos
        if random.random() < 0.005:
            glu = random.uniform(50, 68)
        # Occasional dropout (sensor gap)
        if random.random() < 0.01:
            continue
        glu = max(40, min(400, glu))
        points.append((ts, round(glu, 1)))
    return points


def write_dexcom():
    path = os.path.join(HERE, "synth_dexcom.csv")
    with open(path, "w", newline="") as f:
        w = csv.writer(f)
        w.writerow(["Index", "Timestamp (YYYY-MM-DDTHH:MM:SS)", "Event Type",
                    "Glucose Value (mg/dL)", "Patient Info"])
        idx = 1
        for s_idx, sid in enumerate(SUBJECTS):
            for ts, glu in synth_glucose_series(s_idx):
                w.writerow([idx, ts.strftime("%Y-%m-%dT%H:%M:%S"), "EGV", glu, sid])
                idx += 1
    return path


def write_libre():
    path = os.path.join(HERE, "synth_libre.csv")
    with open(path, "w", newline="") as f:
        w = csv.writer(f)
        w.writerow(["Device", "Serial Number", "Device Timestamp", "Record Type",
                    "Historic Glucose mg/dL", "Scan Glucose mg/dL", "Patient"])
        for s_idx, sid in enumerate(SUBJECTS):
            for ts, glu in synth_glucose_series(s_idx + 1):
                w.writerow(["Libre3", f"SN-{s_idx:04d}", ts.strftime("%Y-%m-%d %H:%M"),
                            "Historic", glu, "", sid])
    return path


def write_tandem():
    path = os.path.join(HERE, "synth_tandem.csv")
    with open(path, "w", newline="") as f:
        w = csv.writer(f)
        w.writerow(["DeviceTimestamp", "EventType", "BasalRate(U/hr)",
                    "BolusDelivered(U)", "CarbInput(g)", "GlucoseValue(mg/dL)",
                    "PatientID"])
        for s_idx, sid in enumerate(SUBJECTS):
            for ts, glu in synth_glucose_series(s_idx + 2):
                # basal mostly steady ~0.8 U/hr with diurnal modulation
                basal = round(0.8 + 0.2 * math.sin(2 * math.pi * ts.hour / 24.0), 2)
                bolus = ""
                carbs = ""
                if ts.hour in (7, 12, 18) and ts.minute == 30:
                    bolus = round(random.uniform(3, 8), 1)
                    carbs = random.choice([30, 45, 60, 75])
                w.writerow([ts.strftime("%Y-%m-%d %H:%M:%S"), "CGM", basal,
                            bolus, carbs, glu, sid])
    return path


def write_medtronic():
    path = os.path.join(HERE, "synth_medtronic.csv")
    with open(path, "w", newline="") as f:
        w = csv.writer(f)
        # Medtronic-like with separate Date / Time
        w.writerow(["Date", "Time", "Sensor Glucose (mg/dL)", "Basal Rate (U/h)",
                    "Bolus Volume Delivered (U)", "BWZ Carb Input (g)", "Patient"])
        for s_idx, sid in enumerate(SUBJECTS):
            for ts, glu in synth_glucose_series((s_idx + 1) % 3):
                basal = round(0.75 + 0.15 * math.sin(2 * math.pi * ts.hour / 24.0), 2)
                bolus = ""
                carbs = ""
                if ts.hour in (7, 12, 18) and ts.minute == 30:
                    bolus = round(random.uniform(3, 8), 1)
                    carbs = random.choice([30, 45, 60, 75])
                w.writerow([ts.strftime("%Y-%m-%d"), ts.strftime("%H:%M:%S"),
                            glu, basal, bolus, carbs, sid])
    return path


def generate_all():
    paths = [write_dexcom(), write_libre(), write_tandem(), write_medtronic()]
    return paths


if __name__ == "__main__":
    for p in generate_all():
        print(f"wrote: {p}")
