"""
Signature computation utilities for MRS.

Signatures capture patterns in reasoning outputs for:
    - Pattern detection
    - Consistency checking
    - State comparison
"""

from typing import Any, List, Optional, Tuple
import hashlib


def compute_signature(text: str, window_size: int = 3) -> Tuple[str, List[int]]:
    """
    Compute a signature for text content.

    Creates a compact representation for pattern matching.

    Args:
        text: Input text to signature
        window_size: Size of n-gram windows

    Returns:
        Tuple of (hash_signature, feature_vector)
    """
    if not text:
        return ("empty", [0])

    text = str(text).lower()

    full_hash = hashlib.sha256(text.encode()).hexdigest()[:16]

    words = text.split()
    features = []

    features.append(len(text))
    features.append(len(words))
    features.append(text.count("."))
    features.append(text.count(","))
    features.append(sum(1 for c in text if c.isupper()))

    if len(words) >= window_size:
        ngram_hashes = []
        for i in range(len(words) - window_size + 1):
            ngram = " ".join(words[i : i + window_size])
            ngram_hash = hash(ngram) % 1000
            ngram_hashes.append(ngram_hash)
        if ngram_hashes:
            features.append(sum(ngram_hashes) // len(ngram_hashes))

    return (full_hash, features)


def signature_distance(
    sig1: Tuple[str, List[int]], sig2: Tuple[str, List[int]]
) -> float:
    """
    Compute distance between two signatures.

    Args:
        sig1: First signature (hash, features)
        sig2: Second signature (hash, features)

    Returns:
        Distance value between 0.0 (identical) and 1.0 (maximally different)
    """
    hash1, feat1 = sig1
    hash2, feat2 = sig2

    if hash1 == hash2:
        return 0.0

    common_chars = sum(c1 == c2 for c1, c2 in zip(hash1, hash2))
    hash_sim = common_chars / max(len(hash1), len(hash2))

    min_len = min(len(feat1), len(feat2))
    if min_len == 0:
        return 1.0 - hash_sim * 0.5

    feat_diffs = []
    for i in range(min_len):
        if feat1[i] == 0 and feat2[i] == 0:
            feat_diffs.append(0)
        else:
            max_val = max(abs(feat1[i]), abs(feat2[i]), 1)
            diff = abs(feat1[i] - feat2[i]) / max_val
            feat_diffs.append(min(1.0, diff))

    feat_dist = sum(feat_diffs) / len(feat_diffs)

    return 0.3 * (1.0 - hash_sim) + 0.7 * feat_dist


def signatures_match(
    sig1: Tuple[str, List[int]], sig2: Tuple[str, List[int]], threshold: float = 0.3
) -> bool:
    """
    Check if two signatures are similar enough to match.

    Args:
        sig1: First signature
        sig2: Second signature
        threshold: Maximum distance to consider a match

    Returns:
        True if signatures match within threshold
    """
    return signature_distance(sig1, sig2) <= threshold


def compute_output_signature(outputs: List[Any]) -> str:
    """
    Compute a combined signature for a list of outputs.

    Args:
        outputs: List of reasoning outputs

    Returns:
        Combined signature hash
    """
    combined = "|||".join(str(o)[:100] for o in outputs)
    return hashlib.md5(combined.encode()).hexdigest()[:12]
