"""Formato y escritura de las salidas.

Las salidas numéricas se escriben redondeadas a 10 decimales (protocolo §8), con saltos de línea
LF y UTF-8 sin BOM. El redondeo solo se aplica al escribir: los cálculos y los criterios (por
ejemplo DSR >= 0.95) usan siempre el valor de 64 bits.
"""

from __future__ import annotations

import csv
import hashlib
import json
import math
from collections.abc import Iterable, Sequence
from pathlib import Path

DECIMALS = 10  # protocolo §8


def fmt(value: float) -> str:
    """Texto con 10 decimales; el cero negativo y los negativos que redondean a 0 salen como 0.

    Un valor no finito (nan, inf) detiene el código: nunca se escribe como dato.
    """
    if not math.isfinite(value):
        raise ValueError(f"valor no finito en una salida: {value!r}")
    return f"{round(value, DECIMALS) + 0.0:.{DECIMALS}f}"


def fmt_bool(value: bool) -> str:
    return "true" if value else "false"


def write_csv(path: Path, header: Sequence[str], rows: Iterable[Sequence[object]]) -> None:
    """Escribe un CSV con encabezado; cada celda ya debe venir como texto o como entero."""
    with path.open("w", newline="", encoding="utf-8") as handle:
        writer = csv.writer(handle, lineterminator="\n")
        writer.writerow(header)
        writer.writerows(rows)


def write_json(path: Path, payload: object) -> None:
    text = json.dumps(payload, indent=2, ensure_ascii=False, sort_keys=True) + "\n"
    path.write_bytes(text.encode("utf-8"))


def sha256_of(path: Path) -> str:
    return hashlib.sha256(path.read_bytes()).hexdigest()
