"""Telemetry query API client."""

from datetime import datetime
from typing import TYPE_CHECKING
from uuid import UUID

from fishinfo.models.query import (
    AggregatedTelemetry,
    AggregationParams,
    AggregationType,
    DownsampleParams,
    LatestTelemetryResponse,
    OrderDirection,
    TelemetryQueryParams,
    TelemetryResponse,
)
from fishinfo.models.telemetry import DataType

if TYPE_CHECKING:
    from fishinfo.client import FishinfoClient


class TelemetryApi:
    """API client for querying telemetry data.

    Provides methods for querying, aggregating, and downsampling telemetry data.

    Example:
        ```python
        async with FishinfoClient(...) as client:
            telemetry = TelemetryApi(client)

            # Query telemetry points
            response = await telemetry.query(
                vessel_id=UUID("..."),
                data_type="position",
                start_time=datetime.now(UTC) - timedelta(hours=1),
                limit=100,
            )

            # Get latest telemetry
            latest = await telemetry.get_latest(
                vessel_id=UUID("..."),
                data_type="position,speed",
            )

            # Get aggregated data
            agg = await telemetry.aggregate(
                vessel_id=UUID("..."),
                data_type=DataType.SPEED,
                start_time=datetime.now(UTC) - timedelta(days=1),
                end_time=datetime.now(UTC),
                interval="1 hour",
                agg_type=AggregationType.AVG,
            )
        ```

    Attributes:
        client: FishinfoClient instance
    """

    def __init__(self, client: "FishinfoClient") -> None:
        """Initialize telemetry API client.

        Args:
            client: FishinfoClient instance
        """
        self.client = client

    async def query(
        self,
        vessel_id: UUID,
        data_type: str | None = None,
        start_time: datetime | None = None,
        end_time: datetime | None = None,
        limit: int = 1000,
        offset: int = 0,
        order: OrderDirection = OrderDirection.DESC,
    ) -> TelemetryResponse:
        """Query telemetry data with filters.

        Returns paginated telemetry points for the specified vessel with optional
        filters for data type and time range.

        Args:
            vessel_id: UUID of the vessel to query
            data_type: Filter by data type(s), comma-separated (optional)
            start_time: Start time for query range (inclusive)
            end_time: End time for query range (exclusive)
            limit: Maximum number of results (default: 1000, max: 10000)
            offset: Offset for pagination
            order: Sort order by time (asc or desc, default: desc)

        Returns:
            TelemetryResponse with paginated data

        Raises:
            ValidationError: If query parameters are invalid
            ResourceNotFoundError: If vessel not found
            AuthenticationError: If authentication fails
            AuthorizationError: If user lacks permission

        Example:
            ```python
            # Get latest 100 position points
            response = await telemetry.query(
                vessel_id=vessel_id,
                data_type="position",
                limit=100,
            )

            # Get speed data for date range
            response = await telemetry.query(
                vessel_id=vessel_id,
                data_type="speed",
                start_time=datetime(2025, 12, 11, 0, 0, 0, tzinfo=UTC),
                end_time=datetime(2025, 12, 12, 0, 0, 0, tzinfo=UTC),
            )

            # Get multiple types
            response = await telemetry.query(
                vessel_id=vessel_id,
                data_type="position,speed,course",
            )
            ```
        """
        params = TelemetryQueryParams(
            vessel_id=vessel_id,
            data_type=data_type,
            start_time=start_time,
            end_time=end_time,
            limit=limit,
            offset=offset,
            order=order,
        )

        # Build query parameters
        query_params = {
            "vessel_id": str(params.vessel_id),
            "limit": params.limit,
            "offset": params.offset,
            "order": params.order.value,
        }

        if params.data_type:
            query_params["data_type"] = params.data_type

        if params.start_time:
            query_params["start"] = params.start_time.isoformat()

        if params.end_time:
            query_params["end"] = params.end_time.isoformat()

        response_data = await self.client._request("GET", "/telemetry", params=query_params)

        return TelemetryResponse(**response_data)

    async def get_latest(
        self,
        vessel_id: UUID,
        data_type: str | None = None,
    ) -> LatestTelemetryResponse:
        """Get the latest telemetry point(s) for a vessel.

        If `data_type` is specified, returns the latest point for each type.
        Otherwise, returns the single most recent point regardless of type.

        Args:
            vessel_id: UUID of the vessel
            data_type: Filter by data type(s), comma-separated (optional)

        Returns:
            LatestTelemetryResponse with latest point(s)

        Raises:
            ResourceNotFoundError: If no telemetry found for vessel
            ValidationError: If data_type is invalid
            AuthenticationError: If authentication fails
            AuthorizationError: If user lacks permission

        Example:
            ```python
            # Get latest point
            latest = await telemetry.get_latest(vessel_id=vessel_id)

            # Get latest position and speed
            latest = await telemetry.get_latest(
                vessel_id=vessel_id,
                data_type="position,speed",
            )
            ```
        """
        query_params: dict[str, str] = {}

        if data_type:
            query_params["data_type"] = data_type

        response_data = await self.client._request(
            "GET",
            f"/telemetry/latest/{vessel_id}",
            params=query_params,
        )

        return LatestTelemetryResponse(**response_data)

    async def aggregate(
        self,
        vessel_id: UUID,
        data_type: DataType,
        start_time: datetime,
        end_time: datetime,
        interval: str,
        agg_type: AggregationType = AggregationType.AVG,
    ) -> AggregatedTelemetry:
        """Get time-bucketed aggregated telemetry data.

        Uses TimescaleDB's `time_bucket()` function to aggregate telemetry data
        into fixed time intervals.

        Args:
            vessel_id: UUID of the vessel
            data_type: Data type to aggregate
            start_time: Start time for aggregation range
            end_time: End time for aggregation range
            interval: Time bucket size (e.g., "1 minute", "5 minutes", "1 hour")
            agg_type: Aggregation function - avg, min, max, sum, count, first, last

        Returns:
            AggregatedTelemetry with time-bucketed data

        Raises:
            ValidationError: If parameters are invalid
            AuthenticationError: If authentication fails
            AuthorizationError: If user lacks permission

        Example:
            ```python
            # Hourly average speed
            agg = await telemetry.aggregate(
                vessel_id=vessel_id,
                data_type=DataType.SPEED,
                start_time=datetime.now(UTC) - timedelta(days=1),
                end_time=datetime.now(UTC),
                interval="1 hour",
                agg_type=AggregationType.AVG,
            )

            # 5-minute max depth
            agg = await telemetry.aggregate(
                vessel_id=vessel_id,
                data_type=DataType.DEPTH,
                start_time=start,
                end_time=end,
                interval="5 minutes",
                agg_type=AggregationType.MAX,
            )
            ```
        """
        params = AggregationParams(
            vessel_id=vessel_id,
            data_type=data_type,
            start_time=start_time,
            end_time=end_time,
            interval=interval,
            agg_type=agg_type,
        )

        query_params = {
            "vessel_id": str(params.vessel_id),
            "data_type": params.data_type.value,
            "start": params.start_time.isoformat(),
            "end": params.end_time.isoformat(),
            "interval": params.interval,
            "agg_type": params.agg_type.value,
        }

        response_data = await self.client._request(
            "GET",
            "/telemetry/aggregate",
            params=query_params,
        )

        return AggregatedTelemetry(**response_data)

    async def downsample(
        self,
        vessel_id: UUID,
        data_type: DataType,
        start_time: datetime,
        end_time: datetime,
        target_points: int = 500,
    ) -> TelemetryResponse:
        """Downsample telemetry data for visualization.

        Reduces data density by selecting representative points from time buckets,
        useful for rendering large datasets efficiently.

        If the total number of points is less than `target_points`, all points
        are returned without downsampling.

        Args:
            vessel_id: UUID of the vessel
            data_type: Data type to downsample
            start_time: Start time for query range
            end_time: End time for query range
            target_points: Target number of points (default: 500, range: 10-10000)

        Returns:
            TelemetryResponse with downsampled data

        Raises:
            ValidationError: If parameters are invalid
            AuthenticationError: If authentication fails
            AuthorizationError: If user lacks permission

        Example:
            ```python
            # Get 500 position points for chart
            response = await telemetry.downsample(
                vessel_id=vessel_id,
                data_type=DataType.POSITION,
                start_time=datetime.now(UTC) - timedelta(days=7),
                end_time=datetime.now(UTC),
                target_points=500,
            )

            # Get 1000 speed points
            response = await telemetry.downsample(
                vessel_id=vessel_id,
                data_type=DataType.SPEED,
                start_time=start,
                end_time=end,
                target_points=1000,
            )
            ```
        """
        params = DownsampleParams(
            vessel_id=vessel_id,
            data_type=data_type,
            start_time=start_time,
            end_time=end_time,
            target_points=target_points,
        )

        query_params = {
            "vessel_id": str(params.vessel_id),
            "data_type": params.data_type.value,
            "start": params.start_time.isoformat(),
            "end": params.end_time.isoformat(),
            "target_points": params.target_points,
        }

        response_data = await self.client._request(
            "GET",
            "/telemetry/downsample",
            params=query_params,
        )

        return TelemetryResponse(**response_data)
