use std::fs;
use std::path::Path;

use crate::app::helpers::inspect::build_runtime_compact_event_dispatch_cluster_report;
use crate::app::reports::inspect::{
    RuntimeCompactEventDispatchClusterCountsOutput, RuntimeCompactEventDispatchClusterCountsReport,
    RuntimeCompactEventDispatchClusterOutput, RuntimeMapTitleHintDirectoryOutput,
    RuntimeMapTitleHintDirectoryReport, RuntimeMapTitleHintMapEntry,
};
use rrt_runtime::inspect::smp::map_title::inspect_map_title_hint_file;

pub(crate) fn inspect_map_title_hints(root_path: &Path) -> Result<(), Box<dyn std::error::Error>> {
    let mut maps = Vec::new();
    let mut maps_scanned = 0usize;
    let mut maps_with_probe = 0usize;
    let mut maps_with_grounded_title_hits = 0usize;
    let mut maps_with_adjacent_title_pairs = 0usize;
    let mut maps_with_same_stem_adjacent_pairs = 0usize;

    let mut paths = fs::read_dir(root_path)?
        .filter_map(|entry| entry.ok().map(|entry| entry.path()))
        .filter(|path| {
            path.extension()
                .and_then(|extension| extension.to_str())
                .is_some_and(|extension| extension.eq_ignore_ascii_case("gmp"))
        })
        .collect::<Vec<_>>();
    paths.sort();

    for path in paths {
        maps_scanned += 1;
        if let Some(probe) = inspect_map_title_hint_file(&path)? {
            maps_with_probe += 1;
            if !probe.grounded_title_hits.is_empty() {
                maps_with_grounded_title_hits += 1;
            }
            if !probe.adjacent_reference_title_pairs.is_empty() {
                maps_with_adjacent_title_pairs += 1;
            }
            if probe.strongest_same_stem_pair.is_some() {
                maps_with_same_stem_adjacent_pairs += 1;
            }
            maps.push(RuntimeMapTitleHintMapEntry {
                path: path.display().to_string(),
                probe,
            });
        }
    }

    let output = RuntimeMapTitleHintDirectoryOutput {
        root_path: root_path.display().to_string(),
        report: RuntimeMapTitleHintDirectoryReport {
            maps_scanned,
            maps_with_probe,
            maps_with_grounded_title_hits,
            maps_with_adjacent_title_pairs,
            maps_with_same_stem_adjacent_pairs,
            maps,
        },
    };
    println!("{}", serde_json::to_string_pretty(&output)?);
    Ok(())
}

pub(crate) fn inspect_compact_event_dispatch_cluster(
    root_path: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
    let report = build_runtime_compact_event_dispatch_cluster_report(root_path)?;
    let output = RuntimeCompactEventDispatchClusterOutput {
        root_path: root_path.display().to_string(),
        report,
    };
    println!("{}", serde_json::to_string_pretty(&output)?);
    Ok(())
}

pub(crate) fn inspect_compact_event_dispatch_cluster_counts(
    root_path: &Path,
) -> Result<(), Box<dyn std::error::Error>> {
    let report = build_runtime_compact_event_dispatch_cluster_report(root_path)?;
    let output = RuntimeCompactEventDispatchClusterCountsOutput {
        root_path: root_path.display().to_string(),
        report: RuntimeCompactEventDispatchClusterCountsReport {
            maps_scanned: report.maps_scanned,
            maps_with_event_runtime_collection: report.maps_with_event_runtime_collection,
            maps_with_dispatch_strip_records: report.maps_with_dispatch_strip_records,
            dispatch_strip_record_count: report.dispatch_strip_record_count,
            dispatch_strip_records_with_trigger_kind: report
                .dispatch_strip_records_with_trigger_kind,
            dispatch_strip_records_missing_trigger_kind: report
                .dispatch_strip_records_missing_trigger_kind,
            dispatch_strip_payload_families: report.dispatch_strip_payload_families,
            dispatch_descriptor_occurrence_counts: report.dispatch_descriptor_occurrence_counts,
            dispatch_descriptor_map_counts: report.dispatch_descriptor_map_counts,
            unknown_descriptor_ids: report.unknown_descriptor_ids,
            unknown_descriptor_special_condition_label_matches: report
                .unknown_descriptor_special_condition_label_matches,
            add_building_dispatch_record_count: report.add_building_dispatch_record_count,
            add_building_dispatch_records_with_trigger_kind: report
                .add_building_dispatch_records_with_trigger_kind,
            add_building_dispatch_records_missing_trigger_kind: report
                .add_building_dispatch_records_missing_trigger_kind,
            add_building_descriptor_occurrence_counts: report
                .add_building_descriptor_occurrence_counts,
            add_building_descriptor_map_counts: report.add_building_descriptor_map_counts,
            add_building_row_shape_occurrence_counts: report
                .add_building_row_shape_occurrence_counts,
            add_building_row_shape_map_counts: report.add_building_row_shape_map_counts,
            add_building_signature_family_occurrence_counts: report
                .add_building_signature_family_occurrence_counts,
            add_building_signature_family_map_counts: report
                .add_building_signature_family_map_counts,
            add_building_condition_tuple_occurrence_counts: report
                .add_building_condition_tuple_occurrence_counts,
            add_building_condition_tuple_map_counts: report.add_building_condition_tuple_map_counts,
            add_building_signature_condition_cluster_occurrence_counts: report
                .add_building_signature_condition_cluster_occurrence_counts,
            add_building_signature_condition_cluster_map_counts: report
                .add_building_signature_condition_cluster_map_counts,
            add_building_signature_condition_cluster_descriptor_keys: report
                .add_building_signature_condition_cluster_descriptor_keys,
            add_building_signature_condition_cluster_non_add_building_descriptor_keys: report
                .add_building_signature_condition_cluster_non_add_building_descriptor_keys,
        },
    };
    println!("{}", serde_json::to_string_pretty(&output)?);
    Ok(())
}
