#![expect(clippy::unwrap_used, reason = "examples can panic")]
#![expect(clippy::print_stdout, reason = "examples can log to stdout")]
#![expect(clippy::print_stderr, reason = "examples can log to stderr")]

use std::str::FromStr as _;

use chrono::{DateTime, Utc};
use ocpi_tariffs::{cdr, generate, guess, tariff, warning, Version};
use rust_decimal::Decimal;

fn main() {
    const TARIFF_JSON: &str = include_str!("data/tariff_time_and_parking_time_separate.json");

    let report = tariff::parse_and_report(TARIFF_JSON).unwrap();
    let guess::Report {
        unexpected_fields,
        version,
    } = report;

    if !unexpected_fields.is_empty() {
        eprintln!("Strange... there are fields in the tariff that are not defined in the spec.");

        for path in &unexpected_fields {
            eprintln!("  * {path}");
        }

        eprintln!();
    }

    let tariff = version.certain_or(Version::V221);

    let config = generate::Config {
        timezone: chrono_tz::Europe::Amsterdam,
        start_date_time: DateTime::<Utc>::from_str("2025-06-12 18:22:33+00:00").unwrap(),
        end_date_time: DateTime::<Utc>::from_str("2025-06-12 22:33:44+00:00").unwrap(),
        max_current_supply_amp: Decimal::from(4),
        requested_kwh: Decimal::from(24),
        max_power_supply_kw: Decimal::from(80),
    };
    let report = match cdr::generate_from_tariff(&tariff, &config) {
        Ok(r) => r,
        Err(set) => {
            let (error, warnings) = set.into_parts();
            print_error(&error);
            print_warnings(&warnings);
            return;
        }
    };
    let (report, warnings) = report.into_parts();

    print_warnings(&warnings);

    let generate::Report {
        tariff_id,
        tariff_currency_code,
        partial_cdr,
    } = report;

    println!("CDR generated for tariff with id: `{tariff_id}` and currency code: `{tariff_currency_code}`");
    println!("{partial_cdr:#?}");
}

/// Print `generate::Warning` that halted the example to `stderr`.
fn print_error(error: &warning::Error<generate::Warning>) {
    eprintln!(
        "ERR: Unable to generate CDR due to error at path `{}`: {}",
        error.element().path(),
        error.warning()
    );
}

/// Print `generate::Warning`s to `stderr`.
fn print_warnings(warnings: &warning::Set<generate::Warning>) {
    if warnings.is_empty() {
        return;
    }

    eprintln!(
        "WARN: {} warnings from the linting:\n {}",
        warnings.len_warnings(),
        warning::SetWriter::new(warnings)
    );
}
