"""Electric vehicle operations: status, refresh, charging commands."""

from __future__ import annotations

from typing import Any

from tyta.core.client import ToyotaClient

# ---------------------------------------------------------------------------
# Endpoint constants
# ---------------------------------------------------------------------------

VEHICLE_GLOBAL_REMOTE_ELECTRIC_STATUS_ENDPOINT = "/v1/global/remote/electric/status"
VEHICLE_GLOBAL_REMOTE_ELECTRIC_REALTIME_STATUS_ENDPOINT = (
    "/v1/global/remote/electric/realtime-status"
)
VEHICLE_GLOBAL_REMOTE_ELECTRIC_CONTROL_ENDPOINT = "/v1/global/remote/electric/command"

# Warning always emitted for real-time EV refresh
EV_12V_WARNING = "Frequent use of real-time EV status refresh drains the vehicle's 12V battery."


# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------


async def get_electric_status(client: ToyotaClient, vin: str) -> dict[str, Any]:
    """Fetch the current electric status for a vehicle.

    Args:
        client: Authenticated ToyotaClient instance.
        vin: Vehicle Identification Number.

    Returns:
        The ``payload`` sub-dict from the electric status API response,
        or ``None`` if the endpoint returned no payload.

    Raises:
        ToyotaApiError: If the API call returns a non-2xx response.

    """
    raw = await client.get(VEHICLE_GLOBAL_REMOTE_ELECTRIC_STATUS_ENDPOINT, vin=vin)
    return raw.get("payload")


async def refresh_electric_realtime_status(client: ToyotaClient, vin: str) -> dict[str, Any]:
    """Request a real-time EV status refresh from the vehicle.

    This is a fire-and-forget command — the vehicle executes it asynchronously.
    Always emits a 12V battery warning.

    Args:
        client: Authenticated ToyotaClient instance.
        vin: Vehicle Identification Number.

    Returns:
        Dict with ``status`` key from the API response.

    Raises:
        ToyotaApiError: If the API call returns a non-2xx response.

    """
    await client.post(VEHICLE_GLOBAL_REMOTE_ELECTRIC_REALTIME_STATUS_ENDPOINT, vin=vin)
    return {
        "status": "command_queued",
        "message": "Real-time EV status refresh requested. The vehicle may take a moment to respond.",
    }


async def send_charge_now(client: ToyotaClient, vin: str) -> dict[str, Any]:
    """Send an immediate charge start command to the vehicle.

    Args:
        client: Authenticated ToyotaClient instance.
        vin: Vehicle Identification Number.

    Returns:
        Dict with ``status`` and ``message`` indicating the command was queued.

    Raises:
        ToyotaApiError: If the API call returns a non-2xx response.

    """
    body = {"command": "CHARGE_NOW"}
    await client.post(VEHICLE_GLOBAL_REMOTE_ELECTRIC_CONTROL_ENDPOINT, vin=vin, body=body)
    return {
        "status": "command_queued",
        "message": "Charge now command sent. The vehicle may take a moment to respond.",
    }


async def send_reserve_charge(
    client: ToyotaClient,
    vin: str,
    day: str,
    start: str,
    end: str | None,
    charge_type: str,
) -> dict[str, Any]:
    """Send a reserve charge schedule to the vehicle.

    Args:
        client: Authenticated ToyotaClient instance.
        vin: Vehicle Identification Number.
        day: Uppercase weekday name (e.g. MONDAY, TUESDAY).
        start: Start time as HH:MM (24h).
        end: Optional end time as HH:MM (24h).
        charge_type: Either "startOnly" or "startEnd".

    Returns:
        Dict with ``status`` and ``message`` indicating the command was queued.

    Raises:
        ToyotaApiError: If the API call returns a non-2xx response.

    """
    body = _build_charge_command("RESERVE_CHARGE", day, start, end, charge_type)
    await client.post(VEHICLE_GLOBAL_REMOTE_ELECTRIC_CONTROL_ENDPOINT, vin=vin, body=body)
    return {
        "status": "command_queued",
        "message": "Reserve charge command sent. The vehicle may take a moment to respond.",
    }


async def send_set_charging_time(
    client: ToyotaClient,
    vin: str,
    day: str,
    start: str,
    end: str | None,
    charge_type: str,
) -> dict[str, Any]:
    """Send a charging time schedule to the vehicle.

    Args:
        client: Authenticated ToyotaClient instance.
        vin: Vehicle Identification Number.
        day: Uppercase weekday name (e.g. MONDAY, TUESDAY).
        start: Start time as HH:MM (24h).
        end: Optional end time as HH:MM (24h).
        charge_type: Either "startOnly" or "startEnd".

    Returns:
        Dict with ``status`` and ``message`` indicating the command was queued.

    Raises:
        ToyotaApiError: If the API call returns a non-2xx response.

    """
    body = _build_charge_command("SET_CHARGING_TIME", day, start, end, charge_type)
    await client.post(VEHICLE_GLOBAL_REMOTE_ELECTRIC_CONTROL_ENDPOINT, vin=vin, body=body)
    return {
        "status": "command_queued",
        "message": "Set charging time command sent. The vehicle may take a moment to respond.",
    }


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------


def _parse_time(hhmm: str) -> dict[str, int]:
    """Parse an HH:MM string into a {"hour": int, "minute": int} dict.

    Args:
        hhmm: Time string in HH:MM 24h format.

    Returns:
        Dict with ``hour`` and ``minute`` integer keys.

    Raises:
        ValueError: If the string is not in HH:MM format or values are out of range.

    """
    parts = hhmm.split(":")
    if len(parts) != 2:
        msg = f"Invalid time format: {hhmm!r}. Expected HH:MM."
        raise ValueError(msg)
    try:
        hour = int(parts[0])
        minute = int(parts[1])
    except ValueError as exc:
        msg = f"Invalid time format: {hhmm!r}. Expected HH:MM with integer values."
        raise ValueError(msg) from exc
    if not (0 <= hour <= 23):
        msg = f"Hour must be 0-23, got {hour}."
        raise ValueError(msg)
    if not (0 <= minute <= 59):
        msg = f"Minute must be 0-59, got {minute}."
        raise ValueError(msg)
    return {"hour": hour, "minute": minute}


def _build_charge_command(
    command: str,
    day: str,
    start: str,
    end: str | None,
    charge_type: str,
) -> dict[str, Any]:
    """Build the request body for a charge command.

    Args:
        command: Command type string (RESERVE_CHARGE or SET_CHARGING_TIME).
        day: Uppercase weekday name.
        start: Start time as HH:MM.
        end: Optional end time as HH:MM.
        charge_type: "startOnly" or "startEnd".

    Returns:
        Dict suitable for the electric command endpoint body.

    """
    reservation: dict[str, Any] = {
        "chargeType": charge_type,
        "day": day,
        "startTime": _parse_time(start),
    }
    if end is not None:
        reservation["endTime"] = _parse_time(end)
    return {
        "command": command,
        "reservationCharge": reservation,
    }
