///|
pub(all) struct CliResponse {
  exit_code : Int
  stdout : String
  stderr : String
}

///|
pub fn version() -> String {
  "0.1.0"
}

///|
pub fn dispatch(args : ArrayView[String]) -> CliResponse {
  // --help / -h
  if args.length() == 0 ||
    (args.length() == 1 && (args[0] == "--help" || args[0] == "-h")) {
    return { exit_code: 0, stdout: root_command().render_help(), stderr: "" }
  }
  // --version / -V
  if args.length() == 1 && (args[0] == "--version" || args[0] == "-V") {
    return { exit_code: 0, stdout: version(), stderr: "" }
  }
  // 解析 subcommand
  let matches = root_command().parse(argv=args, env={}) catch {
    err => return { exit_code: 2, stdout: "", stderr: "\{err}" }
  }
  match matches.subcommand {
    Some((name, sub_matches)) =>
      match name {
        "invoice" => dispatch_invoice(sub_matches)
        _ => { exit_code: 2, stdout: "", stderr: "unknown subcommand: \{name}" }
      }
    None => { exit_code: 0, stdout: root_command().render_help(), stderr: "" }
  }
}

///|
fn root_command() -> @argparse.Command {
  @argparse.Command(
    "ofdx",
    about="OFD 版式文档执行工具",
    version=version(),
    subcommands=[invoice_command()],
  )
}

///|
fn invoice_command() -> @argparse.Command {
  @argparse.Command(
    "invoice",
    about="解析 OFD 增值税电子发票,输出结构化 JSON",
    positionals=[
      @argparse.PositionArg(
        "file",
        about="OFD 文件路径(.ofd)",
        num_args=@argparse.ValueRange(lower=1, upper=1),
      ),
    ],
  )
}

///|
fn dispatch_invoice(matches : @argparse.Matches) -> CliResponse {
  let values : Map[String, Array[String]] = matches.values
  guard values is { "file": [file, ..], .. } else {
    return { exit_code: 1, stdout: "", stderr: "missing file argument" }
  }
  let data = @fs.read_file_to_bytes(file) catch {
    _ =>
      return { exit_code: 1, stdout: "", stderr: "无法读取文件: " + file }
  }
  let port = @adaptor.MooncakeOfdPort::from_bytes(data) catch {
    e =>
      return {
        exit_code: 1,
        stdout: "",
        stderr: "OFD 解包失败: " + e.to_string(),
      }
  }
  let reader = match @reader.OfdReader::open(port) {
    Ok(r) => r
    Err(e) =>
      return {
        exit_code: 1,
        stdout: "",
        stderr: "OFD 解析失败: " + e.to_string(),
      }
  }
  match @invoice.extract_invoice(reader) {
    Ok(inv) =>
      { exit_code: 0, stdout: @invoice.invoice_to_json(inv), stderr: "" }
    Err(e) =>
      {
        exit_code: 1,
        stdout: "",
        stderr: "发票提取失败: " + e.to_string(),
      }
  }
}