#!/usr/bin/env python3
"""Create synthetic teaching data offline. No sending, sniffing or DNS queries."""
import argparse
import json
from pathlib import Path

import scapy
from scapy.all import ARP, Ether, IP, Raw, TCP, UDP, raw, wrpcap


def examples():
    a, b = "02:00:00:00:00:01", "02:00:00:00:00:02"
    packets = [
        Ether(src=a, dst=b) / IP(src="192.0.2.10", dst="192.0.2.20", ttl=64)
        / UDP(sport=40000, dport=9000) / Raw(b"LAB"),
        Ether(src=a, dst=b) / IP(src="192.0.2.10", dst="192.0.2.20")
        / TCP(sport=41000, dport=8000, flags="S", seq=100),
        Ether(src=b, dst=a) / IP(src="192.0.2.20", dst="192.0.2.10")
        / TCP(sport=8000, dport=41000, flags="SA", seq=500, ack=101),
        Ether(src=a, dst=b) / IP(src="192.0.2.10", dst="192.0.2.20")
        / TCP(sport=41000, dport=8000, flags="A", seq=101, ack=501),
        Ether(src=a, dst="ff:ff:ff:ff:ff:ff")
        / ARP(op=1, hwsrc=a, psrc="192.0.2.10", hwdst="00:00:00:00:00:00", pdst="192.0.2.20"),
        Ether(src=b, dst=a)
        / ARP(op=2, hwsrc=b, psrc="192.0.2.20", hwdst=a, pdst="192.0.2.10"),
    ]
    assembled = []
    for index, packet in enumerate(packets):
        parsed = Ether(raw(packet))
        # Fixed timestamps make the generated fixture reproducible.
        parsed.time = 1700000000 + index
        assembled.append(parsed)
    return assembled


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--output", required=True, type=Path, help="New output directory; existing paths are not overwritten")
    args = parser.parse_args()
    packets = examples()
    try:
        args.output.mkdir(parents=True, exist_ok=False)
    except FileExistsError:
        parser.error("Output already exists. Choose a new directory.")
    wrpcap(str(args.output / "tutorial.pcap"), packets)
    description = {
        "kind": "synthetic offline fixture, not a real capture or a student report",
        "scapy_version": scapy.__version__,
        "packets": [{"index": i + 1, "summary": p.summary(), "bytes": len(raw(p)), "hex": raw(p).hex()} for i, p in enumerate(packets)],
    }
    (args.output / "input-description.json").write_text(json.dumps(description, indent=2) + "\n", encoding="utf-8")
    print(f"Created {len(packets)} synthetic frames in {args.output}. No network traffic was sent.")


if __name__ == "__main__":
    main()
