#!/usr/bin/env catnip
# Analyse comparative des températures globales (GISTEMP vs GCAG)
# Dataset: anomalies annuelles moyennes, deux sources indépendantes
# Sources: NASA GISTEMP (1880-2023) + NOAA GCAG (1850-2024)
#   https://github.com/datasets/global-temp

numpy = import('numpy')
import('pathlib', 'Path')

# Chargement des données (3 colonnes: Source, Year, Mean)

data_dir = Path(META.file).parent / "data"
csv_path = str(data_dir / "global-temp_annual.csv")
sources = numpy.genfromtxt(csv_path, delimiter=",", skip_header=1, usecols=0, dtype="U10")
years_all = numpy.genfromtxt(csv_path, delimiter=",", skip_header=1, usecols=1)
means_all = numpy.genfromtxt(csv_path, delimiter=",", skip_header=1, usecols=2)

# Séparation par source

gi_mask = numpy.char.equal(sources, "GISTEMP")
gc_mask = numpy.char.equal(sources, "gcag")

gi_years = years_all[gi_mask]
gi_means = means_all[gi_mask]
gc_years = years_all[gc_mask]
gc_means = means_all[gc_mask]

print("⇒ Dataset Annual Temperature Anomalies")
print(f"  GISTEMP: {int(gi_years[0])}-{int(gi_years[-1])} ({len(gi_years)} années)")
print(f"  GCAG:    {int(gc_years[0])}-{int(gc_years[-1])} ({len(gc_years)} années)")

# Statistiques par source

struct SourceStats {
    name; mean; std; min_val; max_val

    display(self) => {
        print(f"  {self.name}")
        print(f"    Moyenne:    {self.mean} °C")
        print(f"    Écart-type: {self.std} °C")
        print(f"    Plage:      [{self.min_val}, {self.max_val}] °C")
    }
}

make_stats = (name, data) => {
    SourceStats(
        name,
        round(numpy.mean(data), 3),
        round(numpy.std(data), 3),
        round(numpy.min(data), 3),
        round(numpy.max(data), 3),
    )
}

print()
print("⇒ Statistiques par source")
make_stats("GISTEMP", gi_means).display()
make_stats("GCAG", gc_means).display()

# Divergence entre sources (période commune 1880-2023)

gi_common = gi_means
gc_common_mask = numpy.logical_and(
    numpy.greater_equal(gc_years, gi_years[0]),
    numpy.less_equal(gc_years, gi_years[-1]),
)
gc_common = gc_means[gc_common_mask]
common_years = gi_years

divergence = numpy.subtract(gi_common, gc_common)

print()
print(f"⇒ Divergence GISTEMP - GCAG ({int(common_years[0])}-{int(common_years[-1])})")
print(f"  Divergence moyenne:  {round(numpy.mean(divergence), 4)} °C")
abs_div = numpy.abs(divergence)
print(f"  Divergence max:      {round(numpy.max(abs_div), 4)} °C")
print(f"  Année de max écart:  {int(common_years[numpy.argmax(abs_div)])}")

# Analyse par période via struct

struct Period {
    start; end; gi_mean; gc_mean; diff

    display(self) => {
        f"  {self.start}-{self.end} : GI={self.gi_mean} / GC={self.gc_mean} (Δ {self.diff})"
    }
}

period_stats = (start, end) => {
    gi_m = numpy.logical_and(numpy.greater_equal(gi_years, start), numpy.less_equal(gi_years, end))
    gc_m = numpy.logical_and(numpy.greater_equal(gc_years, start), numpy.less_equal(gc_years, end))
    gi_val = round(numpy.mean(gi_means[gi_m]), 3)
    gc_val = round(numpy.mean(gc_means[gc_m]), 3)
    Period(start, end, gi_val, gc_val, round(gi_val - gc_val, 3))
}

periods = list(
    period_stats(1880, 1920),
    period_stats(1921, 1960),
    period_stats(1961, 2000),
    period_stats(2001, 2023),
)

print()
print("⇒ Évolution par période (GISTEMP vs GCAG)")
periods.[(p) => { print(p.display()) }]

# Années extrêmes (GISTEMP comme référence)

sorted_idx = numpy.argsort(gi_means)

print()
print("⇒ Top 5 années les plus chaudes (GISTEMP)")
top5 = numpy.flip(sorted_idx[-5:])
for i in top5 {
    print(f"  {int(gi_years[i])} : {round(gi_means[i], 3)} °C")
}

print()
print("⇒ Top 5 années les plus froides (GISTEMP)")
bottom5 = sorted_idx[:5]
for i in bottom5 {
    print(f"  {int(gi_years[i])} : {round(gi_means[i], 3)} °C")
}

# Classification des anomalies par match (moyenne des deux sources)

classify = (value) => {
    match True {
        _ if value > 0.5  => { "forte positive" }
        _ if value > 0    => { "positive" }
        _ if value < -0.3 => { "forte négative" }
        _ if value < 0    => { "négative" }
        _                 => { "neutre" }
    }
}

print()
print("⇒ Classification récente (moyenne des sources)")
nc = len(common_years)
for i in range(nc - 5, nc) {
    avg = round((gi_common[i] + gc_common[i]) / 2, 3)
    label = classify(avg)
    print(f"  {int(common_years[i])} : {avg} °C → {label}")
}

# Tendances linéaires comparées

linear_slope = (xs, ys) => {
    x_mean = numpy.mean(xs)
    y_mean = numpy.mean(ys)
    xc = numpy.subtract(xs, x_mean)
    yc = numpy.subtract(ys, y_mean)
    numpy.sum(numpy.multiply(xc, yc)) / numpy.sum(numpy.power(xc, 2))
}

gi_slope = linear_slope(gi_years, gi_means)
gc_slope = linear_slope(gc_years, gc_means)

print()
print("⇒ Tendances linéaires")
print(f"  GISTEMP: {round(gi_slope * 100, 3)} °C/siècle")
print(f"  GCAG:    {round(gc_slope * 100, 3)} °C/siècle")

gi_intercept = numpy.mean(gi_means) - gi_slope * numpy.mean(gi_years)
print(f"  Projection GISTEMP 2050: {round(gi_slope * 2050 + gi_intercept, 2)} °C")
print(f"  Projection GISTEMP 2100: {round(gi_slope * 2100 + gi_intercept, 2)} °C")

# Moyenne mobile comparée (fenêtre de 10 ans)

window = 10
kernel = numpy.ones(window) / window
gi_ma = numpy.convolve(gi_means, kernel, mode="valid")
gc_ma = numpy.convolve(gc_means, kernel, mode="valid")

print()
print(f"⇒ Moyenne mobile ({window} ans)")
print(f"  GISTEMP dernière valeur: {round(gi_ma[-1], 3)} °C")
print(f"  GCAG dernière valeur:    {round(gc_ma[-1], 3)} °C")

# Broadcasting: conversion en Fahrenheit

gi_f = gi_common * 1.8
gc_f = gc_common * 1.8

print()
print("⇒ Anomalies récentes en Fahrenheit")
for i in range(nc - 4, nc) {
    print(f"  {int(common_years[i])} : GI={round(gi_f[i], 3)} / GC={round(gc_f[i], 3)} °F")
}

# Comptage: années au-dessus du seuil

threshold = 0.5
gi_above = int(numpy.sum(numpy.greater(gi_means, threshold)))
gc_above = int(numpy.sum(numpy.greater(gc_means, threshold)))
gi_first = int(gi_years[numpy.argmax(numpy.greater(gi_means, threshold))])
gc_first = int(gc_years[numpy.argmax(numpy.greater(gc_means, threshold))])

print()
print(f"⇒ Années avec anomalie > {threshold} °C")
print(f"  GISTEMP: {gi_above} années (première: {gi_first})")
print(f"  GCAG:    {gc_above} années (première: {gc_first})")