#!/usr/bin/env python3
"""Reimplementacion independiente del formato sello-config-v1.

No lee el fichero que escribe el EA ni su codigo fuente: reconstruye la
cadena canonica desde los parametros y la hashea. Si los dos hashes
coinciden, el formato esta completo -- y esa es la demostracion, no el
hash en si.

Comentarios sin acentos a proposito: este fichero viaja por editores,
foros y portapapeles, y un fichero de codigo en ASCII puro no se puede
malinterpretar. Los acentos del texto van en el articulo, no aqui.
"""

import hashlib
import struct

FORMATO = "sello-config-v1"


def doble(valor):
    """Los 8 bytes del double en hexadecimal, digito mas significativo primero.

    Nunca `str(valor)`: el decimal redondea, y dos configuraciones
    distintas darian el mismo hash. Aqui no hay conversion a decimal,
    asi que es exacto.

    BIG-endian ('>d') a proposito. En MQL5 esto se hace con una `union`
    que lee la memoria en little-endian, pero al imprimirse como NUMERO
    con `%016I64X` el orden se invierte otra vez y sale el patron de
    bits MSB->LSB. Con '<d' salen los mismos ocho bytes al reves y por
    tanto otro hash: es el error mas probable al reimplementar esto.
    """
    return struct.pack(">d", valor).hex().upper()


def canonica(lotaje, magic, riesgo_pct, stop_puntos, periodo, trailing, etiqueta):
    """El texto exacto que se hashea: un campo por linea, en orden fijo."""
    # Un salto de linea dentro de un valor partiria el campo en dos y haria que
    # dos configuraciones distintas se hashearan igual. Se sustituye, no se borra.
    etiqueta = etiqueta.replace("\r", " ").replace("\n", " ")

    campos = [
        FORMATO,                                    # subirlo invalida los sellos previos
        f"01_lotaje={doble(lotaje)}",
        f"02_magic={magic}",
        f"03_riesgo_pct={doble(riesgo_pct)}",
        f"04_stop_puntos={stop_puntos}",
        f"05_periodo={periodo}",                    # el entero del timeframe: M15 -> 15
        f"06_trailing={1 if trailing else 0}",
        f"07_etiqueta={etiqueta}",
    ]

    # Separador LF, y LF tambien al final del ultimo campo. Nunca CRLF: cada
    # 0x0D de mas es un byte que entra en el hash.
    return "".join(campo + "\n" for campo in campos)


def sello(**parametros):
    datos = canonica(**parametros).encode("utf-8")  # UTF-8, sin BOM, sin terminador
    return hashlib.sha256(datos).hexdigest(), len(datos)


if __name__ == "__main__":
    huella, tam = sello(lotaje=0.10, magic=246810, riesgo_pct=1.5,
                        stop_puntos=350, periodo=15, trailing=True,
                        etiqueta="produccion")
    print(f"sha256 = {huella}\nbytes = {tam}")
