"""MCP tool implementations — thin async wrappers around tyta/core/ functions."""

from __future__ import annotations

import os
from datetime import date
from typing import Any

from loguru import logger

from tyta.core.auth import NotAuthenticatedError, get_auth_path, get_valid_token, login
from tyta.core.auth import status as auth_status_core
from tyta.core.client import ToyotaClient
from tyta.core.remote import (
    CMD_DOOR_LOCK,
    CMD_DOOR_UNLOCK,
    CMD_FIND_VEHICLE,
    CMD_SOUND_HORN,
    send_command,
)
from tyta.core.vehicles import resolve_vin

_NOT_AUTH_MSG = (
    "Not authenticated. Set TOYOTA_USERNAME and TOYOTA_PASSWORD env vars"
    " or run `tyta auth login` first."
)

# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------


async def _get_client() -> ToyotaClient:
    """Load a valid token and construct a ToyotaClient.

    If no stored token is found, attempts to auto-authenticate using
    TOYOTA_USERNAME and TOYOTA_PASSWORD environment variables.

    Returns:
        Authenticated ToyotaClient ready for API calls.

    Raises:
        RuntimeError: If no token file and no env var credentials are available.
        TokenExpiredError: If tokens are expired and cannot be refreshed.

    """
    auth_path = get_auth_path()
    try:
        token = await get_valid_token(auth_path)
    except NotAuthenticatedError:
        env_username = os.environ.get("TOYOTA_USERNAME")
        env_password = os.environ.get("TOYOTA_PASSWORD")
        if env_username and env_password:
            logger.info("No stored token found; auto-authenticating via env vars.")
            token = await login(env_username, env_password, auth_path)
        else:
            raise RuntimeError(_NOT_AUTH_MSG) from None
    return ToyotaClient(access_token=token["access_token"], uuid=token["uuid"])


async def _resolve(client: ToyotaClient, vin: str | None) -> str:
    """Apply the 4-step VIN resolution and return the resolved VIN.

    Args:
        client: Authenticated ToyotaClient.
        vin: Explicit VIN passed by the MCP tool caller (step 1).

    Returns:
        Resolved VIN string.

    """
    resolved, warnings = await resolve_vin(client, vin_flag=vin)
    for w in warnings:
        logger.warning(w)
    return resolved


# ---------------------------------------------------------------------------
# Auth tools
# ---------------------------------------------------------------------------


def tool_auth_status() -> dict[str, Any]:
    """Return current authentication status and token expiry.

    Returns:
        Dict with keys: authenticated, username, expires_at, expired.

    """
    auth_path = get_auth_path()
    return auth_status_core(auth_path)


# ---------------------------------------------------------------------------
# Vehicles tools
# ---------------------------------------------------------------------------


async def tool_vehicles_list() -> list[dict[str, Any]]:
    """List all vehicles linked to the Toyota account.

    Returns:
        List of vehicle dicts, each containing at minimum a ``vin`` key.

    """
    from tyta.core.vehicles import list_vehicles

    client = await _get_client()
    return await list_vehicles(client)


# ---------------------------------------------------------------------------
# Status tools
# ---------------------------------------------------------------------------


async def tool_telemetry(vin: str | None = None) -> dict[str, Any] | None:
    """Fetch telemetry data: fuel level, odometer, 12V battery.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).

    Returns:
        Telemetry payload dict, or None if unavailable.

    """
    from tyta.core.status import get_telemetry

    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await get_telemetry(client, resolved_vin)


async def tool_location(vin: str | None = None) -> dict[str, Any] | None:
    """Fetch GPS location: coordinates and timestamp.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).

    Returns:
        Location payload dict, or None if unavailable.

    """
    from tyta.core.status import get_location

    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await get_location(client, resolved_vin)


async def tool_remote_status(vin: str | None = None) -> dict[str, Any] | None:
    """Fetch remote/lock status: lock status and caution count.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).

    Returns:
        Remote status payload dict, or None if unavailable.

    """
    from tyta.core.status import get_remote_status

    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await get_remote_status(client, resolved_vin)


async def tool_health(vin: str | None = None) -> dict[str, Any] | None:
    """Fetch vehicle health: warning lights and health alerts.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).

    Returns:
        Health payload dict, or None if unavailable.

    """
    from tyta.core.status import get_health

    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await get_health(client, resolved_vin)


# ---------------------------------------------------------------------------
# Electric tools
# ---------------------------------------------------------------------------


async def tool_electric_status(vin: str | None = None) -> dict[str, Any] | None:
    """Fetch EV status: battery level, charging status, range.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).

    Returns:
        Electric status payload dict, or None if unavailable.

    """
    from tyta.core.electric import get_electric_status

    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await get_electric_status(client, resolved_vin)


# ---------------------------------------------------------------------------
# Climate tools
# ---------------------------------------------------------------------------


async def tool_climate_status(vin: str | None = None) -> dict[str, Any] | None:
    """Fetch climate status: on/off, temperature, defoggers.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).

    Returns:
        Climate status payload dict, or None if unavailable.

    """
    from tyta.core.climate import get_climate_status

    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await get_climate_status(client, resolved_vin)


# ---------------------------------------------------------------------------
# Trips tools
# ---------------------------------------------------------------------------


async def tool_trips_list(
    vin: str | None = None,
    from_date: str | None = None,
    to_date: str | None = None,
    limit: int = 10,
    page: int = 1,
) -> dict[str, Any]:
    """Fetch trip history with optional date range.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).
        from_date: Start date ISO string (YYYY-MM-DD). Defaults to 30 days ago.
        to_date: End date ISO string (YYYY-MM-DD). Defaults to today.
        limit: Maximum trips to return (1–50, default 10).
        page: 1-based page number (default 1).

    Returns:
        Raw trips response dict from the API.

    """
    from tyta.core.trips import list_trips

    client = await _get_client()
    resolved_vin = await _resolve(client, vin)

    parsed_from: date | None = date.fromisoformat(from_date) if from_date else None
    parsed_to: date | None = date.fromisoformat(to_date) if to_date else None

    return await list_trips(
        client,
        resolved_vin,
        from_date=parsed_from,
        to_date=parsed_to,
        limit=limit,
        page=page,
    )


async def tool_trips_show(trip_id: str, vin: str | None = None) -> dict[str, Any]:
    """Fetch full detail for a single trip by ID.

    Args:
        trip_id: UUID string of the trip.
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).

    Returns:
        Raw trip detail response dict from the API.

    """
    from tyta.core.trips import get_trip

    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await get_trip(client, resolved_vin, trip_id)


# ---------------------------------------------------------------------------
# Remote command tools (write operations — require confirm=True)
# ---------------------------------------------------------------------------

_CONFIRM_ERROR = {"error": "confirm must be True to execute write operations", "executed": False}


async def tool_remote_lock(vin: str | None = None, confirm: bool = False) -> dict[str, Any]:
    """Lock vehicle doors.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).
        confirm: Must be True to execute. Prevents accidental AI-triggered writes.

    Returns:
        API response dict, or an error dict if confirm is False.

    """
    if not confirm:
        return _CONFIRM_ERROR
    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await send_command(client, resolved_vin, CMD_DOOR_LOCK)


async def tool_remote_unlock(vin: str | None = None, confirm: bool = False) -> dict[str, Any]:
    """Unlock vehicle doors.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).
        confirm: Must be True to execute. Prevents accidental AI-triggered writes.

    Returns:
        API response dict, or an error dict if confirm is False.

    """
    if not confirm:
        return _CONFIRM_ERROR
    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await send_command(client, resolved_vin, CMD_DOOR_UNLOCK)


async def tool_remote_horn(vin: str | None = None, confirm: bool = False) -> dict[str, Any]:
    """Sound the vehicle horn.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).
        confirm: Must be True to execute. Prevents accidental AI-triggered writes.

    Returns:
        API response dict, or an error dict if confirm is False.

    """
    if not confirm:
        return _CONFIRM_ERROR
    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await send_command(client, resolved_vin, CMD_SOUND_HORN)


async def tool_remote_find(vin: str | None = None, confirm: bool = False) -> dict[str, Any]:
    """Flash lights and sound horn to locate the vehicle.

    Args:
        vin: Vehicle VIN (optional — resolved via 4-step order if omitted).
        confirm: Must be True to execute. Prevents accidental AI-triggered writes.

    Returns:
        API response dict, or an error dict if confirm is False.

    """
    if not confirm:
        return _CONFIRM_ERROR
    client = await _get_client()
    resolved_vin = await _resolve(client, vin)
    return await send_command(client, resolved_vin, CMD_FIND_VEHICLE)
