#!/usr/bin/env python3
import argparse
import json
import threading
from pathlib import Path

from ros_sugar.launch.executable import setup_component, run_component
from ros_sugar.ui_node import UINode, UINodeConfig
from ros_sugar.ui_node.api import build_api_app
from ros_sugar.utils import logger

import uvicorn


def main():
    """
    Run the UI node: a ROS node plus the JSON/WebSocket API server.

    Optionally run the FastHTML browser UI if dependencies installed.
    """
    logger.info("Starting UI Node executable")

    # Start UI helper ROS node in a separate thread
    ros_node: UINode = setup_component(
        list_of_components=[UINode], list_of_configs=[UINodeConfig]
    )  # type: ignore

    ros_node_config = ros_node.config

    # Get parsed UI elements
    parser = argparse.ArgumentParser()
    parser.add_argument("--ui_input_elements", type=str)
    parser.add_argument("--ui_output_elements", type=str)
    parser.add_argument("--ui_service_clients", type=str)
    parser.add_argument("--system_info", type=str)
    args, _ = parser.parse_known_args()  # type: ignore
    additional_input_elements = (
        json.loads(args.ui_input_elements) if args.ui_input_elements else None
    )
    additional_output_elements = (
        json.loads(args.ui_output_elements) if args.ui_output_elements else None
    )
    if args.ui_service_clients:
        ros_node._client_inputs_json = args.ui_service_clients

    system_info = json.loads(args.system_info) if args.system_info else None

    # Spin the ROS node in a background thread
    ros_thread = threading.Thread(
        target=run_component,
        args=[ros_node],
        daemon=True,
    )
    ros_thread.start()

    # Build the optional FastHTML browser app. Mounts under "/"
    if not ros_node_config.serve_browser:
        logger.info("Browser UI disabled. Serving the JSON/WebSocket API only.")
        browser_app = None
    else:
        from ros_sugar.ui_node.browser import build_browser_app

        browser_app = build_browser_app(
            ros_node,
            additional_input_elements=additional_input_elements,
            additional_output_elements=additional_output_elements,
            system_info=system_info,
        )

    # Create the JSON/WebSocket API is the server host, server host
    api_app = build_api_app(ros_node, browser_app=browser_app)

    # Check if SSL certificates exist
    if not (
        Path(ros_node_config.ssl_keyfile).exists()
        and Path(ros_node_config.ssl_certificate).exists()
    ):
        logger.warning("\n" + "=" * 80)
        logger.warning("WARNING: SSL certificates (key.pem, cert.pem) not found.")
        logger.warning(
            "Microphone access will not work when accessing from another machine."
        )
        logger.warning(
            "To enable microphone over the network, generate certificates by running"
        )
        logger.warning("the following command:")
        logger.warning(
            '\nopenssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365 -nodes -subj "/CN=localhost"\n'
        )
        logger.warning(
            "And give the path to the certificates to the launcher.enable_ui method"
        )
        logger.warning("=" * 80 + "\n")
        key_file = None
        certificate_file = None
        protocol = "http"
    else:
        key_file = ros_node_config.ssl_keyfile
        certificate_file = ros_node_config.ssl_certificate
        protocol = "https"

    logger.info(
        f"Access the recipe UI at: {protocol}://<IP_ADDRESS_OF_THE_ROBOT>:{ros_node_config.port}"
    )
    uvicorn.run(
        api_app,
        host="0.0.0.0",
        port=ros_node_config.port,
        ssl_keyfile=key_file,
        ssl_certfile=certificate_file,
        loop="asyncio",
    )


if __name__ == "__main__":
    main()
