"""Result types for binary analysis."""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Any

import numpy as np
from numpy.typing import NDArray


class PatternRole(Enum):
    """Role classification for repeating patterns."""

    HEADER = "header"
    FOOTER = "footer"
    DELIMITER = "delimiter"
    SYNC_MARKER = "sync_marker"
    UNKNOWN = "unknown"


class FieldType(Enum):
    """Field type classification."""

    CONSTANT = "constant"
    SEQUENCE = "sequence"
    TIMESTAMP = "timestamp"
    CHECKSUM = "checksum"
    PAYLOAD = "payload"
    LENGTH = "length"
    UNKNOWN = "unknown"


@dataclass
class Pattern:
    """Repeating byte pattern in binary file."""

    bytes: bytes
    positions: list[int]
    count: int
    avg_spacing: float
    spacing_variance: float
    regular: bool
    role: PatternRole

    def to_dict(self) -> dict[str, Any]:
        """Export to dictionary."""
        return {
            "hex": self.bytes.hex(" ").upper(),
            "length": len(self.bytes),
            "occurrences": self.count,
            "regular_spacing": self.regular,
            "avg_spacing": self.avg_spacing,
            "spacing_variance": self.spacing_variance,
            "role": self.role.value,
            "sample_positions": self.positions[:10],
        }


@dataclass
class Message:
    """Extracted message from binary file."""

    offset: int
    length: int
    data: bytes
    index: int

    def to_dict(self) -> dict[str, Any]:
        """Export to dictionary."""
        return {
            "index": self.index,
            "offset": self.offset,
            "length": self.length,
            "hex_preview": self.data[:64].hex(" ").upper()
            if len(self.data) > 64
            else self.data.hex(" ").upper(),
        }


@dataclass
class Field:
    """Message field with semantic information."""

    name: str
    offset: int
    length: int
    field_type: FieldType
    constant: bool
    values: list[Any] = field(default_factory=list)
    statistics: dict[str, float] = field(default_factory=dict)
    metadata: dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict[str, Any]:
        """Export to dictionary."""
        result = {
            "name": self.name,
            "offset": self.offset,
            "length": self.length,
            "type": self.field_type.value,
            "constant": self.constant,
            "statistics": self.statistics,
        }

        # Add sample values
        if self.values:
            if isinstance(self.values[0], bytes):
                result["sample_values"] = [v.hex(" ").upper() for v in self.values[:5]]
            else:
                result["sample_values"] = self.values[:5]

        # Add metadata
        if self.metadata:
            result["metadata"] = self.metadata

        return result


@dataclass
class EncodingResult:
    """Encoding detection result with validation."""

    dtype: str
    confidence: float
    alternatives: list[tuple[str, float]]
    validation_passed: bool
    sample_data: NDArray[np.float64]
    statistics: dict[str, float]
    issues: list[str] = field(default_factory=list)

    def to_dict(self) -> dict[str, Any]:
        """Export to dictionary."""
        return {
            "detected_dtype": self.dtype,
            "confidence": f"{self.confidence:.1%}",
            "alternatives": [
                {"dtype": dt, "confidence": f"{conf:.1%}"} for dt, conf in self.alternatives[:3]
            ],
            "validation_passed": self.validation_passed,
            "statistics": {
                "mean": float(np.mean(self.sample_data)),
                "std": float(np.std(self.sample_data)),
                "min": float(np.min(self.sample_data)),
                "max": float(np.max(self.sample_data)),
            },
            "issues": self.issues,
        }


@dataclass
class StructureResult:
    """Inferred file structure result."""

    has_messages: bool
    message_length: int | None
    message_count: int
    messages: list[Message]
    fields: list[Field]
    confidence: float

    def to_dict(self) -> dict[str, Any]:
        """Export to dictionary."""
        result: dict[str, Any] = {
            "has_messages": self.has_messages,
            "message_length": self.message_length,
            "message_count": self.message_count,
            "confidence": f"{self.confidence:.1%}",
        }

        if self.fields:
            result["fields"] = [f.to_dict() for f in self.fields]

        if self.messages:
            result["sample_messages"] = [m.to_dict() for m in self.messages[:5]]

        return result


@dataclass
class BinaryAnalysisResult:
    """Complete binary analysis result."""

    encoding: EncodingResult
    patterns: list[Pattern]
    structure: StructureResult | None = None
    confidence: float = 0.0

    def to_dict(self) -> dict[str, Any]:
        """Export complete results to dictionary."""
        result = {
            "encoding": self.encoding.to_dict(),
            "patterns": [p.to_dict() for p in self.patterns],
            "confidence": f"{self.confidence:.1%}",
        }

        if self.structure:
            result["structure"] = self.structure.to_dict()

        return result

    def __str__(self) -> str:
        """Human-readable summary."""
        lines = [
            "=== Binary Analysis Results ===",
            f"Encoding: {self.encoding.dtype} ({self.encoding.confidence:.1%} confidence)",
            f"Patterns found: {len(self.patterns)}",
        ]

        if self.structure and self.structure.has_messages:
            lines.append(f"Messages: {self.structure.message_count}")
            lines.append(f"Message length: {self.structure.message_length} bytes")
            lines.append(f"Fields identified: {len(self.structure.fields)}")

        lines.append(f"Overall confidence: {self.confidence:.1%}")

        return "\n".join(lines)
