"""Pass 3: Variance service for telemetry generation.

Applies noise to unit values for realistic variation.
"""

import hashlib
from typing import Optional

import numpy as np
import polars as pl


class TelemetryVarianceService:
    """Applies variance to telemetry unit values.

    Single responsibility: Add ±variance_pct noise to unit_value column
    using deterministic seeding for reproducibility.
    """

    def __init__(self, default_variance_pct: float = 50.0):
        """Initialize variance service.

        Args:
            default_variance_pct: Default noise percentage (±X%)
        """
        self.default_variance_pct = default_variance_pct

    def apply_variance(
        self,
        df: pl.DataFrame,
        element_id: str,
        variance_pct: Optional[float] = None
    ) -> pl.DataFrame:
        """Apply variance to element's unit values.

        Args:
            df: DataFrame with unit_value column
            element_id: Element identifier for deterministic seeding
            variance_pct: Override variance percentage (uses default if None)

        Returns:
            DataFrame with variance applied to unit_value column
        """
        if len(df) == 0:
            return df

        # Use provided variance or default
        pct = variance_pct if variance_pct is not None else self.default_variance_pct

        # Skip if variance is 0
        if pct == 0:
            return df

        # Generate deterministic seed
        seed = self._generate_seed(element_id)
        np.random.seed(seed)

        # Generate random multipliers
        n_rows = len(df)
        min_multiplier = 1.0 - (pct / 100.0)
        max_multiplier = 1.0 + (pct / 100.0)

        # Create array of random multipliers
        multipliers = np.random.uniform(min_multiplier, max_multiplier, n_rows)

        # Apply variance using Polars vectorized operations
        return df.with_columns([
            (pl.col("unit_value") * pl.Series("multipliers", multipliers))
            .alias("unit_value")
        ])

    def _generate_seed(self, element_id: str) -> int:
        """Generate deterministic seed for reproducible randomness."""
        combined = f"variance_{element_id}"
        hash_value = hashlib.md5(combined.encode()).hexdigest()
        return int(hash_value[:8], 16) % (2**32)
