from __future__ import annotations

import asyncio
import json
import logging
import sys
from pathlib import Path
from typing import Any


class JsonEventHandler(logging.Handler):
    def __init__(self, emit_event):
        super().__init__()
        self.emit_event = emit_event

    def emit(self, record: logging.LogRecord) -> None:
        try:
            loop = asyncio.get_running_loop()
        except RuntimeError:
            return
        message = self.format(record)
        loop.call_soon_threadsafe(
            asyncio.create_task,
            self.emit_event("log", {"message": message}),
        )


async def write_message(payload: dict[str, Any]) -> None:
    sys.stdout.write(json.dumps(payload, default=str) + "\n")
    sys.stdout.flush()


async def emit_event(name: str, data: Any) -> None:
    await write_message({"event": name, "data": data})


async def main() -> None:
    repo_root = Path(__file__).resolve().parent.parent
    sys.path.insert(0, str(repo_root / "standalone_bridge"))
    try:
        from runtime import PrimeChargerRuntime
    except ModuleNotFoundError as err:
        print(
            f"Missing Python dependency: {err.name}. Install standalone_bridge/requirements.txt first.",
            file=sys.stderr,
        )
        raise SystemExit(1) from err

    runtime = PrimeChargerRuntime(emit_event=emit_event)

    logger = logging.getLogger("anker_prime_bridge")
    logger.handlers.clear()
    logger.setLevel(logging.INFO)
    handler = JsonEventHandler(emit_event)
    handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
    logger.addHandler(handler)

    await emit_event("status", {"message": "Helper ready"})

    try:
        while True:
            line = await asyncio.to_thread(sys.stdin.readline)
            if not line:
                break
            line = line.strip()
            if not line:
                continue
            try:
                request = json.loads(line)
                request_id = request["id"]
                method = request["method"]
                params = request.get("params") or {}
                result = await dispatch(runtime, method, params)
                await write_message({"id": request_id, "result": result})
            except Exception as err:  # noqa: BLE001
                request_id = locals().get("request_id")
                await write_message(
                    {
                        "id": request_id,
                        "error": {
                            "code": err.__class__.__name__,
                            "message": str(err),
                        },
                    }
                )
    finally:
        await runtime.close()


async def dispatch(runtime: PrimeChargerRuntime, method: str, params: dict[str, Any]) -> Any:
    if method == "login":
        return await runtime.login(
            email=params["email"],
            password=params["password"],
            country=params.get("country", "US"),
            debug=bool(params.get("debug", False)),
            restart=bool(params.get("restart", False)),
        )
    if method == "logout":
        return await runtime.logout()
    if method == "connect_device":
        return await runtime.connect_device(
            device_sn=params["deviceSN"],
            refresh_interval=int(params.get("refreshInterval", 300)),
            reconnect_interval=int(params.get("reconnectInterval", 60)),
            polling_fallback=bool(params.get("pollingFallback", True)),
            debug=bool(params.get("debug", False)),
        )
    if method == "refresh":
        return await runtime.refresh()
    if method == "reconnect":
        return await runtime.reconnect()
    if method == "set_port_switch":
        return await runtime.set_port_switch(
            port_key=params["portKey"],
            enabled=bool(params["enabled"]),
        )
    raise RuntimeError(f"Unsupported method: {method}")


if __name__ == "__main__":
    asyncio.run(main())
