"""Service for PX4 parameter upload operations."""

import json
from typing import AsyncGenerator

from mavsdk import System


async def upload_parameters(
    param_file_path: str,
    port: str,
    baudrate: int,
) -> AsyncGenerator[str, None]:
    """Upload PX4 parameters from a .params file, streaming progress via SSE."""

    drone = None
    try:
        drone = System()
        serial = f"serial://{port}:{baudrate}"

        yield "data: {}\n\n".format(
            json.dumps({"type": "status", "message": f"Connecting to {port}..."})
        )
        await drone.connect(system_address=serial)
        yield "data: {}\n\n".format(
            json.dumps({"type": "status", "message": "Connected to device"})
        )

        param_plugin = drone.param
        yield "data: {}\n\n".format(
            json.dumps({"type": "status", "message": "Fetching current parameters..."})
        )
        params = await param_plugin.get_all_params()
        float_params = params.float_params
        int_params = params.int_params
        custom_params = params.custom_params
        int_param_names = [p.name for p in int_params]
        float_param_names = [p.name for p in float_params]
        custom_param_names = [p.name for p in custom_params]

        yield "data: {}\n\n".format(
            json.dumps({"type": "status", "message": "Checking if vehicle is landed..."})
        )
        async for is_in_air in drone.telemetry.in_air():
            if is_in_air:
                yield "data: {}\n\n".format(
                    json.dumps(
                        {
                            "type": "warning",
                            "message": "Waiting until vehicle is landed...",
                        }
                    )
                )
            else:
                break

        yield "data: {}\n\n".format(
            json.dumps(
                {
                    "type": "status",
                    "message": "Uploading parameters... Please do not arm the vehicle!",
                }
            )
        )

        with open(param_file_path, "r", encoding="utf-8") as param_file:
            total_lines = sum(
                1 for line in param_file if line.strip() and not line.startswith("#")
            )

        uploaded_count = 0
        with open(param_file_path, "r", encoding="utf-8") as param_file:
            for line in param_file:
                if line.startswith("#") or not line.strip():
                    continue

                columns = line.strip().split(",")
                if len(columns) < 2:
                    continue

                name = columns[0].strip()
                value = columns[1].strip()

                try:
                    if name in int_param_names:
                        await drone.param.set_param_int(name, int(value))
                    elif name in float_param_names:
                        await drone.param.set_param_float(name, float(value))
                    elif name in custom_param_names:
                        await drone.param.set_param_custom(name, value)
                    else:
                        yield "data: {}\n\n".format(
                            json.dumps(
                                {
                                    "type": "warning",
                                    "message": f"Parameter {name} not found, skipping",
                                }
                            )
                        )
                        continue

                    uploaded_count += 1
                    yield "data: {}\n\n".format(
                        json.dumps(
                            {
                                "type": "progress",
                                "message": f"Uploaded {name} = {value}",
                                "progress": uploaded_count,
                                "total": total_lines,
                            }
                        )
                    )
                except Exception as exc:  # pragma: no cover - streaming generator
                    yield "data: {}\n\n".format(
                        json.dumps(
                            {
                                "type": "error",
                                "message": f"Failed to set {name}: {exc}",
                            }
                        )
                    )

        yield "data: {}\n\n".format(
            json.dumps({"type": "status", "message": "Parameters uploaded, rebooting..."})
        )
        await drone.action.reboot()
        yield "data: {}\n\n".format(
            json.dumps(
                {
                    "type": "success",
                    "message": "Parameters uploaded and vehicle rebooted",
                }
            )
        )

    except Exception as exc:  # pragma: no cover - streaming generator
        yield "data: {}\n\n".format(
            json.dumps(
                {
                    "type": "error",
                    "message": f"Parameter upload failed: {exc}",
                }
            )
        )
        raise
    finally:
        if drone:
            # No explicit teardown required
            pass

