#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Marmara Denizi, Türk Boğazları ve Karadeniz: Yüzey Isınması, 2021 Müsilaj Yılının Bahar Koşulları, Ege–Karadeniz Sıcaklık Farkı ve BGC-Argo Oksijen/Klorofil (1993–2025)
Sea of Marmara, Turkish Straits & Black Sea: Surface Warming, Spring Conditions of the 2021 Mucilage Year, Aegean–Black Sea Temperature Contrast & BGC-Argo Oxygen/Chlorophyll (1993–2025)
==============================================================================
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):
  - nasa_merra2_daily_sst_skin_temp_c, nasa_merra2_daily_wind_10m_max_ms — NASA POWER / MERRA-2 günlük yeniden analiz (Marmara, İstanbul ve Çanakkale Boğazı, Ege)
  - noaa_oisst_area_mean_daily_v1 — NOAA OISST v2.1 (SST_BLACKSEA_BOX, SST_AEGEAN_BOX)
  - omi_rim_current_index — Copernicus Marine OMI, Karadeniz kenar akıntısı endeksi
  - argo_doxy_surface, argo_chla_surface — BGC-Argo yüzey oksijeni ve klorofil-a (SEA_BLACKSEA)

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: Marmara Denizi ve Boğazlar — günlük yüzey sıcaklığı ve rüzgâr (NASA MERRA-2 yeniden analizi, 1996–2025)
# STEP 1: Sea of Marmara & Straits — daily skin temperature and wind (NASA MERRA-2 reanalysis, 1996–2025)
# ==============================================================================
from gomd.stats import mann_kendall_sen, pettitt_changepoint, transfer_entropy_causal

SITES = {
    "BASIN_MARMARA_SEA": "Marmara Denizi",
    "STRAIT_BOSPHORUS": "İstanbul Boğazı",
    "STRAIT_DARDANELLES": "Çanakkale Boğazı",
    "BASIN_AEGEAN_SEA": "Ege Denizi",
}


def daily_series(indicator, entity):
    d = fetch_gomd_records(indicator, entity)
    return pd.Series(d["value"].values, index=pd.to_datetime(d["period"].str[:10])).sort_index()


sst = {code: daily_series("nasa_merra2_daily_sst_skin_temp_c", code) for code in SITES}
wind_marmara = daily_series("nasa_merra2_daily_wind_10m_max_ms", "BASIN_MARMARA_SEA")

annual = {code: s.groupby(s.index.year).mean() for code, s in sst.items()}
annual = {code: a[s.groupby(s.index.year).count() >= 360] for (code, a), s in zip(annual.items(), sst.values())}
rows = []
for code, name in SITES.items():
    a = annual[code]; mk = mann_kendall_sen(a.values.tolist(), t=a.index.tolist())
    rows.append({"Yer": name, "Yıllar": f"{a.index.min()}–{a.index.max()}", "Ortalama (°C)": round(a.mean(), 2),
                 "Sen eğimi (°C/10 yıl)": round(mk["theil_sen_slope"] * 10, 3), "p": fmt_p(mk["p_value"])})
print("\n🌡️ Yıllık ortalama yüzey (skin) sıcaklığı, MERRA-2 yeniden analizi:")
print(pd.DataFrame(rows).to_string(index=False))

# ==============================================================================
# ADIM 2: Bahar koşulları ve 2021 müsilaj yılı — Nisan–Haziran sıcaklık anomalisi ve sakin gün sayısı
# STEP 2: Spring conditions & the 2021 mucilage year — Apr–Jun temperature anomaly and calm days
# ==============================================================================
# Not: 2021 ilkbaharında Marmara'da yaygın müsilaj görüldü (kamuya açık resmi kayıtlar). Literatür, yüksek su sıcaklığı
# ve zayıf rüzgârın (az karışım) olası etkenler arasında olduğunu belirtir. Aşağıdaki hesap bu iki koşulu yalnız
# GÖZLEMSEL/YENİDEN ANALİZ verisiyle tarif eder; müsilajı ölçmez ve nedensellik iddia etmez.
m = sst["BASIN_MARMARA_SEA"]
spring = m[(m.index.month >= 4) & (m.index.month <= 6)]
spring_mean = spring.groupby(spring.index.year).mean()
clim = spring_mean[(spring_mean.index >= 1996) & (spring_mean.index <= 2020)].mean()
spring_anom = (spring_mean - clim).round(3)
w = wind_marmara[(wind_marmara.index.month >= 4) & (wind_marmara.index.month <= 6)]
calm_days = (w < 5.0).groupby(w.index.year).sum()          # günlük en yüksek 10 m rüzgâr < 5 m/s
df_spring = pd.DataFrame({"bahar_sst_anomalisi_c": spring_anom, "sakin_gun": calm_days}).dropna()
rank_anom = int(df_spring["bahar_sst_anomalisi_c"].rank(ascending=False)[2021]) if 2021 in df_spring.index else None
rank_calm = int(df_spring["sakin_gun"].rank(ascending=False, method="min")[2021]) if 2021 in df_spring.index else None
print(f"\n🟫 2021 Nisan–Haziran Marmara sıcaklık anomalisi: {df_spring.loc[2021, 'bahar_sst_anomalisi_c']:+.2f} °C "
      f"(1996–2020 ortalamasına göre; {len(df_spring)} yıl içinde {rank_anom}. en sıcak)")
# Kış (Aralık–Mart) koşulları: kış yılı, Mart'ın ait olduğu yıla atanır (ör. Ara 2020–Mar 2021 → 2021)
wm = m[(m.index.month == 12) | (m.index.month <= 3)]
wy = np.where(wm.index.month == 12, wm.index.year + 1, wm.index.year)
winter = wm.groupby(wy).mean()
winter = winter[(winter.index >= 1997) & (winter.index <= 2025)]
w_anom = winter - winter[(winter.index >= 1997) & (winter.index <= 2020)].mean()
w_rank = int(w_anom.rank(ascending=False)[2021])
print(f"❄️  2021 kışı (Ara 2020–Mar 2021) Marmara sıcaklık anomalisi: {w_anom[2021]:+.2f} °C ({len(w_anom)} kış içinde {w_rank}. en sıcak)")
print(f"🍃 2021 Nisan–Haziran sakin gün sayısı (rüzgâr maks. < 5 m/s): {int(df_spring.loc[2021, 'sakin_gun'])} "
      f"({len(df_spring)} yıl içinde {rank_calm}. sırada)")

# ==============================================================================
# ADIM 3: Karadeniz — Ege sıcaklık farkı (NOAA OISST) ve Karadeniz kenar akıntısı (CMEMS OMI)
# STEP 3: Black Sea – Aegean temperature contrast (NOAA OISST) & Black Sea rim current (CMEMS OMI)
# ==============================================================================
oi = {}
for code in ("SST_BLACKSEA_BOX", "SST_AEGEAN_BOX"):
    d = fetch_gomd_records("noaa_oisst_area_mean_daily_v1", code)
    s = pd.Series(d["value"].values, index=pd.to_datetime(d["period"].str[:10]))
    g = s.groupby(s.index.year)
    oi[code] = g.mean()[g.count() >= 360]
contrast = (oi["SST_AEGEAN_BOX"] - oi["SST_BLACKSEA_BOX"]).dropna()
mk_c = mann_kendall_sen(contrast.values.tolist(), t=contrast.index.tolist())
rim = fetch_gomd_annual_series("omi_rim_current_index", "SEA_BLACKSEA")
print(f"\n🌊 Ege − Karadeniz yıllık SST farkı: {contrast.iloc[0]:.2f} °C ({contrast.index[0]}) → {contrast.iloc[-1]:.2f} °C ({contrast.index[-1]}); "
      f"Sen eğimi {mk_c['theil_sen_slope']*10:+.3f} °C/10 yıl (p = {fmt_p(mk_c['p_value'])})")
print("    (Negatif eğim Karadeniz'in Ege'den hızlı ısındığını gösterir.)")

# ==============================================================================
# ADIM 4: Karadeniz yüzey oksijeni ve klorofili (BGC-Argo, aylık)
# STEP 4: Black Sea surface oxygen & chlorophyll (BGC-Argo, monthly)
# ==============================================================================
doxy = fetch_gomd_records("argo_doxy_surface", "SEA_BLACKSEA")
chla = fetch_gomd_records("argo_chla_surface", "SEA_BLACKSEA")
for d in (doxy, chla):
    d["date"] = pd.to_datetime(d["period"].str[:7])
bio = pd.merge(doxy[["date", "value"]].rename(columns={"value": "doxy"}), chla[["date", "value"]].rename(columns={"value": "chla"}), on="date")
te = transfer_entropy_causal(bio["chla"].tolist(), bio["doxy"].tolist(), bins=3)
print(f"\n🫧 Karadeniz BGC-Argo: {len(bio)} ortak ay; korelasyon (klorofil, O₂) = {bio['chla'].corr(bio['doxy']):+.2f}; "
      f"transfer entropisi klorofil→O₂ = {te['transfer_entropy_x_to_y_bits']:.3f} bit")
print("    Argo şamandıraları her ay farklı noktalardan ölçer; aylık değerler havza ortalaması değil, o ayın şamandıra ortalamasıdır.")

# ==============================================================================
# ADIM 5: 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 = {"BASIN_MARMARA_SEA": "#f43f5e", "STRAIT_BOSPHORUS": "#22c55e", "STRAIT_DARDANELLES": "#f59e0b", "BASIN_AEGEAN_SEA": "#38bdf8"}

ax1 = axes[0, 0]
for code, name in SITES.items():
    ax1.plot(annual[code].index, annual[code].values, color=pal[code], lw=1.8, label=name)
ax1.set_ylabel("°C", color="#cbd5e1")
ax1.set_title("A) Yıllık ortalama yüzey sıcaklığı — MERRA-2", color="#f8fafc", fontweight="bold"); ax1.legend(**leg)

ax2 = axes[0, 1]
cols = ["#f43f5e" if y == 2021 else "#38bdf8" for y in df_spring.index]
ax2.bar(df_spring.index, df_spring["bahar_sst_anomalisi_c"], color=cols)
ax2.set_ylabel("Nisan–Haziran SST anomalisi (°C)", color="#cbd5e1")
ax2t = ax2.twinx(); ax2t.plot(df_spring.index, df_spring["sakin_gun"], color="#f59e0b", marker="o", lw=1.4, label="Sakin gün (rüzgâr < 5 m/s)")
ax2t.tick_params(colors="#fcd34d"); ax2t.set_ylabel("gün", color="#f59e0b")
ax2.set_title("B) Marmara bahar koşulları (kırmızı: 2021 müsilaj yılı)", color="#f8fafc", fontweight="bold"); ax2t.legend(loc="upper left", **leg)

ax3 = axes[1, 0]
ax3.plot(contrast.index, contrast.values, color="#a78bfa", marker="o", lw=1.8, label="Ege − Karadeniz SST farkı (°C)")
ax3.set_ylabel("°C", color="#a78bfa")
ax3t = ax3.twinx(); ry = sorted(rim)
ax3t.plot(ry, [rim[y] for y in ry], color="#22c55e", ls="--", lw=1.4, label="Karadeniz kenar akıntısı endeksi (CMEMS OMI)")
ax3t.tick_params(colors="#86efac")
ax3.set_title("C) Boğazların iki ucu: sıcaklık farkı ve kenar akıntısı", color="#f8fafc", fontweight="bold")
h1, l1 = ax3.get_legend_handles_labels(); h2, l2 = ax3t.get_legend_handles_labels(); ax3.legend(h1 + h2, l1 + l2, **leg)

ax4 = axes[1, 1]
ax4.plot(bio["date"], bio["doxy"], color="#38bdf8", lw=1.5, label="Yüzey O₂ (µmol/kg)")
ax4.set_ylabel("µmol/kg", color="#38bdf8")
ax4t = ax4.twinx(); ax4t.plot(bio["date"], bio["chla"], color="#22c55e", lw=1.3, label="Yüzey klorofil-a (mg/m³)")
ax4t.tick_params(colors="#86efac"); ax4t.set_ylabel("mg/m³", color="#22c55e")
ax4.set_title("D) Karadeniz yüzey oksijeni ve klorofili — BGC-Argo", color="#f8fafc", fontweight="bold")
h1, l1 = ax4.get_legend_handles_labels(); h2, l2 = ax4t.get_legend_handles_labels(); ax4.legend(h1 + h2, l1 + l2, **leg)

fig.suptitle("GOMD — Vaka Çalışması 4: Marmara Denizi, Türk Boğazları ve Karadeniz (gerçek veri)", color="#ffffff", fontsize=12.5, fontweight="bold")
plt.tight_layout()
fig.savefig("cs04_marmara_mucilage_eutrophication_acidification.png", dpi=140, bbox_inches="tight", facecolor=fig.get_facecolor())
plt.show()
