"""Semantic field analysis coordinator."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

from oscura.analyzers.binary.core.results import FieldType
from oscura.analyzers.binary.inference.checksums import ChecksumAnalyzer
from oscura.analyzers.binary.inference.sequences import SequenceAnalyzer
from oscura.analyzers.binary.inference.timestamps import TimestampAnalyzer

if TYPE_CHECKING:
    from oscura.analyzers.binary.core.file_access import BinaryFile
    from oscura.analyzers.binary.core.results import Field, StructureResult


class SemanticAnalyzer:
    """Coordinate semantic analysis of binary fields.

    Enhances field information with semantic metadata including:
    - Sequence number detection and analysis
    - Timestamp format identification
    - Checksum algorithm detection and validation
    - Payload characteristics

    Example:
        >>> analyzer = SemanticAnalyzer()
        >>> enhanced_fields = analyzer.analyze_fields(binary_file, structure)
        >>> for field in enhanced_fields:
        ...     if field.field_type == FieldType.CHECKSUM:
        ...         print(f"Checksum: {field.metadata['algorithm']}")
    """

    def __init__(self) -> None:
        """Initialize semantic analyzer."""
        self.sequence_analyzer = SequenceAnalyzer()
        self.timestamp_analyzer = TimestampAnalyzer()
        self.checksum_analyzer = ChecksumAnalyzer()

    def analyze_fields(self, file: BinaryFile, structure: StructureResult) -> list[Field]:
        """Enhance fields with semantic analysis.

        Args:
            file: Binary file being analyzed.
            structure: Structure inference result.

        Returns:
            List of enhanced fields with metadata.

        Example:
            >>> analyzer = SemanticAnalyzer()
            >>> fields = analyzer.analyze_fields(binary_file, structure_result)
        """
        if not structure.has_messages or not structure.fields:
            return structure.fields

        enhanced_fields = []

        for field in structure.fields:
            # Analyze based on field type
            if field.field_type == FieldType.SEQUENCE:
                metadata = self.sequence_analyzer.analyze(field, structure.messages)
                field.metadata.update(metadata)

            elif field.field_type == FieldType.TIMESTAMP:
                metadata = self.timestamp_analyzer.analyze(field, structure.messages)
                field.metadata.update(metadata)

            elif field.field_type == FieldType.CHECKSUM:
                metadata = self.checksum_analyzer.analyze(field, structure.messages)
                field.metadata.update(metadata)

            elif field.field_type == FieldType.PAYLOAD:
                metadata = self._analyze_payload(field, structure.messages)
                field.metadata.update(metadata)

            enhanced_fields.append(field)

        return enhanced_fields

    def _analyze_payload(self, field: Field, messages: list[Any]) -> dict[str, Any]:
        """Analyze payload field characteristics.

        Args:
            field: Payload field.
            messages: List of messages.

        Returns:
            Metadata dict with payload characteristics.
        """
        if len(messages) == 0:
            return {"payload_type": "unknown"}

        # Sample first few payloads
        sample_size = min(10, len(messages))
        entropies = []

        for msg in messages[:sample_size]:
            if field.offset + field.length <= len(msg.data):
                payload = msg.data[field.offset : field.offset + field.length]
                entropy = self._calculate_entropy(payload)
                entropies.append(entropy)

        if not entropies:
            return {"payload_type": "unknown"}

        avg_entropy = sum(entropies) / len(entropies)

        # Classify payload type by entropy
        if avg_entropy > 7.5:
            payload_type = "compressed_or_encrypted"
        elif avg_entropy > 5.0:
            payload_type = "binary_data"
        elif avg_entropy > 3.0:
            payload_type = "mixed_content"
        else:
            payload_type = "low_entropy"

        return {
            "payload_type": payload_type,
            "average_entropy": avg_entropy,
            "entropy_bits_per_byte": avg_entropy,
        }

    def _calculate_entropy(self, data: bytes) -> float:
        """Calculate Shannon entropy of data.

        Args:
            data: Input bytes.

        Returns:
            Entropy in bits per byte.
        """
        if len(data) == 0:
            return 0.0

        from collections import Counter

        counts = Counter(data)
        total = len(data)

        entropy = 0.0
        for count in counts.values():
            p = count / total
            if p > 0:
                import math

                entropy -= p * math.log2(p)

        return entropy
