#!/usr/bin/env python3
# SPDX-License-Identifier: BSD-3-Clause OR Apache-2.0
# encoding: utf-8

"""Script to send a bundle and receive a specified number of bundles."""

import argparse
import logging
import io
import sys

import cbor2

from pyd3tn.bundle7 import Bundle
from ud3tn_utils.aap import (
    AAPClient,
    AAPTCPClient,
    AAPUnixClient,
    AAPMessageType,
)
from ud3tn_utils.aap.bin.helpers import (
    add_common_parser_arguments,
    initialize_logger,
)


logger = logging.getLogger(__name__)


def _send_and_recv(aap_client: AAPClient, dest_eid: str, payload: bytes,
                   count: int, output: io.BufferedIOBase,
                   logger: logging.Logger):
    logger.info("Sending payload of length %d to %s", len(payload), dest_eid)
    aap_client.send_bundle(dest_eid, payload, False)
    for i in range(count):
        logger.info("Waiting for reception of bundle #%d of %d", i + 1, count)
        while True:
            try:
                msg = aap_client.receive()
            except KeyboardInterrupt:
                logger.info("Terminated by keyboard interrupt.")
                sys.exit(130)  # exit status for SIGINT
            if not msg:
                logger.warning("µD3TN has closed the connection.")
                sys.exit(1)
            enc = False
            if msg.msg_type == AAPMessageType.RECVBUNDLE:
                payload = msg.payload
            elif msg.msg_type == AAPMessageType.RECVBIBE:
                payload = cbor2.loads(msg.payload)
                bundle = Bundle.parse(payload[2])
                payload = bundle.payload_block.data
                enc = True
            else:
                continue
            enc_str = " encapsulated" if enc else ""
            logger.info(
                "Received%s bundle from '%s' with payload of len = %d",
                enc_str,
                msg.eid,
                len(payload),
            )
            output.write(payload)
            output.flush()
            break
    logger.info("Expected number of bundles received, terminating")


def _parse_args():
    parser = argparse.ArgumentParser(
        description="send a bundle via uD3TN and wait for responses",
    )
    add_common_parser_arguments(parser)
    parser.add_argument(
        "DESTINATION",
        help="the destination EID of the created bundle",
    )
    parser.add_argument(
        "PAYLOAD",
        type=argparse.FileType("rb"),
        default=sys.stdin.buffer,
        nargs="?",
        help="the payload of the created bundle, (default: read from STDIN)",
    )
    parser.add_argument(
        "-c", "--count",
        type=int,
        default=1,
        help="count of bundles expected to be received (default: 1)",
    )
    parser.add_argument(
        "-o", "--output",
        type=argparse.FileType("wb"),
        default=sys.stdout.buffer,
        help="file to write the received bundle contents",
    )
    return parser.parse_args()


def main():
    args = _parse_args()
    global logger
    logger = initialize_logger(args.verbosity)

    payload = args.PAYLOAD.read()
    args.PAYLOAD.close()

    try:
        if args.tcp:
            aap_client = AAPTCPClient(address=args.tcp)
        else:
            aap_client = AAPUnixClient(address=args.socket)
        aap_client.connect()
        try:
            aap_client.register(args.agentid)
            _send_and_recv(
                aap_client,
                args.DESTINATION,
                payload,
                args.count,
                args.output,
                logger,
            )
        finally:
            aap_client.disconnect()
    finally:
        args.output.close()


if __name__ == "__main__":
    main()
