use bpaf::{Parser, construct, long};
use std::path::PathBuf;
use crate::cli::{Command, input_arg};
#[derive(Debug, Clone)]
pub struct ExportArgs {
pub input: PathBuf,
pub outputs: Vec<PathBuf>,
pub format: Option<String>,
pub compress_payload: bool,
pub proto: Option<String>,
pub src_ip: Vec<String>,
pub dst_ip: Vec<String>,
pub ip: Vec<String>,
pub src_port: Vec<String>,
pub dst_port: Vec<String>,
pub port: Vec<String>,
pub flow_id: Option<String>,
pub from: Option<String>,
pub to: Option<String>,
pub tcp_flags: Option<String>,
pub min_len: Option<u32>,
pub max_len: Option<u32>,
pub unidirectional: bool,
pub negate: bool,
pub filter_expr: Option<String>,
pub min_flow_packets: Option<u64>,
}
pub fn export_cmd() -> impl Parser<Command> {
let input = input_arg();
let outputs = long("output")
.short('o')
.help("Output file path (.jsonl, .parquet, or .avro). Repeatable for fan-out to multiple formats.")
.argument::<PathBuf>("PATH")
.many();
let format = long("format")
.short('F')
.help("Override output format: json, parquet, or avro. When multiple --output paths are given, this flag applies only to the first; the rest infer their format from the file extension.")
.argument::<String>("FMT")
.optional();
let compress_payload = long("compress-payload")
.help("Compress payload bytes with Zstd")
.switch();
let proto = long("proto")
.help("Comma-separated protocols to keep: tcp,udp,icmp,icmp6 or numbers")
.argument::<String>("PROTOS")
.optional();
let src_ip = long("src-ip")
.help("Source IP or CIDR to keep (repeatable, OR-ed)")
.argument::<String>("CIDR")
.many();
let dst_ip = long("dst-ip")
.help("Destination IP or CIDR to keep (repeatable, OR-ed)")
.argument::<String>("CIDR")
.many();
let ip = long("ip")
.help("Either-endpoint IP or CIDR (repeatable, OR-ed)")
.argument::<String>("CIDR")
.many();
let src_port = long("src-port")
.help("Source port or range to keep (repeatable)")
.argument::<String>("PORT")
.many();
let dst_port = long("dst-port")
.help("Destination port or range to keep (repeatable)")
.argument::<String>("PORT")
.many();
let port = long("port")
.help("Either-endpoint port or range (repeatable)")
.argument::<String>("PORT")
.many();
let flow_id = long("flow-id")
.help("Comma-separated hex flow IDs to retain")
.argument::<String>("IDS")
.optional();
let from = long("from")
.help("Keep packets at or after this datetime (RFC 3339 or Unix epoch seconds)")
.argument::<String>("DATETIME")
.optional();
let to = long("to")
.help("Keep packets at or before this datetime (RFC 3339 or Unix epoch seconds)")
.argument::<String>("DATETIME")
.optional();
let tcp_flags = long("tcp-flags")
.help("TCP flags filter, e.g. SYN, SYN+ACK, RST:exact")
.argument::<String>("FLAGS")
.optional();
let min_len = long("min-len")
.help("Minimum captured packet length in bytes")
.argument::<u32>("BYTES")
.optional();
let max_len = long("max-len")
.help("Maximum captured packet length in bytes")
.argument::<u32>("BYTES")
.optional();
let unidirectional = long("unidirectional")
.short('u')
.help("Compute flow IDs unidirectionally (default: bidirectional)")
.switch();
let negate = long("not")
.help("Invert the filter: keep packets that do NOT match")
.switch();
let filter_expr = long("filter")
.short('f')
.help("tcpdump/libpcap BPF expression, e.g. \"tcp and dst port 443\"")
.argument::<String>("EXPR")
.optional();
let min_flow_packets = long("min-flow-packets")
.help("Only include flows with at least N packets (pre-scan pass; non-IP packets excluded)")
.argument::<u64>("N")
.optional();
construct!(ExportArgs {
compress_payload,
format,
outputs,
proto,
src_ip,
dst_ip,
ip,
src_port,
dst_port,
port,
flow_id,
from,
to,
tcp_flags,
min_len,
max_len,
unidirectional,
negate,
filter_expr,
min_flow_packets,
input,
})
.to_options()
.descr("Export PCAP packets to JSON, Parquet, or Avro with optional filtering")
.command("export")
.map(|a| Command::Export(Box::new(a)))
}