from __future__ import annotations

import argparse
import asyncio
import signal
from contextlib import suppress

from .server import (
    DEFAULT_BIND_ENDPOINT,
    DEFAULT_DEVICE_NAME,
    DEFAULT_ENDPOINT,
    DEFAULT_NAMESPACE_URI,
    DEFAULT_PH_NODE,
    DEFAULT_TEMP_NODE,
    DEFAULT_TIMESTAMP_NODE,
    run_server,
)

try:
    from cf_cli.registry import register_command
except Exception:  # pragma: no cover - optional dependency
    register_command = None


def _add_common_args(parser: argparse.ArgumentParser) -> None:
    parser.add_argument("--interval", type=float, default=1.0, help="Loop interval in seconds.")
    parser.add_argument("--duration", type=float, default=0.0, help="Total runtime in seconds (0=run until stopped).")
    parser.add_argument("--endpoint", type=str, default=DEFAULT_ENDPOINT, help="Client endpoint hint.")
    parser.add_argument("--bind-endpoint", type=str, default=DEFAULT_BIND_ENDPOINT, help="Server bind endpoint.")
    parser.add_argument("--namespace", type=str, default=DEFAULT_NAMESPACE_URI, help="Namespace URI.")
    parser.add_argument("--device-name", type=str, default=DEFAULT_DEVICE_NAME, help="Device object name.")
    parser.add_argument("--ph-node", type=str, default=DEFAULT_PH_NODE, help="pH node id string.")
    parser.add_argument("--temp-node", type=str, default=DEFAULT_TEMP_NODE, help="Temperature node id string.")
    parser.add_argument("--timestamp-node", type=str, default=DEFAULT_TIMESTAMP_NODE, help="Timestamp node id string.")


def _run_from_args(args: argparse.Namespace) -> int:
    cmd = getattr(args, "cmd", None) or "start"
    if cmd != "start":
        return 2

    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    stop_event = asyncio.Event()

    def _request_stop() -> None:
        if not stop_event.is_set():
            print("\nStopping OPC UA server...")
            stop_event.set()

    for sig in (signal.SIGINT, signal.SIGTERM):
        with suppress(ValueError, NotImplementedError):
            loop.add_signal_handler(sig, _request_stop)

    async def _main() -> None:
        await run_server(
            loop_interval=args.interval,
            endpoint=args.endpoint,
            bind_endpoint=args.bind_endpoint,
            namespace_uri=args.namespace,
            device_name=args.device_name,
            ph_node=args.ph_node,
            temp_node=args.temp_node,
            timestamp_node=args.timestamp_node,
            duration=args.duration if args.duration and args.duration > 0 else None,
            stop_event=stop_event,
        )

    try:
        loop.run_until_complete(_main())
    finally:
        loop.close()
    return 0


def _register_cf_cli() -> None:
    if register_command is None:
        return

    def _add_parser(subparsers: argparse._SubParsersAction) -> argparse.ArgumentParser:
        parser = subparsers.add_parser("server", help="Virtual OPC-UA server")
        _add_common_args(parser)
        server_subparsers = parser.add_subparsers(dest="cmd", required=False)
        start_cmd = server_subparsers.add_parser("start", help="Start the virtual OPC-UA server.")
        _add_common_args(start_cmd)
        parser.set_defaults(_cf_handler=_run_from_args)
        return parser

    register_command(
        "opcua",
        "server",
        _add_parser,
        group_help="OPC-UA tools",
        command_help="Run the virtual OPC-UA server",
    )


def main() -> None:
    parser = argparse.ArgumentParser(description="Cogniflow virtual OPC-UA server")
    subparsers = parser.add_subparsers(dest="cmd", required=False)

    start_cmd = subparsers.add_parser("start", help="Start the virtual OPC-UA server.")
    _add_common_args(start_cmd)

    args = parser.parse_args()
    cmd = args.cmd or "start"

    if cmd != "start":
        parser.print_help()
        return

    _run_from_args(args)


if __name__ == "__main__":
    raise SystemExit(main())

_register_cf_cli()
