"""Cliente de integração com a API MyGeotab."""
from datetime import datetime, timedelta, timezone
import mygeotab

from . import config

# IDs de diagnostico padrao do sistema Geotab
DIAGNOSTIC_ODOMETER = "DiagnosticOdometerId"
DIAGNOSTIC_ENGINE_ODOMETER = "DiagnosticEngineOdometerId"
DIAGNOSTIC_ENGINE_HOURS = "DiagnosticEngineHoursId"

# Janelas de busca (dias) tentadas em ordem ate encontrar dado recente
LOOKBACK_WINDOWS_DAYS = [3, 14, 30, 90, 365]


class GeotabClient:
    """
    Por padrao le as credenciais salvas localmente (security.load_geotab_credentials()).
    Um dict `credentials` explicito pode ser passado (usado pelo wizard de setup
    para testar um login antes de salvar).
    """

    def __init__(self, credentials: dict | None = None):
        self._api = None
        self._credentials = credentials

    def _resolve_credentials(self):
        if self._credentials:
            return self._credentials
        from . import security
        creds = security.load_geotab_credentials()
        if not creds:
            raise RuntimeError("Credenciais do Geotab não configuradas.")
        return creds

    @property
    def api(self):
        if self._api is None:
            creds = self._resolve_credentials()
            self._api = mygeotab.API(
                username=creds["username"],
                password=creds["password"],
                database=creds.get("database") or None,
                server=creds.get("server") or "my.geotab.com",
            )
            self._api.authenticate()
        return self._api

    def get_devices(self):
        """Retorna todos os veiculos (trucks) ativos cadastrados no Geotab."""
        devices = self.api.get("Device")
        return [d for d in devices if not d.get("isDisabled", False)]

    def _latest_status_data_all_devices(self, diagnostic_id, window_days):
        from_date = (datetime.now(timezone.utc) - timedelta(days=window_days)).isoformat()
        to_date = datetime.now(timezone.utc).isoformat()
        results = self.api.get(
            "StatusData",
            search={
                "diagnosticSearch": {"id": diagnostic_id},
                "fromDate": from_date,
                "toDate": to_date,
            },
        )
        latest_by_device = {}
        for record in results:
            device_id = record["device"]["id"]
            record_time = record["dateTime"]
            current = latest_by_device.get(device_id)
            if current is None or record_time > current["dateTime"]:
                latest_by_device[device_id] = record
        return latest_by_device

    def get_latest_diagnostic_for_all_devices(self, diagnostic_id, expected_device_ids=None):
        """
        Busca o valor mais recente de um diagnostico para todos os veiculos,
        expandindo a janela de busca ate encontrar dado (trucks parados/sem sinal
        recente ainda aparecem se tiverem histórico mais antigo).
        """
        merged = {}
        for window_days in LOOKBACK_WINDOWS_DAYS:
            batch = self._latest_status_data_all_devices(diagnostic_id, window_days)
            for device_id, record in batch.items():
                if device_id not in merged:
                    merged[device_id] = record
            if expected_device_ids is not None and expected_device_ids.issubset(merged.keys()):
                break
        return merged

    def get_odometer_miles_and_engine_hours(self, device_ids=None):
        """
        Retorna dict device_id -> {"odometer_miles": float|None, "odometer_date": str|None,
                                    "engine_hours": float|None, "engine_hours_date": str|None}
        """
        expected = set(device_ids) if device_ids else None
        odometer_data = self.get_latest_diagnostic_for_all_devices(DIAGNOSTIC_ODOMETER, expected)
        hours_data = self.get_latest_diagnostic_for_all_devices(DIAGNOSTIC_ENGINE_HOURS, expected)

        result = {}
        device_ids = set(odometer_data.keys()) | set(hours_data.keys())
        for device_id in device_ids:
            odo_record = odometer_data.get(device_id)
            hrs_record = hours_data.get(device_id)
            result[device_id] = {
                "odometer_miles": (odo_record["data"] / config.METERS_PER_MILE) if odo_record else None,
                "odometer_date": odo_record["dateTime"] if odo_record else None,
                # DiagnosticEngineHoursId vem em segundos, nao em horas
                "engine_hours": (hrs_record["data"] / 3600) if hrs_record else None,
                "engine_hours_date": hrs_record["dateTime"] if hrs_record else None,
            }
        return result


def get_geotab_client(credentials: dict | None = None) -> "GeotabClient":
    """Cria uma instancia nova a cada chamada (evita reaproveitar sessao expirada)."""
    return GeotabClient(credentials=credentials)
