"""
Linux BenchTools - USB Device Parser
Parses output from 'lsusb -v' command
"""

import re
from typing import Dict, Any, Optional, List


def parse_lsusb_verbose(lsusb_output: str) -> Dict[str, Any]:
    """
    Parse the output of 'lsusb -v' command

    Args:
        lsusb_output: Raw text output from 'lsusb -v' command

    Returns:
        Dictionary with parsed USB device information
    """
    result = {
        "vendor_id": None,
        "product_id": None,
        "usb_device_id": None,
        "marque": None,
        "modele": None,
        "fabricant": None,
        "produit": None,
        "numero_serie": None,
        "usb_version": None,
        "device_class": None,
        "device_subclass": None,
        "device_protocol": None,
        "max_power_ma": None,
        "speed": None,
        "manufacturer": None,
        "product": None,
        "interfaces": [],
        "raw_info": {}
    }

    lines = lsusb_output.strip().split('\n')
    current_interface = None

    for line in lines:
        # Bus and Device info
        # Example: Bus 002 Device 003: ID 0781:5567 SanDisk Corp. Cruzer Blade
        match = re.match(r'Bus\s+(\d+)\s+Device\s+(\d+):\s+ID\s+([0-9a-f]{4}):([0-9a-f]{4})\s+(.*)', line)
        if match:
            result["raw_info"]["bus"] = match.group(1)
            result["raw_info"]["device"] = match.group(2)
            result["vendor_id"] = match.group(3)
            result["product_id"] = match.group(4)
            result["usb_device_id"] = f"{match.group(3)}:{match.group(4)}"

            # Parse manufacturer and product from the description
            desc = match.group(5)
            parts = desc.split(' ', 1)
            if len(parts) == 2:
                result["marque"] = parts[0]
                result["modele"] = parts[1]
            else:
                result["modele"] = desc
            continue

        # idVendor
        match = re.search(r'idVendor\s+0x([0-9a-f]{4})\s+(.*)', line)
        if match:
            if not result["vendor_id"]:
                result["vendor_id"] = match.group(1)
            result["manufacturer"] = match.group(2).strip()
            if not result["marque"]:
                result["marque"] = result["manufacturer"]
            if result.get("vendor_id") and result.get("product_id") and not result.get("usb_device_id"):
                result["usb_device_id"] = f"{result['vendor_id']}:{result['product_id']}"
            continue

        # idProduct
        match = re.search(r'idProduct\s+0x([0-9a-f]{4})\s+(.*)', line)
        if match:
            if not result["product_id"]:
                result["product_id"] = match.group(1)
            result["product"] = match.group(2).strip()
            if not result["modele"]:
                result["modele"] = result["product"]
            if result.get("vendor_id") and result.get("product_id") and not result.get("usb_device_id"):
                result["usb_device_id"] = f"{result['vendor_id']}:{result['product_id']}"
            continue

        # bcdUSB (USB version)
        match = re.search(r'bcdUSB\s+([\d.]+)', line)
        if match:
            result["usb_version"] = match.group(1)
            continue

        # bDeviceClass
        match = re.search(r'bDeviceClass\s+(\d+)\s+(.*)', line)
        if match:
            result["device_class"] = match.group(2).strip()
            result["raw_info"]["device_class_code"] = match.group(1)
            continue

        # bDeviceSubClass
        match = re.search(r'bDeviceSubClass\s+(\d+)\s*(.*)', line)
        if match:
            result["device_subclass"] = match.group(2).strip() if match.group(2) else match.group(1)
            continue

        # bDeviceProtocol
        match = re.search(r'bDeviceProtocol\s+(\d+)\s*(.*)', line)
        if match:
            result["device_protocol"] = match.group(2).strip() if match.group(2) else match.group(1)
            continue

        # MaxPower
        match = re.search(r'MaxPower\s+(\d+)mA', line)
        if match:
            result["max_power_ma"] = int(match.group(1))
            continue

        # iManufacturer
        match = re.search(r'iManufacturer\s+\d+\s+(.*)', line)
        if match and not result["manufacturer"]:
            result["manufacturer"] = match.group(1).strip()
            if not result["fabricant"]:
                result["fabricant"] = result["manufacturer"]
            continue

        # iProduct
        match = re.search(r'iProduct\s+\d+\s+(.*)', line)
        if match and not result["product"]:
            result["product"] = match.group(1).strip()
            if not result["produit"]:
                result["produit"] = result["product"]
            continue

        # iSerial
        match = re.search(r'iSerial\s+\d+\s+(.*)', line)
        if match:
            serial = match.group(1).strip()
            if serial and serial != "0":
                result["numero_serie"] = serial
            continue

        # Speed (from Device Descriptor or Status)
        match = re.search(r'Device Status:.*?Speed:\s*(\w+)', line)
        if match:
            result["speed"] = match.group(1)
            continue

        # Alternative speed detection
        if "480M" in line or "high-speed" in line.lower() or "high speed" in line.lower():
            result["speed"] = "High Speed (480 Mbps)"
        elif "5000M" in line or "super-speed" in line.lower() or "super speed" in line.lower():
            result["speed"] = "Super Speed (5 Gbps)"
        elif "10000M" in line or "superspeed+" in line.lower():
            result["speed"] = "SuperSpeed+ (10 Gbps)"
        elif "12M" in line or "full-speed" in line.lower() or "full speed" in line.lower():
            result["speed"] = "Full Speed (12 Mbps)"
        elif "1.5M" in line or "low-speed" in line.lower() or "low speed" in line.lower():
            result["speed"] = "Low Speed (1.5 Mbps)"

        # Interface information
        match = re.search(r'Interface Descriptor:', line)
        if match:
            current_interface = {}
            result["interfaces"].append(current_interface)
            continue

        if current_interface is not None:
            # bInterfaceClass
            match = re.search(r'bInterfaceClass\s+(\d+)\s+(.*)', line)
            if match:
                current_interface["class"] = match.group(2).strip()
                current_interface["class_code"] = match.group(1)
                continue

            # bInterfaceSubClass
            match = re.search(r'bInterfaceSubClass\s+(\d+)\s*(.*)', line)
            if match:
                current_interface["subclass"] = match.group(2).strip() if match.group(2) else match.group(1)
                continue

            # bInterfaceProtocol
            match = re.search(r'bInterfaceProtocol\s+(\d+)\s*(.*)', line)
            if match:
                current_interface["protocol"] = match.group(2).strip() if match.group(2) else match.group(1)
                continue

    # Clean up empty values
    for key in list(result.keys()):
        if result[key] == "" or result[key] == "0":
            result[key] = None

    # Determine peripheral type from class
    result["type_principal"] = _determine_peripheral_type(result)
    result["sous_type"] = _determine_peripheral_subtype(result)

    return result


def _determine_peripheral_type(usb_info: Dict[str, Any]) -> str:
    """Determine peripheral type from USB class information"""

    device_class = (usb_info.get("device_class") or "").lower()

    # Check interfaces if device class is not specific
    if not device_class or "vendor specific" in device_class or device_class == "0":
        interfaces = usb_info.get("interfaces", [])
        if interfaces:
            interface_class = (interfaces[0].get("class") or "").lower()
        else:
            interface_class = ""
    else:
        interface_class = device_class

    # Map USB classes to peripheral types
    class_map = {
        "hub": "USB",
        "audio": "Audio",
        "hid": "USB",
        "human interface device": "USB",
        "printer": "Imprimante",
        "mass storage": "Stockage",
        "video": "Video",
        "wireless": "Sans-fil",
        "bluetooth": "Bluetooth",
        "smart card": "Securite",
        "application specific": "USB",
        "vendor specific": "USB"
    }

    for key, ptype in class_map.items():
        if key in interface_class:
            return ptype

    # Default
    return "USB"


def _determine_peripheral_subtype(usb_info: Dict[str, Any]) -> Optional[str]:
    """Determine peripheral subtype from USB class information"""

    device_class = (usb_info.get("device_class") or "").lower()
    interfaces = usb_info.get("interfaces", [])

    if interfaces:
        interface_class = (interfaces[0].get("class") or "").lower()
        interface_subclass = (interfaces[0].get("subclass") or "").lower()
    else:
        interface_class = ""
        interface_subclass = ""

    # HID devices
    if "hid" in device_class or "hid" in interface_class or "human interface" in interface_class:
        if "mouse" in interface_subclass or "mouse" in str(usb_info.get("modele", "")).lower():
            return "Souris"
        elif "keyboard" in interface_subclass or "keyboard" in str(usb_info.get("modele", "")).lower():
            return "Clavier"
        elif "gamepad" in interface_subclass or "joystick" in interface_subclass:
            return "Manette"
        else:
            return "Peripherique HID"

    # Mass storage
    if "mass storage" in interface_class:
        model = str(usb_info.get("modele", "")).lower()
        if "card reader" in model or "reader" in model:
            return "Lecteur de cartes"
        else:
            return "Cle USB"

    # Audio
    if "audio" in interface_class:
        if "microphone" in interface_subclass:
            return "Microphone"
        elif "speaker" in interface_subclass:
            return "Haut-parleur"
        else:
            return "Audio"

    # Video
    if "video" in interface_class:
        return "Webcam"

    # Wireless
    if "wireless" in interface_class or "bluetooth" in interface_class:
        if "bluetooth" in interface_class:
            return "Bluetooth"
        else:
            return "Adaptateur sans-fil"

    # Printer
    if "printer" in interface_class:
        return "Imprimante"

    return None


def parse_lsusb_simple(lsusb_output: str) -> List[Dict[str, Any]]:
    """
    Parse the output of simple 'lsusb' command (without -v)

    Args:
        lsusb_output: Raw text output from 'lsusb' command

    Returns:
        List of dictionaries with basic USB device information
    """
    devices = []

    for line in lsusb_output.strip().split('\n'):
        # Example: Bus 002 Device 003: ID 0781:5567 SanDisk Corp. Cruzer Blade
        match = re.match(r'Bus\s+(\d+)\s+Device\s+(\d+):\s+ID\s+([0-9a-f]{4}):([0-9a-f]{4})\s+(.*)', line)
        if match:
            desc = match.group(5)
            parts = desc.split(' ', 1)

            device = {
                "bus": match.group(1),
                "device": match.group(2),
                "vendor_id": match.group(3),
                "product_id": match.group(4),
                "marque": parts[0] if len(parts) >= 1 else None,
                "modele": parts[1] if len(parts) == 2 else desc,
                "type_principal": "USB",
                "sous_type": None
            }
            devices.append(device)

    return devices


def create_device_name(usb_info: Dict[str, Any]) -> str:
    """Generate a readable device name from USB info"""
    parts = []

    if usb_info.get("marque"):
        parts.append(usb_info["marque"])

    if usb_info.get("modele"):
        parts.append(usb_info["modele"])

    if not parts:
        parts.append("Peripherique USB")
        if usb_info.get("vendor_id") and usb_info.get("product_id"):
            parts.append(f"({usb_info['vendor_id']}:{usb_info['product_id']})")

    return " ".join(parts)
