// SPDX-License-Identifier: Apache-2.0
// SPDX-FileCopyrightText: 2026 ndaal Gesellschaft für Sicherheit in der Informationstechnik mbH & Co KG, Cologne
// SPDX-FileCopyrightText: Author: Pierre Gronau <Pierre.Gronau@ndaal.eu>

//! SARIF Viewer — an offline, single-binary viewer, validator and
//! multi-format exporter for SARIF 2.1.0 and SARIF 2.2 (draft).
//!
//! The crate is built by reusing the ndaal CSAF-CRUD validation/import/export
//! pattern and the BSI-Grundschutz OSCAL viewer's web layer (matchit router,
//! security-header middleware) and multi-format export engine (Markdown + ODT
//! via `lo_writer`, PDF via an embedded-font renderer).
//!
//! Module map:
//!
//! * [`schema`] / [`validation`] — JSON-Schema gate enforced on every import
//!   and export.
//! * [`model`] / [`store`] — typed views over a SARIF log and the in-memory
//!   collection of loaded logs.
//! * [`import`] / [`export`] / [`export_pdf`] / [`sidecar`] — the import and
//!   multi-format export pipelines.
//! * [`router`] / [`static_files`] / [`html`] / [`routes`] / [`app_state`] /
//!   [`server`] — the localhost web viewer.

#![forbid(unsafe_code)]

pub mod app_state;
pub mod export;
pub mod export_pdf;
pub mod html;
pub mod import;
pub mod model;
pub mod path_security;
pub mod router;
pub mod routes;
pub mod schema;
pub mod server;
pub mod sidecar;
pub mod static_files;
pub mod store;
pub mod tls;
pub mod validation;

use store::SarifStore;

/// The embedded sample logs (name, bytes), shown out of the box. Both are
/// schema-valid SARIF 2.1.0; the non-conformant `*-report.sarif` files under
/// `data/samples/` are kept on disk to demonstrate import rejection.
const SAMPLES: &[(&str, &str)] = &[
    ("minimal.sarif", include_str!("../data/samples/minimal.sarif")),
    (
        "nvulnlookup-clean.sarif",
        include_str!("../data/samples/nvulnlookup-clean.sarif"),
    ),
];

/// Load the embedded sample logs into `store` (best-effort).
///
/// Each sample is validated like any other import; a sample that fails
/// validation is logged and skipped rather than aborting start-up. Returns the
/// number of samples admitted.
pub fn load_samples(store: &SarifStore) -> usize {
    let mut loaded: usize = 0;
    for (name, body) in SAMPLES {
        match import::load_bytes(name, body.as_bytes(), store) {
            Ok(log) => {
                store.insert(log);
                loaded = loaded.saturating_add(1);
            }
            Err(error) => {
                tracing::warn!(sample = name, %error, "embedded sample skipped (did not validate)");
            }
        }
    }
    loaded
}
