# -*- coding: utf-8 -*-
"""
verificar_cadena.py — comprueba, SIN depender del sistema que la generó, que una exportación de la
cadena de registro de jornada está íntegra.

    python verificar_cadena.py cadena_registro_jornada_AAAAMMDD_HHMM.jsonl

Solo usa la librería estándar de Python 3. No se conecta a nada. Recalcula cada huella a partir del
contenido de cada registro y de la huella del anterior, como explica la primera línea del archivo.

Qué demuestra y qué no:
  · Si dice CORRECTA: ningún registro de la exportación ha sido modificado, quitado ni intercalado
    respecto a como se escribió, y la última huella es la que figura al final.
  · Para saber que la exportación es la de VERDAD (y no una cadena entera fabricada de nuevo), hay
    que comparar esa última huella con una tomada antes de forma independiente: la que va impresa en
    cada informe mensual en PDF, que se guarda fuera del servidor con su fecha.
"""
import sys
import json
import hashlib

VACIO = "0" * 64


def main(ruta):
    with open(ruta, "r", encoding="utf-8") as f:
        lineas = [l for l in f.read().splitlines() if l.strip()]
    if not lineas:
        print("Archivo vacío.")
        return 2
    cabecera = json.loads(lineas[0])
    campos_por_version = {int(k): v for k, v in cabecera["campos_por_version"].items()}
    print("Empresa:   %s" % cabecera.get("empresa"))
    print("Exportada: %s" % cabecera.get("exportada"))

    previo = VACIO
    problemas = []
    ids = []
    for n, linea in enumerate(lineas[1:], start=2):
        reg = json.loads(linea)
        hv = int(reg["hv"])
        campos = reg["campos"]
        if sorted(campos) != sorted(campos_por_version[hv]):
            problemas.append("línea %d: los campos no son los de la versión %d" % (n, hv))
        canon = json.dumps({k: campos.get(k) for k in campos_por_version[hv]},
                           sort_keys=True, ensure_ascii=False, separators=(",", ":"))
        esperado = hashlib.sha256((previo + "|" + canon).encode("utf-8")).hexdigest()
        if reg["hash_previo"] != previo:
            problemas.append("registro %s: no enlaza con el anterior (falta, sobra o se movió uno)"
                             % campos.get("id"))
        if reg["hash"] != esperado:
            problemas.append("registro %s: su contenido no corresponde a su huella (modificado)"
                             % campos.get("id"))
        ids.append(campos.get("id"))
        previo = reg["hash"]

    saltos = [b for a, b in zip(ids, ids[1:]) if b != a + 1]
    if ids and ids[0] != 1:
        problemas.append("la cadena no empieza en el registro 1")
    if saltos:
        problemas.append("faltan números de registro antes de: %s" % saltos[:10])

    print("Registros: %d" % len(ids))
    print("Última huella: %s" % previo)
    if problemas:
        print("\nCADENA NO VÁLIDA:")
        for p in problemas[:30]:
            print("  - " + p)
        return 1
    print("\nCADENA CORRECTA. Compara la última huella con la impresa en el informe mensual.")
    return 0


if __name__ == "__main__":
    if len(sys.argv) != 2:
        print(__doc__)
        sys.exit(2)
    sys.exit(main(sys.argv[1]))
