//! `kobold-guard` CLI: triage a fixed-record COBOL data image against a JSON layout and emit a
//! findings report (JSON). Fail-closed: a non-zero exit means damage-severity findings were raised.
//!
//! Usage:
//!   kobold-guard scan <data-file> --layout <layout.json> [--pretty]
//!
//! The layout JSON matches [`kobold_guard::Layout`], e.g.:
//!   {"lrecl":8,"fields":[
//!      {"name":"id","offset":0,"len":5,"encoding":{"zoned-ascii":{"signed":false}}},
//!      {"name":"amt","offset":5,"len":3,"encoding":{"packed":{"digits":5,"signed":true}}}]}
#![forbid(unsafe_code)]

use kobold_guard::{triage, Layout};
use std::process::ExitCode;

fn main() -> ExitCode {
    let args: Vec<String> = std::env::args().collect();
    if args.len() < 2 || args[1] != "scan" {
        eprintln!("usage: kobold-guard scan <data-file> --layout <layout.json> [--pretty]");
        return ExitCode::from(2);
    }

    let mut data_path: Option<String> = None;
    let mut layout_path: Option<String> = None;
    let mut pretty = false;
    let mut i = 2;
    while i < args.len() {
        match args[i].as_str() {
            "--layout" => {
                i += 1;
                layout_path = args.get(i).cloned();
            }
            "--pretty" => pretty = true,
            other => data_path = Some(other.to_string()),
        }
        i += 1;
    }

    let (Some(dp), Some(lp)) = (data_path, layout_path) else {
        eprintln!("error: need both <data-file> and --layout <layout.json>");
        return ExitCode::from(2);
    };

    let data = match std::fs::read(&dp) {
        Ok(d) => d,
        Err(e) => {
            eprintln!("error: cannot read data file {dp}: {e}");
            return ExitCode::from(2);
        }
    };
    let layout_src = match std::fs::read_to_string(&lp) {
        Ok(s) => s,
        Err(e) => {
            eprintln!("error: cannot read layout {lp}: {e}");
            return ExitCode::from(2);
        }
    };
    let layout: Layout = match serde_json::from_str(&layout_src) {
        Ok(l) => l,
        Err(e) => {
            eprintln!("error: invalid layout JSON: {e}");
            return ExitCode::from(2);
        }
    };

    let report = triage(&data, &layout);
    let json = if pretty {
        serde_json::to_string_pretty(&report)
    } else {
        serde_json::to_string(&report)
    };
    match json {
        Ok(s) => println!("{s}"),
        Err(e) => {
            eprintln!("error: serialize report: {e}");
            return ExitCode::from(2);
        }
    }

    if report.clean {
        ExitCode::SUCCESS
    } else {
        ExitCode::FAILURE
    }
}
