from __future__ import annotations

import asyncio
from importlib.metadata import version
from typing import TypedDict

from bleak import BleakClient, BleakScanner
from bleak.exc import BleakDeviceNotFoundError

from k1link.artifacts import utc_now_iso


class DescriptorRecord(TypedDict):
    uuid: str
    handle: int
    description: str


class CharacteristicRecord(TypedDict):
    uuid: str
    handle: int
    description: str
    properties: list[str]
    descriptors: list[DescriptorRecord]


class ServiceRecord(TypedDict):
    uuid: str
    handle: int
    description: str
    characteristics: list[CharacteristicRecord]


class GattDumpResult(TypedDict):
    schema_version: int
    started_at_utc: str
    completed_at_utc: str
    adapter: str
    bleak_version: str
    device_macos_uuid: str
    device_name: str
    metadata_only: bool
    services: list[ServiceRecord]


async def dump_metadata(device_macos_uuid: str, timeout_seconds: float) -> GattDumpResult:
    """Connect and enumerate GATT metadata without characteristic reads or writes."""
    if timeout_seconds <= 0:
        raise ValueError("timeout_seconds must be positive")

    started_at = utc_now_iso()
    async with asyncio.timeout(timeout_seconds):
        device = await BleakScanner.find_device_by_address(
            device_macos_uuid,
            timeout=min(20.0, timeout_seconds),
        )
        if device is None:
            raise BleakDeviceNotFoundError(
                device_macos_uuid,
                "Device was not rediscovered; keep the K1 powered and nearby.",
            )

        async with BleakClient(device, timeout=timeout_seconds, pair=False) as client:
            services: list[ServiceRecord] = []
            for service in client.services:
                characteristics: list[CharacteristicRecord] = []
                for characteristic in service.characteristics:
                    descriptors: list[DescriptorRecord] = []
                    for descriptor in characteristic.descriptors:
                        descriptors.append(
                            {
                                "uuid": descriptor.uuid,
                                "handle": descriptor.handle,
                                "description": descriptor.description,
                            }
                        )
                    characteristics.append(
                        {
                            "uuid": characteristic.uuid,
                            "handle": characteristic.handle,
                            "description": characteristic.description,
                            "properties": sorted(characteristic.properties),
                            "descriptors": descriptors,
                        }
                    )
                services.append(
                    {
                        "uuid": service.uuid,
                        "handle": service.handle,
                        "description": service.description,
                        "characteristics": characteristics,
                    }
                )
            return {
                "schema_version": 1,
                "started_at_utc": started_at,
                "completed_at_utc": utc_now_iso(),
                "adapter": "CoreBluetooth",
                "bleak_version": version("bleak"),
                "device_macos_uuid": device_macos_uuid,
                "device_name": client.name,
                "metadata_only": True,
                "services": services,
            }
