"""Order-independent named NumPy ``SeedSequence`` substreams."""

from __future__ import annotations

import hashlib
from typing import Iterable, Mapping

import numpy as np

from .hashing import canonical_json_bytes


DEFAULT_STREAMS = ("trajectory", "sensor", "model", "network")


def _label_words(*labels: object) -> list[int]:
    digest = hashlib.sha256(canonical_json_bytes(labels)).digest()
    return [
        int.from_bytes(digest[offset : offset + 4], "little")
        for offset in range(0, 16, 4)
    ]


def named_seed_record(
    root_seed: int,
    namespace: object,
    stream_names: Iterable[str] = DEFAULT_STREAMS,
) -> dict[str, list[int]]:
    """Create stable named seed states independent of request order."""
    root_seed = int(root_seed)
    if root_seed < 0:
        raise ValueError("root_seed must be non-negative")
    record: dict[str, list[int]] = {}
    for name in sorted(set(stream_names)):
        if not name:
            raise ValueError("stream names must be non-empty")
        entropy = [root_seed & 0xFFFFFFFF, (root_seed >> 32) & 0xFFFFFFFF]
        entropy.extend(_label_words(namespace, name))
        state = np.random.SeedSequence(entropy).generate_state(4, dtype=np.uint32)
        record[name] = [int(word) for word in state]
    return record


def generator_from_record(
    record: Mapping[str, list[int]],
    stream_name: str,
) -> np.random.Generator:
    if stream_name not in record:
        raise KeyError(f"Unknown random stream {stream_name!r}")
    words = [int(word) for word in record[stream_name]]
    if len(words) != 4 or any(word < 0 or word > 0xFFFFFFFF for word in words):
        raise ValueError(f"Invalid seed state for stream {stream_name!r}")
    return np.random.default_rng(np.random.SeedSequence(words))
