"""Timestamp field analysis."""

from __future__ import annotations

from datetime import UTC, datetime
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from oscura.analyzers.binary.core.results import Field, Message


class TimestampAnalyzer:
    """Analyze timestamp fields.

    Detects various timestamp formats and validates temporal consistency.

    Example:
        >>> analyzer = TimestampAnalyzer()
        >>> metadata = analyzer.analyze(field, messages)
        >>> if metadata["is_timestamp"]:
        ...     print(f"Format: {metadata['format']}")
        ...     print(f"Sample: {metadata['sample_decoded']}")
    """

    def analyze(self, field: Field, messages: list[Message]) -> dict[str, Any]:
        """Analyze timestamp field.

        Args:
            field: Field to analyze.
            messages: List of messages containing field.

        Returns:
            Metadata dict with timestamp information.

        Example:
            >>> result = analyzer.analyze(field, messages)
            >>> result["format"]  # e.g., "unix_microseconds"
            >>> result["time_range"]  # (start, end) datetimes
        """
        if len(messages) < 3:
            return {
                "is_timestamp": False,
                "reason": "insufficient_data",
            }

        # Extract field values
        values = self._extract_values(field, messages)

        if len(values) < 3:
            return {
                "is_timestamp": False,
                "reason": "could_not_extract_values",
            }

        # Test various timestamp formats
        formats_to_test = [
            ("unix_seconds", 1, 1),
            ("unix_milliseconds", 1000, 1),
            ("unix_microseconds", 1_000_000, 1),
            ("unix_nanoseconds", 1_000_000_000, 1),
            ("gps_time", 1, 315964800),  # GPS epoch offset
            ("ntp_time", 1, 2208988800),  # NTP epoch offset
        ]

        best_format = None
        best_confidence = 0.0
        best_decoded = []

        for format_name, divisor, epoch_offset in formats_to_test:
            confidence, decoded = self._test_format(values, format_name, divisor, epoch_offset)

            if confidence > best_confidence:
                best_confidence = confidence
                best_format = format_name
                best_decoded = decoded

        if best_confidence < 0.6:
            return {
                "is_timestamp": False,
                "reason": "low_confidence",
                "tested_formats": [f[0] for f in formats_to_test],
            }

        # Extract time range
        time_range = self._get_time_range(best_decoded)

        return {
            "is_timestamp": True,
            "format": best_format,
            "confidence": best_confidence,
            "sample_decoded": str(best_decoded[0]) if best_decoded else None,
            "time_range": {
                "start": str(time_range[0]) if time_range[0] else None,
                "end": str(time_range[1]) if time_range[1] else None,
                "duration_seconds": (
                    (time_range[1] - time_range[0]).total_seconds()
                    if time_range[0] and time_range[1]
                    else 0
                ),
            },
            "monotonic": self._is_monotonic(values),
        }

    def _extract_values(self, field: Field, messages: list[Message]) -> list[int]:
        """Extract field values as integers.

        Args:
            field: Field specification.
            messages: List of messages.

        Returns:
            List of integer values.
        """
        values = []

        for msg in messages:
            if field.offset + field.length <= len(msg.data):
                field_bytes = msg.data[field.offset : field.offset + field.length]

                try:
                    if field.length in [4, 8]:
                        value = int.from_bytes(field_bytes, byteorder="little", signed=False)
                        values.append(value)
                except Exception:
                    continue

        return values

    def _test_format(
        self,
        values: list[int],
        format_name: str,
        divisor: int,
        epoch_offset: int,
    ) -> tuple[float, list[datetime]]:
        """Test if values match a timestamp format.

        Args:
            values: Raw timestamp values.
            format_name: Format name being tested.
            divisor: Divisor to convert to seconds.
            epoch_offset: Epoch offset in seconds.

        Returns:
            (confidence, decoded_timestamps).
        """
        decoded = []
        valid_count = 0

        for val in values[:100]:  # Test first 100
            try:
                # Convert to Unix seconds
                unix_seconds = (val / divisor) - epoch_offset

                # Create datetime
                dt = datetime.fromtimestamp(unix_seconds, tz=UTC)

                # Validate: reasonable date range (2000-2030)
                if datetime(2000, 1, 1, tzinfo=UTC) <= dt <= datetime(2030, 12, 31, tzinfo=UTC):
                    decoded.append(dt)
                    valid_count += 1
            except Exception:
                pass  # Expected: timestamp format does not apply

        # Calculate confidence
        if len(values) == 0:
            return 0.0, []

        confidence = valid_count / min(len(values), 100)

        # Check monotonic increase (timestamps should increase)
        if len(decoded) > 1:
            monotonic_count = sum(
                1 for i in range(len(decoded) - 1) if decoded[i] <= decoded[i + 1]
            )
            monotonic_ratio = monotonic_count / (len(decoded) - 1)

            confidence *= monotonic_ratio

        return confidence, decoded

    def _get_time_range(self, decoded: list[datetime]) -> tuple[datetime | None, datetime | None]:
        """Get time range from decoded timestamps.

        Args:
            decoded: List of datetime objects.

        Returns:
            (start, end) tuple.
        """
        if not decoded:
            return None, None

        return min(decoded), max(decoded)

    def _is_monotonic(self, values: list[int]) -> bool:
        """Check if values are monotonically increasing.

        Args:
            values: List of values.

        Returns:
            True if monotonic.
        """
        if len(values) < 2:
            return True

        increasing = sum(1 for i in range(len(values) - 1) if values[i] <= values[i + 1])

        return increasing / (len(values) - 1) > 0.95
