#!/usr/bin/env python3
"""K2Aley GAR-BOT remote transmitter starter.

Runs on Raspberry Pi Zero 2 W + Pico Voice. The Zero 2 W Wi-Fi path is used
for SSH/setup/LAN tests; LoRa is the field-control path. The Arduino Pro Mini
and redundant short-range radio design have been removed from the transmitter.
"""

from __future__ import annotations

import json
import time
import socket
import sys
from pathlib import Path
from urllib import request


COMMANDS = {
    "stop": "stop",
    "forward": "forward",
    "reverse": "reverse",
    "left": "left",
    "right": "right",
    "open-left-claw": "open left claw",
    "open-right-claw": "open right claw",
    "open-both-claws": "open both claws",
    "close-left-claw": "close left claw",
    "close-right-claw": "close right claw",
    "close-both-claws": "close both claws",
    "status": "status",
}

WIFI_HTTP_MODES = {"http", "wifi", "wifi-http", "lan", "lan-http"}
WIFI_UDP_MODES = {"udp", "wifi-udp", "lan-udp"}
LORA_MODES = {"lora", "serial"}


def load_config() -> dict:
    path = Path(__file__).with_name("transmitter_config.json")
    return json.loads(path.read_text(encoding="utf-8"))


def command_packet(config: dict, command_text: str) -> dict:
    return {
        "source": config["transmitter_name"],
        "controller": config["controller"],
        "voice_board": config["voice_board"],
        "text": command_text,
    }


def send_udp(config: dict, command_text: str) -> None:
    packet = command_packet(config, command_text)
    data = json.dumps(packet).encode("utf-8")
    port = int(config.get("robot_udp_port", config.get("udp_port", 9090)))
    with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock:
        sock.sendto(data, (config["robot_host"], port))


def send_http(config: dict, command_text: str) -> None:
    port = int(config.get("robot_http_port", config.get("robot_port", 8080)))
    url = f"http://{config['robot_host']}:{port}/command"
    data = json.dumps({"text": command_text}).encode("utf-8")
    req = request.Request(
        url,
        data=data,
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    with request.urlopen(req, timeout=5) as response:
        response.read()


def send_lora(config: dict, command_text: str) -> None:
    try:
        import serial  # type: ignore
    except ImportError:
        print("pyserial is required for LoRa mode")
        raise

    packet = command_packet(config, command_text)
    data = json.dumps(packet).encode("utf-8") + b"\n"
    with serial.Serial(config["lora_device"], int(config.get("lora_baud", 115200)), timeout=1, write_timeout=1) as link:
        link.write(data)
        link.flush()
        time.sleep(0.02)


def send_command(config: dict, command_text: str) -> str:
    mode = config.get("default_send_mode", "udp").lower()
    if mode in WIFI_HTTP_MODES:
        send_http(config, command_text)
        return "wifi-http"
    if mode in WIFI_UDP_MODES:
        send_udp(config, command_text)
        return "wifi-udp"
    if mode in LORA_MODES:
        send_lora(config, command_text)
        return "lora"
    elif mode == "auto":
        try:
            send_lora(config, command_text)
            return "lora"
        except Exception as exc:
            print(f"LoRa send failed: {exc}")

        try:
            send_http(config, command_text)
            return "wifi-http"
        except Exception as exc:
            print(f"HTTP fallback failed: {exc}")
            raise

    send_udp(config, command_text)
    return "wifi-udp"


def main(argv: list[str]) -> int:
    if len(argv) != 2 or argv[1] not in COMMANDS:
        print("Usage: remote_agent.py <command>")
        print("Commands:")
        for name in sorted(COMMANDS):
            print(f"  {name}")
        return 2
    config = load_config()
    transport = send_command(config, COMMANDS[argv[1]])
    print(f"sent via {transport}: {COMMANDS[argv[1]]}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))
