"""Fetch Tesla State of Health from the Fleet API and print the JSON payload."""

from __future__ import annotations

import json
import logging
import os
import sys
from datetime import datetime, timezone
from typing import Any, Dict, List

import requests


EU_BASE = os.getenv("TESLA_FLEET_BASE", "https://fleet-api.prd.eu.vn.cloud.tesla.com")
AUTH_BASE = os.getenv("TESLA_AUTH_BASE", "https://auth.tesla.com/oauth2/v3")
TESLA_VIN = os.getenv("TESLA_VIN")

SCOPES = os.getenv(
    "TESLA_OAUTH_SCOPES",
    "openid offline_access vehicle_device_data vehicle_energy_data",
).split()

LOG_LEVEL = os.getenv("TESLA_SOH_LOG_LEVEL", "INFO").upper()
logging.basicConfig(
    level=getattr(logging, LOG_LEVEL, logging.INFO),
    format="%(asctime)s %(levelname)s %(message)s",
)
logger = logging.getLogger(__name__)


def require_env(var_name: str) -> str:
    value = os.getenv(var_name)
    if not value:
        logger.error("Environment variable %s is required", var_name)
        raise SystemExit(1)
    return value


def refresh_access_token() -> str:
    """Refresh the OAuth access token using the stored refresh token."""

    payload = {
        "grant_type": "refresh_token",
        "client_id": require_env("TESLA_CLIENT_ID"),
        "client_secret": require_env("TESLA_CLIENT_SECRET"),
        "refresh_token": require_env("TESLA_REFRESH_TOKEN"),
        "redirect_uri": require_env("TESLA_REDIRECT_URI"),
        "scope": " ".join(SCOPES),
    }
    logger.debug("Refreshing access token at %s/token", AUTH_BASE)
    response = requests.post(f"{AUTH_BASE}/token", data=payload, timeout=30)
    response.raise_for_status()
    token = response.json()["access_token"]
    logger.info("Obtained new access token")
    return token


def list_vehicles(token: str) -> List[Dict[str, Any]]:
    """Return all vehicles for the account."""

    url = f"{EU_BASE}/api/1/vehicles"
    logger.debug("Requesting vehicle list from %s", url)
    response = requests.get(url, headers={"Authorization": f"Bearer {token}"}, timeout=30)
    response.raise_for_status()
    vehicles = response.json().get("response", [])
    logger.info("Retrieved %d vehicles", len(vehicles))
    return vehicles


def select_vehicle(vehicles: List[Dict[str, Any]], vin: str | None) -> Dict[str, Any]:
    """Select the vehicle that matches the VIN or the first entry."""

    if not vehicles:
        logger.error("No vehicles returned by the Tesla API")
        raise SystemExit(2)

    if vin:
        for vehicle in vehicles:
            if vehicle.get("vin") == vin:
                logger.info("Selected vehicle with VIN %s", vin)
                return vehicle
        logger.error("VIN %s not found in Tesla account", vin)
        raise SystemExit(3)

    vehicle = vehicles[0]
    logger.info("No VIN provided, using first vehicle with VIN %s", vehicle.get("vin"))
    return vehicle


def fetch_battery_health(token: str, vehicle: Dict[str, Any]) -> Dict[str, Any]:
    """Fetch the SoH payload via the Fleet API."""

    vehicle_id = vehicle.get("id") or vehicle.get("vin")
    if not vehicle_id:
        logger.error("Vehicle entry is missing both VIN and id fields: %s", vehicle)
        raise SystemExit(4)

    params = {"endpoints": "battery_health"}
    url = f"{EU_BASE}/api/1/vehicles/{vehicle_id}/vehicle_data"
    logger.debug("Requesting battery health from %s", url)
    response = requests.get(
        url,
        headers={"Authorization": f"Bearer {token}"},
        params=params,
        timeout=45,
    )
    response.raise_for_status()
    payload = response.json().get("response", {})
    logger.debug("Battery health payload: %s", payload)
    return payload


def main() -> None:
    try:
        token = refresh_access_token()
        vehicles = list_vehicles(token)
        vehicle = select_vehicle(vehicles, TESLA_VIN)
        battery_health = fetch_battery_health(token, vehicle)
    except requests.RequestException as exc:
        logger.error("HTTP error while contacting Tesla API: %s", exc)
        raise SystemExit(5) from exc

    result = {
        "ts": datetime.now(timezone.utc).isoformat(),
        "vin": vehicle.get("vin"),
        "battery_health": battery_health,
    }
    json.dump(result, sys.stdout, ensure_ascii=False)
    sys.stdout.write("\n")
    logger.info("Successfully retrieved battery health for VIN %s", vehicle.get("vin"))


if __name__ == "__main__":
    main()