import hashlib, struct

DOMAIN = "oomi:mutation:v1"
RULE = "oomi-rules/0.3"
TRAITS = [  # order defines trait index i
    ("aura", [("Signal Cyan", 34), ("Deep Plasma", 26), ("Dusk Violet", 18), ("Tidal Teal", 14), ("Halo Gold", 8)]),
    ("earGlow", [("Dim", 22), ("Soft", 34), ("Bright", 28), ("Radiant", 16)]),
    ("droplets", [("Still", 30), ("Drifting", 38), ("Orbiting", 20), ("Swarming", 12)]),
    ("pattern", [("Marbled", 36), ("Rippled", 26), ("Crystalline", 22), ("Static", 16)]),
    ("temperament", [("Curious", 30), ("Playful", 24), ("Serene", 20), ("Mischievous", 16), ("Focused", 10)]),
]

def lp(s: str) -> bytes:
    b = s.encode()
    return struct.pack(">I", len(b)) + b

def seed(epoch: int, identity: str, root_hex: str, entropy_hex: str, rule: str = RULE) -> bytes:
    pre = lp(DOMAIN) + struct.pack(">I", epoch) + lp(identity) + bytes.fromhex(root_hex) + lp(rule) + bytes.fromhex(entropy_hex)
    return hashlib.sha256(pre).digest()

def derive(epoch, identity, root_hex, entropy_hex):
    s = seed(epoch, identity, root_hex, entropy_hex)
    out = {}
    for i, (name, opts) in enumerate(TRAITS):
        u = struct.unpack(">I", hashlib.sha256(s + struct.pack(">I", i)).digest()[:4])[0] / 2**32
        total, acc = sum(w for _, w in opts), 0.0
        for value, w in opts:
            acc += w / total
            if u < acc:
                break
        out[name] = value
    return s.hex(), out

if __name__ == "__main__":
    h = lambda t: hashlib.sha256(t.encode()).hexdigest()
    print(derive(7, "oomi:flagship", h("snapshot"), h("entropy")))
