
import os

# Paths are resolved relative to this script so the package is self-contained.
_HERE = os.path.dirname(os.path.abspath(__file__))
DATA = os.path.normpath(os.path.join(_HERE, "..", "..", "data"))

"""E) 207-ornek refit  F) bootstrap theta-C korelasyonu  I) model (c) tersine muhendislik"""
import csv, numpy as np


lat, bw = {}, {}
for r in csv.DictReader(open(os.path.join(DATA, "latency_210.csv"), encoding="utf-8-sig")):
    lat[(int(r["qIdx"]), int(float(r["B_Mbps"])), int(r["trial"]))] = float(r["latency_ms"])
for r in csv.DictReader(open(os.path.join(DATA, "latency_trials_raw_210.csv"),
                             encoding="utf-8")):
    bw[(int(r["qIdx"]), int(r["target_Mbps"]), int(r["trial"]))] = (
        float(r["achieved_Mbps"]), int(r["valid_owd"]))

keys = sorted(lat)
q = np.array([k[0] for k in keys]); tgt = np.array([k[1] for k in keys])
tri = np.array([k[2] for k in keys])
L = np.array([lat[k] for k in keys])
b = np.array([bw[k][0] for k in keys])
valid = np.array([bw[k][1] == 1 for k in keys])


def X_full(bb, qq, C):
    cols = [np.ones_like(bb), bb, 1.0 / (C - bb)]
    for j in range(2, 8):
        cols.append((qq == j).astype(float))
    return np.column_stack(cols)


def fit(bb, qq, yy, coarse=True):
    lo = bb.max() + 1e-3
    grid = np.concatenate([np.linspace(lo, lo + 60, 300), np.linspace(lo + 60, 2500, 900)]) \
        if coarse else np.linspace(lo, 2500, 4000)
    best = None
    for C in grid:
        X = X_full(bb, qq, C)
        p, *_ = np.linalg.lstsq(X, yy, rcond=None)
        r = yy - X @ p; s = float(r @ r)
        if best is None or s < best[0]:
            best = (s, C, p)
    s, C, p = best
    step = 1.0
    for _ in range(50):
        moved = False
        for c2 in (C - step, C + step):
            if c2 <= lo: continue
            X = X_full(bb, qq, c2)
            pp, *_ = np.linalg.lstsq(X, yy, rcond=None)
            r = yy - X @ pp; ss = float(r @ r)
            if ss < s: s, C, p, moved = ss, c2, pp, True
        if not moved:
            step /= 2
            if step < 1e-5: break
    return C, p


def met(y, yh):
    e = y - yh
    return np.mean(np.abs(e)), np.sqrt(np.mean(e**2)), 1 - np.sum(e**2)/np.sum((y-y.mean())**2)


print("=" * 76)
print("E) 207 ORNEKLE YENIDEN FIT  (imputed 3 deneme cikarilarak)")
print("=" * 76)
C0, p0 = fit(b, q, L)
m0 = met(L, X_full(b, q, C0) @ p0)
C1, p1 = fit(b[valid], q[valid], L[valid])
m1 = met(L[valid], X_full(b[valid], q[valid], C1) @ p1)
names = ["L0", "beta", "theta", "g2", "g3", "g4", "g5", "g6", "g7"]
v0 = list(p0[:3]) + list(p0[3:]); v1 = list(p1[:3]) + list(p1[3:])
print(f"  {'param':7s} {'M=210':>12s} {'M=207':>12s} {'fark':>10s}")
worst = 0
for n, a, bb2 in zip(names, v0, v1):
    d = abs(bb2 - a) / max(abs(a), 1e-9) * 100
    if n in ("L0", "beta", "theta"): worst = max(worst, d)
    print(f"  {n:7s} {a:12.4f} {bb2:12.4f} {d:9.2f}%")
dC = abs(C1 - C0) / C0 * 100
worst = max(worst, dC)
print(f"  {'C':7s} {C0:12.4f} {C1:12.4f} {dC:9.2f}%")
print(f"  {'MAE':7s} {m0[0]:12.3f} {m1[0]:12.3f} {abs(m1[0]-m0[0]):9.3f} ms")
print(f"  {'RMSE':7s} {m0[1]:12.3f} {m1[1]:12.3f} {abs(m1[1]-m0[1]):9.3f} ms")
print(f"  {'R2':7s} {m0[2]:12.4f} {m1[2]:12.4f} {abs(m1[2]-m0[2]):9.4f}")
print(f"\n  -> Z (L0,beta,theta,C icin en buyuk goreli degisim) = {worst:.1f}%")
print(f"  -> W (MAE degisimi) = {abs(m1[0]-m0[0]):.3f} ms, RMSE {abs(m1[1]-m0[1]):.3f} ms, "
      f"R2 {abs(m1[2]-m0[2]):.4f}")

print()
print("=" * 76)
print("F) HUCRE BOOTSTRAP (1000 replika), theta-C korelasyonu + %95 GA")
print("=" * 76)
rng = np.random.default_rng(42)
cells = {}
for i, k in enumerate(keys):
    cells.setdefault((k[0], k[1]), []).append(i)
cell_idx = [np.array(v) for v in cells.values()]
TH, CC, L0s, BE = [], [], [], []
G = [[] for _ in range(6)]
for rep in range(1000):
    sel = np.concatenate([c[rng.integers(0, len(c), len(c))] for c in cell_idx])
    try:
        Cb, pb = fit(b[sel], q[sel], L[sel], coarse=True)
    except Exception:
        continue
    L0s.append(pb[0]); BE.append(pb[1]); TH.append(pb[2]); CC.append(Cb)
    for j in range(6): G[j].append(pb[3 + j])
TH, CC = np.array(TH), np.array(CC)
r = np.corrcoef(TH, CC)[0, 1]
print(f"  gecerli replika: {len(TH)}")
print(f"  corr(theta, C) = {r:+.3f}   (log-olcekte {np.corrcoef(np.log(TH), np.log(CC))[0,1]:+.3f})")
print()
print("  %95 bootstrap guven araliklari (makale Tablo 3 ile karsilastirma):")
ref = {"L0": (7.643, 9.554), "beta": (0.0271, 0.0339), "theta": (65.445, 1066.650),
       "C": (540.673, 673.624)}
for nm, arr in [("L0", np.array(L0s)), ("beta", np.array(BE)), ("theta", TH), ("C", CC)]:
    lo, hi = np.percentile(arr, [2.5, 97.5])
    rl, rh = ref[nm]
    print(f"    {nm:6s} [{lo:10.3f}, {hi:10.3f}]   makale [{rl:.3f}, {rh:.3f}]")
for j, nm in enumerate(["g2", "g3", "g4", "g5", "g6", "g7"]):
    lo, hi = np.percentile(np.array(G[j]), [2.5, 97.5])
    print(f"    {nm:6s} [{lo:10.3f}, {hi:10.3f}]")

print()
print("=" * 76)
print("I) MODEL (c), makalenin degerini hangi C uretiyor?")
print("=" * 76)
train = np.isin(tri, [1, 2, 3]); test = np.isin(tri, [4, 5])
target = (2.892, 3.633, 0.797)
best = None
for C in np.linspace(b[train].max() + 0.5, 3000, 6000):
    f = 1.0 / (C - b[train])
    X = np.column_stack([np.ones_like(f), f])
    p, *_ = np.linalg.lstsq(X, L[train], rcond=None)
    if p[0] < 0 or p[1] < 0:      # negatiflik kisiti
        continue
    ft = 1.0 / (C - b[test])
    m = met(L[test], p[0] + p[1] * ft)
    d = abs(m[0] - target[0]) + abs(m[1] - target[1])
    if best is None or d < best[0]:
        best = (d, C, p, m)
d, C, p, m = best
print(f"  L0,theta >= 0 kisitli en iyi eslesme:")
print(f"    C = {C:.2f} Mbps, L0 = {p[0]:.3f} ms, theta = {p[1]:.1f} ms*Mbps")
print(f"    test MAE={m[0]:.3f} RMSE={m[1]:.3f} R2={m[2]:.3f}   | makale 2.892/3.633/0.797")
print(f"    kalan fark: MAE {abs(m[0]-target[0]):.3f}, RMSE {abs(m[1]-target[1]):.3f}")
