#!/usr/bin/env python3
"""Simple test client that exercises all pybyd endpoints.

Reads credentials from environment variables and prints structured
output from every available API endpoint.

Usage:
    export BYD_USERNAME="your@email.com"
    export BYD_PASSWORD="yourpassword"
    export BYD_COUNTRY_CODE="NL"        # optional, default NL
    python scripts/test_client.py

Optional flags:
    --skip-control   Skip remote control commands (lock/unlock/etc.)
    --vin VIN        Target a specific VIN (default: first vehicle)
"""

from __future__ import annotations

import argparse
import asyncio
import logging
import sys
from typing import TYPE_CHECKING, Any

from pybyd import (
    BydApiError,
    BydClient,
    BydConfig,
    BydRemoteControlError,
    RemoteCommand,
)

if TYPE_CHECKING:
    from pybyd import (
        EnergyConsumption,
        GpsInfo,
        RemoteControlResult,
        Vehicle,
        VehicleRealtimeData,
    )

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s  %(levelname)-8s  %(name)s  %(message)s",
    datefmt="%H:%M:%S",
)
_logger = logging.getLogger("test_client")


# ── Pretty-printers ─────────────────────────────────────────────


def _header(title: str) -> None:
    width = 60
    print()
    print("=" * width)
    print(f"  {title}")
    print("=" * width)


def _field(label: str, value: Any, unit: str = "") -> None:
    suffix = f" {unit}" if unit and value is not None else ""
    print(f"  {label:<30s}  {value}{suffix}")


def _print_vehicle(v: Vehicle, index: int) -> None:
    print(f"\n  [{index}] {v.model_name or '(unknown model)'}")
    _field("VIN", v.vin)
    _field("Brand", v.brand_name)
    _field("Energy type", v.energy_type)
    _field("Alias", v.auto_alias or "(none)")
    _field("Plate", v.auto_plate or "(none)")


def _print_realtime(rt: VehicleRealtimeData) -> None:
    _header("REALTIME TELEMETRY")
    _field("Online state", rt.online_state, "(1=on, 2=off)")
    _field("Vehicle state", rt.vehicle_state)
    _field("Battery", rt.elec_percent, "%")
    _field("Range", rt.endurance_mileage, "km")
    _field("Odometer", rt.total_mileage, "km")
    _field("Speed", rt.speed, "km/h")
    _field("Cabin temperature", rt.temp_in_car, "C")
    _field("Charging state", rt.charging_state)
    print()
    _field("Left front door", rt.left_front_door)
    _field("Right front door", rt.right_front_door)
    _field("Left rear door", rt.left_rear_door)
    _field("Right rear door", rt.right_rear_door)
    _field("Trunk lid", rt.trunk_lid)
    print()
    _field("Tire LF", rt.left_front_tire_pressure, "bar")
    _field("Tire RF", rt.right_front_tire_pressure, "bar")
    _field("Tire LR", rt.left_rear_tire_pressure, "bar")
    _field("Tire RR", rt.right_rear_tire_pressure, "bar")
    print()
    _field("Timestamp", rt.timestamp)
    _field("Request serial", rt.request_serial)


def _print_gps(gps: GpsInfo) -> None:
    _header("GPS LOCATION")
    _field("Latitude", gps.latitude)
    _field("Longitude", gps.longitude)
    _field("Speed", gps.speed, "km/h")
    _field("Direction", gps.direction, "deg")
    _field("GPS timestamp", gps.gps_timestamp)
    _field("Request serial", gps.request_serial)


def _print_energy(ec: EnergyConsumption) -> None:
    _header("ENERGY CONSUMPTION")
    _field("VIN", ec.vin)
    _field("Total energy", ec.total_energy)
    _field("Avg consumption", ec.avg_energy_consumption)
    _field("Electricity", ec.electricity_consumption)
    _field("Fuel", ec.fuel_consumption)


def _print_control_result(cmd: RemoteCommand, rc: RemoteControlResult) -> None:
    status_map = {0: "PENDING", 1: "SUCCESS", 2: "FAILED"}
    state_label = status_map.get(rc.control_state, str(rc.control_state))
    _field(f"{cmd.name}", f"{state_label} (success={rc.success})")


# ── Main routine ─────────────────────────────────────────────────


async def run(args: argparse.Namespace) -> None:
    try:
        config = BydConfig.from_env()
    except (TypeError, KeyError) as exc:
        _logger.error(
            "Missing credentials. Set BYD_USERNAME and BYD_PASSWORD environment variables. (%s)",
            exc,
        )
        sys.exit(1)

    _logger.info("Connecting to %s as %s", config.base_url, config.username)

    async with BydClient(config) as client:
        # ── 1. Login ─────────────────────────────────────────
        _header("LOGIN")
        token = await client.login()
        _field("User ID", token.user_id)
        _field("Sign token", token.sign_token[:16] + "...")
        _field("Encry token", token.encry_token[:16] + "...")

        # ── 2. Vehicle list ──────────────────────────────────
        _header("VEHICLES")
        vehicles = await client.get_vehicles()
        if not vehicles:
            _logger.warning("No vehicles found on this account.")
            return

        for i, v in enumerate(vehicles):
            _print_vehicle(v, i)

        # Pick target VIN
        vin = args.vin
        if vin:
            if not any(v.vin == vin for v in vehicles):
                _logger.error("VIN %s not found in vehicle list.", vin)
                sys.exit(1)
        else:
            vin = vehicles[0].vin

        _logger.info("Target VIN: %s", vin)

        # ── 3. Realtime telemetry ────────────────────────────
        try:
            rt = await client.get_vehicle_realtime(vin)
            _print_realtime(rt)
        except BydApiError as exc:
            _logger.warning("Realtime data failed: %s", exc)

        # ── 4. GPS ───────────────────────────────────────────
        try:
            gps = await client.get_gps_info(vin)
            _print_gps(gps)
        except BydApiError as exc:
            _logger.warning("GPS data failed: %s", exc)

        # ── 5. Energy consumption ────────────────────────────
        try:
            ec = await client.get_energy_consumption(vin)
            _print_energy(ec)
        except BydApiError as exc:
            _logger.warning("Energy consumption failed: %s", exc)

        # ── 6. Remote control (optional) ─────────────────────
        if args.skip_control:
            _logger.info("Skipping remote control commands (--skip-control)")
        else:
            _header("REMOTE CONTROL")
            # Only test flash lights — safest non-destructive command
            _logger.info("Sending FLASH_LIGHTS command...")
            try:
                rc = await client.flash_lights(vin)
                _print_control_result(RemoteCommand.FLASH_LIGHTS, rc)
            except BydRemoteControlError as exc:
                _logger.warning("Flash lights failed: %s", exc)
            except BydApiError as exc:
                _logger.warning("Flash lights API error: %s", exc)

    _header("DONE")
    print("  All endpoint tests completed.\n")


def main() -> None:
    parser = argparse.ArgumentParser(
        description="Test client for the pybyd library.",
    )
    parser.add_argument(
        "--skip-control",
        action="store_true",
        help="Skip remote control commands (lock/unlock/flash/etc.)",
    )
    parser.add_argument(
        "--vin",
        type=str,
        default="",
        help="Target a specific VIN (default: first vehicle)",
    )
    args = parser.parse_args()
    asyncio.run(run(args))


if __name__ == "__main__":
    main()
