from scapy.all import Ether, IPv6, send, Raw, sendp
import argparse
from datetime import datetime

TYPE_REPLAY_RECORD = 1
TYPE_REPLAY_CLEAR = 2
TYPE_REPLAY_RUN = 4
CREASE_PROT = 254
S_TO_NS = 1_000_000_000

def send_command(
        msg_type: int,
        iface: str,
        args: Raw
):
    if msg_type not in (TYPE_REPLAY_RECORD, TYPE_REPLAY_CLEAR, TYPE_REPLAY_RUN):
        raise ValueError(f"Invalid command type: {msg_type}")
    
    msg = Raw(bytes([msg_type]))/args
    pkts = []
    pkt = Ether(dst="ff:ff:ff:ff:ff:ff")/IPv6(dst="2001:abcd::3", src="2001:abcd::2", nh=CREASE_PROT)/msg
    pkts.append(pkt)

    for pkt in pkts:
        sendp(pkt, verbose=False, iface=iface)
    print(f"Commands sent")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Send commands to Crease nodes")
    parser.add_argument("msg_type", type=int, choices=[TYPE_REPLAY_RECORD, TYPE_REPLAY_CLEAR, TYPE_REPLAY_RUN],
                        help="Type of command to send")
    parser.add_argument("-i", action="append", help="Interface to send out of")
    parser.add_argument("-a", action="append", help="Additional arguments to include in the command")

    args = parser.parse_args()
    msg_args = None
    curr_time = datetime.now().timestamp()

    if args.msg_type == TYPE_REPLAY_RECORD:
        if len(args.a) < 2:
            raise ValueError("For TYPE_REPLAY_RECORD, two arguments are required: <start offset> <end offset>")
        start_offset = float(args.a[0])
        end_offset = float(args.a[1])
        msg_args = Raw(int((curr_time + start_offset) * S_TO_NS).to_bytes(8, 'big'))/Raw(int((curr_time + end_offset) * S_TO_NS).to_bytes(8, 'big'))
    elif args.msg_type == TYPE_REPLAY_CLEAR:
        msg_args = Raw(b'\x00')
    elif args.msg_type == TYPE_REPLAY_RUN:
        if len(args.a) < 1:
            raise ValueError("For TYPE_REPLAY_RUN, one argument is required: <start offset>")
        start_offset = int(args.a[0])
        msg_args = Raw(int((curr_time + start_offset) * S_TO_NS).to_bytes(8, 'big'))

    print(f"Sending command type {args.msg_type} to receivers: {args.i}")
    send_command(args.msg_type, args.i[0], msg_args)