#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Deniz Yetki Alanı Verisi ve Kızıldeniz Krizinin Etkisi: GOMD Yetki Alanı Serileri, Marine Regions MEB Poligonları ve UNCTAD Hat Bağlantısallığı Üzerinde Sentetik Farkların Farkı (SDID) ve Placebo Testi (2019–2026)
Maritime Jurisdiction Data & the Red Sea Crisis: GOMD Jurisdiction Series, Marine Regions EEZ Polygons and Synthetic Difference-in-Differences (SDID) with Placebo Tests on UNCTAD Liner Connectivity (2019–2026)
==============================================================================
GOMD Python SDK — Gerçek veriyle yeniden üretilebilir vaka çalışması / Reproducible real-data case study
Google Colab Install: !pip install -q --upgrade gomd

Veri kaynakları / Data sources (hepsi GOMD sunucusundan canlı çekilir / all fetched live from the GOMD server):
  - mavi_vatan_official_jurisdiction_km2 — GOMD (seri yüklendiğinde)
  - mr_eez_area_km2 — VLIZ Marine Regions v12 MEB poligon alanları (hukuki sınır değildir)
  - UNCTAD_LSCI_MONTHLY — UNCTAD hat taşımacılığı bağlantısallık endeksi (ülke)

Not / Note: Bu betik sentetik veri üretmez. Bir seri sunucuda yoksa betik açık bir hata mesajıyla durur.
            This script never generates synthetic data. If a series is missing on the server, it stops with an explicit error.
"""

# ==============================================================================
# ADIM 0: GOMD Python SDK Kurulumu ve Canlı Veri Yardımcıları
# STEP 0: Install the GOMD Python SDK & Live Data Helpers
# ==============================================================================
import importlib
import os
import subprocess
import sys
import math
import json
from pathlib import Path
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

if hasattr(sys.stdout, "reconfigure"):
    try:
        sys.stdout.reconfigure(encoding="utf-8", errors="replace")
    except Exception:
        pass

_IN_COLAB = "google.colab" in sys.modules
_GOMD_WHEEL_URL = "https://gomd.pirireis.edu.tr/sdk/dist/gomd-2.0.1-py3-none-any.whl"
try:
    import gomd  # noqa: F401
    if _IN_COLAB:
        subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "--force-reinstall", "--no-cache-dir", _GOMD_WHEEL_URL])
except ImportError:
    subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", "--force-reinstall", "--no-cache-dir", _GOMD_WHEEL_URL])

import gomd
for _mod_name in list(sys.modules.keys()):
    if _mod_name == "gomd" or _mod_name.startswith("gomd."):
        importlib.reload(sys.modules[_mod_name])
import gomd
from gomd import GOMDClient

client = GOMDClient("https://gomd.pirireis.edu.tr")


def fetch_gomd_records(indicator: str, entity: str, period_from=None, period_to=None, limit: int = 50000) -> pd.DataFrame:
    """
    GOMD sunucusundan bir göstergenin TEK bir varlık (ülke/havza) için ham kayıtlarını çeker.
    Yalnız istenen varlığın kayıtları tutulur; sunucu başka bir varlık döndürürse kullanılmaz.
    Returns a DataFrame with columns: period (str), value (float).
    """
    rows = client.get_series(indicator=indicator, entity=entity, period_from=period_from,
                             period_to=period_to, limit=limit, as_df=False)
    keep = [r for r in rows if str(r.get("entity_code") or "") == entity and r.get("value") is not None]
    if not keep:
        raise RuntimeError(f"GOMD sunucusunda veri yok: indicator={indicator}, entity={entity}")
    df = pd.DataFrame({"period": [str(r["period"]) for r in keep], "value": [float(r["value"]) for r in keep]})
    df = df.drop_duplicates("period").sort_values("period").reset_index(drop=True)
    print(f"📡 [GOMD] {indicator:<44} | {entity:<18} | N={len(df):<6} ({df['period'].iloc[0][:10]} – {df['period'].iloc[-1][:10]})")
    return df


def fetch_gomd_annual_series(indicator: str, entity: str, period_from: int = 1900, period_to: int = 2100,
                             how: str = "mean", min_count: int = 1) -> dict:
    """
    Yıllık seri döndürür: {yıl: değer}. Kayıtlar yıllık değilse (aylık/günlük) yıl içi ortalama alınır
    ve yalnız en az `min_count` kaydı olan yıllar tutulur. Returns {year: value}.
    """
    df = fetch_gomd_records(indicator, entity)
    df["year"] = df["period"].str[:4].astype(int)
    df = df[(df["year"] >= period_from) & (df["year"] <= period_to)]
    g = df.groupby("year")["value"]
    agg = g.mean() if how == "mean" else g.last()
    cnt = g.count()
    out = {int(y): float(v) for y, v in agg.items() if cnt[y] >= min_count}
    if not out:
        raise RuntimeError(f"Seçilen dönemde veri yok: indicator={indicator}, entity={entity}")
    return dict(sorted(out.items()))


def fmt_p(p: float) -> str:
    """p değerini okunur biçimde yazar / readable p-value."""
    return "<1e-6" if p < 1e-6 else f"{p:.4f}"


print(f"✅ GOMD Python SDK Sürümü / Version : v{gomd.__version__}")
print(f"🌐 Canlı Veri Sunucusu / Server     : {client.base_url}")
print(f"🏛️ Kurum / Institution              : Pîrî Reis Üniversitesi & T.C. Çevre, Şehircilik ve İklim Değişikliği Bakanlığı Çevre Yönetimi Genel Müdürlüğü — GOMD (COP31 Türkiye)")

# ==============================================================================
# ADIM 1: Deniz yetki alanı verisi — GOMD'deki kaynaklar ve doğru kullanım
# STEP 1: Maritime jurisdiction data — what GOMD holds and how to use it correctly
# ==============================================================================
from gomd.stats import synthetic_did_ate

# 1a) Türkiye resmî deniz yetki alanı serisi (Mavi Vatan). Seri veritabanına yüklenmemişse adım bunu açıkça bildirir;
#     yerine sabit/varsayılan sayı KONMAZ.
try:
    mv = client.get_mavi_vatan_jurisdiction()
    mv_rows = len(mv) if hasattr(mv, "__len__") else 0
except Exception as exc:          # sunucu hatası durumunda da sayı uydurulmaz
    mv, mv_rows = None, 0
if mv_rows:
    print("\n🧭 Türkiye resmî deniz yetki alanı serisi (GOMD):")
    print(mv.to_string(index=False) if hasattr(mv, "to_string") else mv)
else:
    print("\n🧭 'mavi_vatan_official_jurisdiction_km2' serisi GOMD veritabanında henüz yok; bu adım veri yüklendiğinde kendiliğinden dolar.")

# 1b) Marine Regions (VLIZ) v12 MEB poligon alanları — sağlayıcının çizimi, durağan referans değer
MR = {
    "MRGID_5697": "Türkiye", "MRGID_5679": "Yunanistan", "MRGID_8376": "Kıbrıs", "MRGID_8490": "Mısır", "MRGID_8372": "Libya",
    "MRGID_8375": "İsrail", "MRGID_8374": "Lübnan", "MRGID_8373": "Suriye", "MRGID_5672": "Bulgaristan", "MRGID_5689": "Romanya",
    "MRGID_5678": "Gürcistan", "MRGID_64430": "Örtüşen talep: Mısır / Libya",
}
eez_rows = []
for code, name in MR.items():
    d = fetch_gomd_records("mr_eez_area_km2", code)
    eez_rows.append({"Kayıt": name, "MRGID": code.split("_")[1], "Poligon alanı (km²)": int(round(d["value"].iloc[-1]))})
print("\n🗺️ Marine Regions v12 MEB poligon alanları (Doğu Akdeniz ve Karadeniz kıyı devletleri):")
print(pd.DataFrame(eez_rows).to_string(index=False))
print("ℹ️  Bu poligonlar sağlayıcının (VLIZ) teknik çizimleridir; hukuki sınır değildir ve uyuşmazlık konusu alanlarda tarafların")
print("    resmî tutumlarını yansıtmaz. Uyuşmazlıklı ve ortak alanlar ayrı kayıt olarak gelir; ülke toplamına eklenemez.")
print("    Türkiye'nin resmî tutumu için GOMD gösterge notuna (mr_eez_area_km2) bakınız.")

# ==============================================================================
# ADIM 2: Sentetik farkların farkı (SDID) — Kızıldeniz krizinin hat bağlantısallığına etkisi
# STEP 2: Synthetic difference-in-differences (SDID) — effect of the Red Sea crisis on liner connectivity
# ==============================================================================
# Müdahale: Kasım 2023'te Kızıldeniz'de ticari gemilere saldırılar başladı; Aralık 2023'ten itibaren büyük hat
# işletmecileri Süveyş yerine Ümit Burnu'nu kullanmaya başladı. Sonuç değişkeni: UNCTAD LSCI (ülke, log).
# Kontrol havuzu: Süveyş güzergâhına doğrudan bağlı olmayan Amerika ve Doğu Asya-Pasifik ülkeleri.
TREATED = {"EGY": "Mısır", "TUR": "Türkiye", "GRC": "Yunanistan"}
DONORS = ["USA", "CAN", "MEX", "BRA", "PAN", "AUS", "JPN", "KOR", "TWN"]
QM = ("02", "05", "08", "11")       # 2006–2022 yalnız bu aylar yayımlandı; seri boyunca aynı aylar kullanılır
lsci = {}
for iso in list(TREATED) + DONORS:
    d = fetch_gomd_records("UNCTAD_LSCI_MONTHLY", iso)
    d = d[d["period"].str[5:7].isin(QM) & (d["period"] >= "2019-02")]
    lsci[iso] = pd.Series(np.log(d["value"].values), index=d["period"].str[:7].values)
common = sorted(set.intersection(*[set(s.index) for s in lsci.values()]))
pre = [p for p in common if p <= "2023-08"]
post = [p for p in common if p >= "2024-02"]           # 2023-11 geçiş dönemi olarak dışarıda bırakılır
print(f"\n📅 Ön dönem {pre[0]} – {pre[-1]} ({len(pre)} gözlem), son dönem {post[0]} – {post[-1]} ({len(post)} gözlem)")


def sdid_for(unit, donors, zeta=0.05):
    return synthetic_did_ate(
        treated_pre=[lsci[unit][p] for p in pre], treated_post=[lsci[unit][p] for p in post],
        control_matrix_pre=[[lsci[j][p] for p in pre] for j in donors],
        control_matrix_post=[[lsci[j][p] for p in post] for j in donors], ridge_zeta=zeta)


# Yerleştirme (placebo) testi: her kontrol ülkesi sanki müdahale görmüş gibi tahmin edilir
placebo = {j: sdid_for(j, [k for k in DONORS if k != j])["sdid_att_estimate"] for j in DONORS}
res, rows = {}, []
for iso, name in TREATED.items():
    r = sdid_for(iso, DONORS); res[iso] = r
    att = r["sdid_att_estimate"]
    rank_p = (1 + sum(abs(v) >= abs(att) for v in placebo.values())) / (1 + len(placebo))
    top = sorted(zip(DONORS, r["unit_weights_omega"]), key=lambda x: -x[1])[:3]
    rows.append({"Ülke": name, "SDID etkisi (log)": round(att, 3), "≈ %": round(100 * (math.exp(att) - 1), 1),
                 "Klasik DiD (log)": round(r["classic_did_estimate"], 3), "Ön dönem RMSPE": round(r["pre_treatment_rmspe"], 3),
                 "Placebo p": round(rank_p, 2), "En büyük ağırlıklar": ", ".join(f"{k} {w:.2f}" for k, w in top)})
print("\n🎯 Kızıldeniz krizi sonrası LSCI etkisi (SDID, log puan):")
print(pd.DataFrame(rows).to_string(index=False))
print("   Placebo kontrol etkileri: " + ", ".join(f"{k} {v:+.3f}" for k, v in placebo.items()))
sens = {iso: [sdid_for(iso, DONORS, z)["sdid_att_estimate"] for z in (0.05, 0.01, 0.005)] for iso in TREATED}
print("   Duyarlılık (ridge_zeta = 0,05 / 0,01 / 0,005): " + "; ".join(f"{TREATED[i]} " + " / ".join(f"{v:+.3f}" for v in s) for i, s in sens.items()))
# Kısa pencere karşılaştırması: son ön dönem gözleminden (2023-08) ilk iki son dönem gözlemine (2024-02, 2024-05) değişim.
# Uzun ön dönem eğilimlerinden (Mısır ve Türkiye'de 2022–2023 artışı) daha az etkilenir.
SW = ["2024-02", "2024-05"]
def short_change(iso):
    return float(np.mean([lsci[iso][p] for p in SW]) - lsci[iso]["2023-08"])
ctrl_sc = {j: short_change(j) for j in DONORS}
ctrl_mean = float(np.mean(list(ctrl_sc.values())))
print("\n⏱️ Kısa pencere (2023-08 → 2024 ilk yarısı), kontrol ortalamasına göre fark:")
for iso, name in TREATED.items():
    eff = short_change(iso) - ctrl_mean
    p_sw = (1 + sum(abs(v - ctrl_mean) >= abs(eff) for v in ctrl_sc.values())) / (1 + len(ctrl_sc))
    print(f"   {name:<11}: {eff:+.3f} log (≈ %{100 * (math.exp(eff) - 1):+.1f}), placebo p = {p_sw:.2f}")
print("   Ön dönem eğilimleri paralel değilse (Panel A–C), tüm son dönem ortalamasına dayanan SDID tahmini yanıltıcı olabilir;")
print("   krizin ilk etkisini kısa pencere daha iyi gösterir.")
print("ℹ️  Placebo p, etkinin kontrol ülkelerinde rastgele görülen etkilerden büyük olup olmadığını ölçer (9 kontrolle en küçük p = 0,10).")
print("    LSCI ağ bağlantısallığını ölçer, yük hacmini değil. Aynı dönemdeki başka gelişmeler (filo yeniden dağılımı, yeni")
print("    hatlar, ekonomik koşullar) etkiye karışmış olabilir; sonuç tek başına nedensellik kanıtı sayılmamalıdır.")

# ==============================================================================
# ADIM 3: 4 Panelli Görselleştirme / 4-panel figure
# ==============================================================================
fig, axes = plt.subplots(2, 2, figsize=(14, 9.5), dpi=120)
fig.patch.set_facecolor("#071324")
for ax in axes.flat:
    ax.set_facecolor("#0b1d36"); ax.tick_params(colors="#cbd5e1")
    for sp in ax.spines.values():
        sp.set_color("#1e3a5f")
    ax.grid(alpha=0.18, color="#64748b")
leg = dict(facecolor="#0f172a", edgecolor="#334155", labelcolor="#f8fafc", fontsize=8)
pal = {"EGY": "#fb923c", "TUR": "#f43f5e", "GRC": "#38bdf8"}
xd = pd.to_datetime(common)

ax1 = axes[0, 0]
for iso, name in TREATED.items():
    ax1.plot(xd, [math.exp(lsci[iso][p]) for p in common], color=pal[iso], lw=1.8, label=name)
don_mean = [np.mean([math.exp(lsci[j][p]) for j in DONORS]) for p in common]
ax1.plot(xd, don_mean, color="#94a3b8", lw=1.4, ls="--", label="Kontrol ülkeleri ortalaması")
ax1.axvline(pd.Timestamp("2023-11-01"), color="#e2e8f0", ls=":", lw=1.3, label="Kasım 2023")
ax1.set_ylabel("LSCI (Şubat 2023 ort. = 100)", color="#cbd5e1")
ax1.set_title("A) Hat bağlantısallığı: müdahale ve kontrol grupları", color="#f8fafc", fontweight="bold"); ax1.legend(**leg)


def plot_synth(ax, iso):
    r = res[iso]; w = np.array(r["unit_weights_omega"])
    synth = np.array([sum(w[k] * lsci[j][p] for k, j in enumerate(DONORS)) for p in common])
    shift = np.mean([lsci[iso][p] for p in pre]) - np.mean(synth[:len(pre)])
    ax.plot(xd, [lsci[iso][p] for p in common], color=pal[iso], lw=2, label=f"{TREATED[iso]} (gerçekleşen)")
    ax.plot(xd, synth + shift, color="#94a3b8", lw=1.6, ls="--", label="Sentetik kontrol (ön döneme hizalı)")
    ax.axvline(pd.Timestamp("2023-11-01"), color="#e2e8f0", ls=":", lw=1.3)
    ax.set_ylabel("log LSCI", color="#cbd5e1")
    ax.set_title(f"{'B' if iso == 'EGY' else 'C'}) {TREATED[iso]}: SDID etkisi {r['sdid_att_estimate']:+.3f} log (≈ %{100 * (math.exp(r['sdid_att_estimate']) - 1):+.0f})",
                 color="#f8fafc", fontweight="bold")
    ax.legend(**leg)


plot_synth(axes[0, 1], "EGY")
plot_synth(axes[1, 0], "TUR")

ax4 = axes[1, 1]
names = list(placebo) + list(TREATED)
vals = list(placebo.values()) + [res[i]["sdid_att_estimate"] for i in TREATED]
cols = ["#64748b"] * len(placebo) + [pal[i] for i in TREATED]
order = np.argsort(vals)
ax4.barh([names[i] for i in order], [vals[i] for i in order], color=[cols[i] for i in order])
ax4.axvline(0, color="#e2e8f0", lw=0.8)
ax4.set_xlabel("SDID etkisi (log LSCI)", color="#cbd5e1")
ax4.set_title("D) Placebo testi: kontrol ülkeleri (gri) ve müdahale ülkeleri", color="#f8fafc", fontweight="bold")

fig.suptitle("GOMD — Vaka Çalışması 5: Deniz yetki alanı verisi ve Kızıldeniz krizinin bağlantısallığa etkisi (SDID, gerçek veri)", color="#ffffff", fontsize=12.5, fontweight="bold")
plt.tight_layout()
fig.savefig("cs05_mavi_vatan_icj_delimitation_causal_sdid.png", dpi=140, bbox_inches="tight", facecolor=fig.get_facecolor())
plt.show()
