"""tyta vehicles subcommands: list, use, capabilities, features, subscriptions."""

from __future__ import annotations

import asyncio
import json
import sys
from typing import Annotated

import typer

from tyta.cli import render
from tyta.core import auth as core_auth
from tyta.core import config as core_config
from tyta.core import envelope as env
from tyta.core import vehicles as core_vehicles
from tyta.core.client import ToyotaApiError, ToyotaClient

app = typer.Typer(
    name="vehicles",
    help="Manage vehicles linked to your Toyota account.",
    no_args_is_help=True,
)


def _get_state() -> dict:
    from tyta.cli.main import _get_state as _gs

    return _gs()


def _is_json_mode() -> bool:
    return _get_state().get("json", False)


def _load_config() -> dict:
    config_path = core_config.get_config_path(_get_state().get("config_file"))
    try:
        return core_config.load_config(config_path)
    except Exception:  # noqa: BLE001
        return {}


def _emit_and_exit(data: dict, exit_code: int = 0, command: str = "") -> None:
    json_mode = _is_json_mode()
    if exit_code != 0:
        render.render_error(data, json_mode)
    else:
        render.render_output(data, json_mode, command, config=_load_config())
    sys.exit(exit_code)


@app.command("list")
def vehicles_list() -> None:
    """List all vehicles linked to the account."""
    asyncio.run(_vehicles_list())


async def _vehicles_list() -> None:
    state = _get_state()
    debug = state.get("debug", False)
    auth_path = core_auth.get_auth_path(state.get("auth_file"))

    try:
        token_data = await core_auth.get_valid_token(auth_path)
    except core_auth.NotAuthenticatedError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except core_auth.TokenExpiredError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except json.JSONDecodeError:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("invalid_config", "Token file is malformed JSON."), exit_code=1)
        return

    client = ToyotaClient(
        access_token=token_data["access_token"],
        uuid=token_data["uuid"],
    )

    try:
        vehicles = await core_vehicles.list_vehicles(client)
    except ToyotaApiError as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("api_error", f"Toyota API error: {exc.message}"), exit_code=1)
        return
    except Exception as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("unknown_error", str(exc)), exit_code=1)
        return

    # Produce a simplified representation of each vehicle
    summary = [
        {
            "vin": v.get("vin"),
            "nickname": v.get("nickName"),
            "model_name": v.get("modelName"),
            "model_year": v.get("modelYear"),
            "color": v.get("color"),
            "brand": v.get("brand"),
            "fuel_type": v.get("fuelType"),
            "ev_vehicle": v.get("evVehicle"),
        }
        for v in vehicles
    ]

    _emit_and_exit(env.ok({"vehicles": summary}), command="vehicles list")


@app.command("use")
def vehicles_use(
    vin: Annotated[str, typer.Argument(help="VIN to set as default.")],
) -> None:
    """Set the default vehicle VIN (validates against API)."""
    asyncio.run(_vehicles_use(vin))


async def _vehicles_use(vin: str) -> None:
    state = _get_state()
    debug = state.get("debug", False)
    auth_path = core_auth.get_auth_path(state.get("auth_file"))
    config_path = state.get("config_file")

    try:
        token_data = await core_auth.get_valid_token(auth_path)
    except core_auth.NotAuthenticatedError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except core_auth.TokenExpiredError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except json.JSONDecodeError:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("invalid_config", "Token file is malformed JSON."), exit_code=1)
        return

    client = ToyotaClient(
        access_token=token_data["access_token"],
        uuid=token_data["uuid"],
    )

    try:
        await core_vehicles.set_default_vin(client, vin, config_path)
    except core_vehicles.VehicleNotFoundError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except core_vehicles.NoVehiclesError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except ToyotaApiError as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("api_error", f"Toyota API error: {exc.message}"), exit_code=1)
        return
    except Exception as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("unknown_error", str(exc)), exit_code=1)
        return

    _emit_and_exit(env.ok({"message": f"Default VIN set to '{vin}'."}), command="vehicles use")


# ---------------------------------------------------------------------------
# Shared helper: authenticate + resolve VIN
# ---------------------------------------------------------------------------


async def _auth_and_resolve_vin(
    vin_flag: str | None,
) -> tuple[ToyotaClient, str, list[str]] | None:
    """Authenticate and resolve VIN. Returns (client, vin, warnings) or calls _emit_and_exit and returns None."""
    state = _get_state()
    debug = state.get("debug", False)
    auth_path = core_auth.get_auth_path(state.get("auth_file"))
    config_path = state.get("config_file")

    try:
        token_data = await core_auth.get_valid_token(auth_path)
    except core_auth.NotAuthenticatedError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return None
    except core_auth.TokenExpiredError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return None
    except json.JSONDecodeError:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("invalid_config", "Token file is malformed JSON."), exit_code=1)
        return None

    client = ToyotaClient(
        access_token=token_data["access_token"],
        uuid=token_data["uuid"],
    )

    try:
        vin, warnings = await core_vehicles.resolve_vin(
            client, vin_flag=vin_flag, config_path=config_path
        )
    except core_vehicles.VehicleNotFoundError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return None
    except core_vehicles.NoVehiclesError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return None
    except ToyotaApiError as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("api_error", f"Toyota API error: {exc.message}"), exit_code=1)
        return None
    except Exception as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("unknown_error", str(exc)), exit_code=1)
        return None

    return client, vin, warnings


# ---------------------------------------------------------------------------
# capabilities
# ---------------------------------------------------------------------------


@app.command("capabilities")
def vehicles_capabilities(
    vin: Annotated[str | None, typer.Option("--vin", help="Vehicle VIN.")] = None,
    show_all: Annotated[
        bool, typer.Option("--all", help="Show all flags including false.")
    ] = False,
) -> None:
    """Show hardware and remote service capability flags."""
    asyncio.run(_vehicles_capabilities(vin, show_all))


async def _vehicles_capabilities(vin_flag: str | None, show_all: bool) -> None:
    state = _get_state()
    debug = state.get("debug", False)

    result = await _auth_and_resolve_vin(vin_flag)
    if result is None:
        return
    client, vin, warnings = result

    try:
        vehicle = await core_vehicles.get_vehicle(client, vin)
    except core_vehicles.VehicleNotFoundError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except core_vehicles.NoVehiclesError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except ToyotaApiError as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("api_error", f"Toyota API error: {exc.message}"), exit_code=1)
        return
    except Exception as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("unknown_error", str(exc)), exit_code=1)
        return

    extended = vehicle.get("extendedCapabilities") or {}
    remote = vehicle.get("remoteServiceCapabilities") or {}

    if not show_all:
        extended = {k: v for k, v in extended.items() if v is True}
        remote = {k: v for k, v in remote.items() if v is True}

    data = env.ok(
        {"vin": vin, "extended_capabilities": extended, "remote_service_capabilities": remote},
        warnings=warnings,
    )
    _emit_and_exit(data, command="vehicles capabilities")


# ---------------------------------------------------------------------------
# features
# ---------------------------------------------------------------------------


@app.command("features")
def vehicles_features(
    vin: Annotated[str | None, typer.Option("--vin", help="Vehicle VIN.")] = None,
    show_all: Annotated[
        bool, typer.Option("--all", help="Show all flags including false.")
    ] = False,
) -> None:
    """Show connected service feature flags."""
    asyncio.run(_vehicles_features(vin, show_all))


async def _vehicles_features(vin_flag: str | None, show_all: bool) -> None:
    state = _get_state()
    debug = state.get("debug", False)

    result = await _auth_and_resolve_vin(vin_flag)
    if result is None:
        return
    client, vin, warnings = result

    try:
        vehicle = await core_vehicles.get_vehicle(client, vin)
    except core_vehicles.VehicleNotFoundError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except core_vehicles.NoVehiclesError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except ToyotaApiError as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("api_error", f"Toyota API error: {exc.message}"), exit_code=1)
        return
    except Exception as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("unknown_error", str(exc)), exit_code=1)
        return

    features = vehicle.get("features") or {}

    if not show_all:
        features = {k: v for k, v in features.items() if v is True}

    data = env.ok({"vin": vin, "features": features}, warnings=warnings)
    _emit_and_exit(data, command="vehicles features")


# ---------------------------------------------------------------------------
# subscriptions
# ---------------------------------------------------------------------------


@app.command("subscriptions")
def vehicles_subscriptions(
    vin: Annotated[str | None, typer.Option("--vin", help="Vehicle VIN.")] = None,
) -> None:
    """Show subscription products for the vehicle."""
    asyncio.run(_vehicles_subscriptions(vin))


async def _vehicles_subscriptions(vin_flag: str | None) -> None:
    state = _get_state()
    debug = state.get("debug", False)

    result = await _auth_and_resolve_vin(vin_flag)
    if result is None:
        return
    client, vin, warnings = result

    try:
        vehicle = await core_vehicles.get_vehicle(client, vin)
    except core_vehicles.VehicleNotFoundError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except core_vehicles.NoVehiclesError as exc:
        _emit_and_exit(env.error(exc.code, exc.message), exit_code=1)
        return
    except ToyotaApiError as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("api_error", f"Toyota API error: {exc.message}"), exit_code=1)
        return
    except Exception as exc:
        if debug:
            import traceback

            traceback.print_exc(file=sys.stderr)
        _emit_and_exit(env.error("unknown_error", str(exc)), exit_code=1)
        return

    subscriptions = vehicle.get("subscriptions") or []

    data = env.ok({"vin": vin, "subscriptions": subscriptions}, warnings=warnings)
    _emit_and_exit(data, command="vehicles subscriptions")
