"""Feature flags for independent v2/v3 pipeline routing.

Supports per-agent, per-document-type, and percentage-based routing
between pipeline versions. Both versions can run simultaneously.
"""

from __future__ import annotations

import enum
import hashlib
from dataclasses import dataclass, field
from typing import Any
from uuid import UUID


class PipelineVersion(str, enum.Enum):
    """Available pipeline versions."""

    V2 = "v2"
    V3 = "v3"
    SHADOW = "shadow"  # V3 runs alongside V2 but doesn't affect outputs


@dataclass
class FeatureFlags:
    """Pipeline version routing with per-agent, per-document-type,
    and percentage-based controls.

    Each flag can be overridden independently. The evaluation order:
    1. Agent-specific override (if set)
    2. Document-type override (if set)
    3. Percentage-based routing (deterministic by document_id)
    4. Default version
    """

    default_version: PipelineVersion = PipelineVersion.V2
    v3_enabled: bool = False
    shadow_enabled: bool = False
    v3_percentage: int = 0  # 0-100, percentage of documents routed to v3
    agent_overrides: dict[str, PipelineVersion] = field(default_factory=dict)
    document_type_overrides: dict[str, PipelineVersion] = field(
        default_factory=dict
    )
    excluded_document_types: set[str] = field(default_factory=set)

    def resolve(
        self,
        document_id: str,
        agent_id: str | UUID | None = None,
        document_type: str | None = None,
    ) -> PipelineVersion:
        """Determine which pipeline version handles a document.

        Resolution is deterministic for the same inputs.
        """
        if not self.v3_enabled and not self.shadow_enabled:
            return PipelineVersion.V2

        # Check excluded document types
        if document_type and document_type in self.excluded_document_types:
            return PipelineVersion.V2

        # Agent-specific override
        agent_key = str(agent_id) if agent_id else None
        if agent_key and agent_key in self.agent_overrides:
            return self.agent_overrides[agent_key]

        # Document-type override
        if document_type and document_type in self.document_type_overrides:
            return self.document_type_overrides[document_type]

        # Shadow mode: run both
        if self.shadow_enabled:
            return PipelineVersion.SHADOW

        # Percentage-based routing (deterministic hash)
        if self.v3_percentage > 0:
            bucket = self._hash_to_bucket(document_id)
            if bucket < self.v3_percentage:
                return PipelineVersion.V3

        return self.default_version

    def _hash_to_bucket(self, document_id: str) -> int:
        """Deterministic hash to 0-99 bucket for percentage routing."""
        h = hashlib.sha256(document_id.encode()).hexdigest()
        return int(h[:8], 16) % 100

    def is_v3_active(self) -> bool:
        """Whether v3 processing is active in any form."""
        return self.v3_enabled or self.shadow_enabled or self.v3_percentage > 0

    def set_agent_override(
        self, agent_id: str | UUID, version: PipelineVersion
    ) -> None:
        """Set a per-agent pipeline version override."""
        self.agent_overrides[str(agent_id)] = version

    def clear_agent_override(self, agent_id: str | UUID) -> None:
        """Remove a per-agent override."""
        self.agent_overrides.pop(str(agent_id), None)

    def to_dict(self) -> dict[str, Any]:
        """Serialize flags for API/config responses."""
        return {
            "default_version": self.default_version.value,
            "v3_enabled": self.v3_enabled,
            "shadow_enabled": self.shadow_enabled,
            "v3_percentage": self.v3_percentage,
            "agent_overrides": {
                k: v.value for k, v in self.agent_overrides.items()
            },
            "document_type_overrides": {
                k: v.value for k, v in self.document_type_overrides.items()
            },
            "excluded_document_types": list(self.excluded_document_types),
        }
