"""bp-tunnel CLI."""

import argparse
import os
import sys

from .file_transport import FileTransport, DEFAULT_BASE_DIR
from .tunnel import Tunnel


def _rand_id() -> str:
    return os.urandom(4).hex()


def cmd_create(args):
    tid = _rand_id()
    t = FileTransport(args.base_dir)
    t.create(tid, args.as_)
    print(tid)


def cmd_join(args):
    t = FileTransport(args.base_dir)
    t.join(args.tunnel, args.as_)
    m = t.members(args.tunnel)
    print(f"joined {args.tunnel} ({len(m)} members)")


def cmd_send(args):
    t = FileTransport(args.base_dir)
    tun = Tunnel(args.tunnel, args.as_, t)
    tun.send(args.message, to=args.to)
    print("ok")


def cmd_recv(args):
    t = FileTransport(args.base_dir)
    tun = Tunnel(args.tunnel, args.as_, t)
    msg = tun.receive(from_=args.from_)
    if msg:
        print(f"{msg.from_}: {msg.payload}")
    else:
        print("[empty]")


def cmd_listen(args):
    t = FileTransport(args.base_dir)
    tun = Tunnel(args.tunnel, args.as_, t)
    label = f"listening on {args.tunnel} as {args.as_}"
    if args.from_:
        label += f" (from {args.from_})"
    print(label)
    try:
        for msg in tun.listen(from_=args.from_):
            print(f"{msg.from_}: {msg.payload}")
    except KeyboardInterrupt:
        print()


def cmd_promote(args):
    t = FileTransport(args.base_dir)
    tun = Tunnel(args.tunnel, args.as_, t)
    tun.promote(args.agent)
    print(f"{args.agent} is now admin")


def cmd_demote(args):
    t = FileTransport(args.base_dir)
    tun = Tunnel(args.tunnel, args.as_, t)
    tun.demote(args.agent)
    print(f"{args.agent} is no longer admin")


def cmd_leave(args):
    t = FileTransport(args.base_dir)
    tun = Tunnel(args.tunnel, args.as_, t)
    tun.leave()
    print(f"left {args.tunnel}")


def cmd_info(args):
    t = FileTransport(args.base_dir)
    members = t.members(args.tunnel)
    admins = t.admins(args.tunnel)
    print(f"tunnel: {args.tunnel}")
    print(f"members ({len(members)}):")
    for m in members:
        suffix = " [admin]" if m in admins else ""
        print(f"  {m}{suffix}")


def cmd_ls(args):
    t = FileTransport(args.base_dir)
    for tid in t.tunnels():
        m = t.members(tid)
        print(f"{tid}  ({len(m)} members)")


def main():
    p = argparse.ArgumentParser(prog="bp-tunnel", description="Inter-agent tunnel messaging")
    p.add_argument("--base-dir", default=DEFAULT_BASE_DIR)
    p.add_argument("--version", action="version", version=f"%(prog)s {_get_version()}")
    sub = p.add_subparsers(dest="cmd", required=True)

    # create --as name
    s = sub.add_parser("create", help="Create a new tunnel")
    s.add_argument("--as", dest="as_", required=True)

    # join <tunnel> --as name
    s = sub.add_parser("join", help="Join an existing tunnel")
    s.add_argument("tunnel")
    s.add_argument("--as", dest="as_", required=True)

    # send <tunnel> <message> --as name [--to name]
    s = sub.add_parser("send", help="Send a message")
    s.add_argument("tunnel")
    s.add_argument("message")
    s.add_argument("--as", dest="as_", required=True)
    s.add_argument("--to", default=None, help="direct message to agent")

    # recv <tunnel> --as name [--from name]
    s = sub.add_parser("recv", help="Receive one message")
    s.add_argument("tunnel")
    s.add_argument("--as", dest="as_", required=True)
    s.add_argument("--from", dest="from_", default=None, help="filter by sender")

    # listen <tunnel> --as name [--from name]
    s = sub.add_parser("listen", help="Listen for messages (blocking)")
    s.add_argument("tunnel")
    s.add_argument("--as", dest="as_", required=True)
    s.add_argument("--from", dest="from_", default=None, help="filter by sender")

    # promote <tunnel> <agent> --as name
    s = sub.add_parser("promote", help="Promote agent to admin")
    s.add_argument("tunnel")
    s.add_argument("agent")
    s.add_argument("--as", dest="as_", required=True)

    # demote <tunnel> <agent> --as name
    s = sub.add_parser("demote", help="Remove admin from agent")
    s.add_argument("tunnel")
    s.add_argument("agent")
    s.add_argument("--as", dest="as_", required=True)

    # leave <tunnel> --as name
    s = sub.add_parser("leave", help="Leave a tunnel")
    s.add_argument("tunnel")
    s.add_argument("--as", dest="as_", required=True)

    # info <tunnel>
    s = sub.add_parser("info", help="Show tunnel info")
    s.add_argument("tunnel")

    # ls
    sub.add_parser("ls", help="List all tunnels")

    args = p.parse_args()
    try:
        {
            "create": cmd_create, "join": cmd_join,
            "send": cmd_send, "recv": cmd_recv, "listen": cmd_listen,
            "promote": cmd_promote, "demote": cmd_demote, "leave": cmd_leave,
            "info": cmd_info, "ls": cmd_ls,
        }[args.cmd](args)
    except (ValueError, PermissionError) as e:
        print(f"error: {e}", file=sys.stderr)
        sys.exit(1)
    except KeyboardInterrupt:
        print()


def _get_version() -> str:
    from . import __version__
    return __version__


if __name__ == "__main__":
    main()
