#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
voyagermon degrau-0: Voyager 2, merged hourly (SPDF/COHO, NASA, público).

Fonte: https://spdf.gsfc.nasa.gov/pub/data/voyager/voyager2/merged/vy2_YYYY.asc
(1977–2024, horário; formato vy2mgd.txt). Licença NASA/SPDF aberta — ao
contrário do Kumamoto, o pacote É redistribuível.

Extrai canais com fill declarado no formato (999.999 etc.):
  B    col 7   |B| médio da hora (nT)        fill 999.999
  V    col 12  velocidade de bulk (km/s)     fill 9999.9
  dens col 15  densidade de prótons (n/cc)   fill 99.99999
  T    col 16  temperatura de prótons (K)    fill 9999999.
  lecp col 17  fluxo H 0,52–1,45 MeV         fill 9.999e+05  → guardado log10

Saídas em dados/:
  serie.csv.gz          ano,dia,hora,B,V,dens,T,log10_lecp  ("" = ausente)
  canal_<nome>.csv.gz   1 coluna, só amostras válidas, em ordem — p/ tube -pack
  presenca_<nome>.bin.gz bitmap 1 bit/hora da missão (custo da máscara de gaps)
"""
import csv, gzip, os
from pathlib import Path

AQUI = Path(__file__).parent
CACHE = Path(os.environ.get("VOYAGERMON_CACHE",
             "/private/tmp/claude-501/-Users-andreyandrade-Code-telemetria/"
             "c41544e1-f32d-4f5e-9af4-3f143c65e4aa/scratchpad/voyager"))
DADOS = AQUI / "dados"
ANOS = range(1977, 2025)

CANAIS = {          # nome -> (coluna 0-based, string de fill, log10?)
    "B":    (6,  "999.999",   False),
    "V":    (11, "9999.9",    False),
    "dens": (14, "99.99999",  False),
    "T":    (15, "9999999.",  False),
    "lecp": (16, "9.999e+05", True),
}


def main():
    DADOS.mkdir(exist_ok=True)
    import math
    linhas = []          # (ano, dia, hora, {canal: valor})
    for ano in ANOS:
        p = CACHE / f"vy2_{ano}.asc"
        if not p.exists():
            print(f"{ano}: ausente, pulando")
            continue
        for ln in p.read_text().splitlines():
            c = ln.split()
            if len(c) < 17:
                continue
            vals = {}
            for nome, (col, fill, uselog) in CANAIS.items():
                s = c[col]
                if s == fill:
                    continue
                v = float(s)
                if uselog:
                    if v <= 0:
                        continue
                    v = math.log10(v)
                vals[nome] = v
            linhas.append((int(c[0]), int(c[1]), int(c[2]), vals))
    linhas.sort(key=lambda r: (r[0], r[1], r[2]))

    with gzip.open(DADOS / "serie.csv.gz", "wt", newline="") as f:
        w = csv.writer(f)
        w.writerow(["ano", "dia", "hora"] + list(CANAIS))
        for ano, dia, hora, vals in linhas:
            w.writerow([ano, dia, hora] +
                       [f"{vals[n]:.6g}" if n in vals else "" for n in CANAIS])

    for nome in CANAIS:
        seq = [vals[nome] for _, _, _, vals in linhas if nome in vals]
        with gzip.open(DADOS / f"canal_{nome}.csv.gz", "wt") as f:
            for v in seq:
                f.write(f"{v:.6g}\n")
        # bitmap de presença: 1 bit por hora da missão, na ordem das linhas
        bits = bytearray((len(linhas) + 7) // 8)
        for i, (_, _, _, vals) in enumerate(linhas):
            if nome in vals:
                bits[i // 8] |= 1 << (i % 8)
        with gzip.open(DADOS / f"presenca_{nome}.bin.gz", "wb") as f:
            f.write(bytes(bits))
        print(f"{nome}: {len(seq):,} amostras válidas de {len(linhas):,} horas "
              f"({100*len(seq)/len(linhas):.1f}%)")


if __name__ == "__main__":
    main()
