use std::collections::BTreeSet;

use pdf_xfa::adobe_compat::{registry, AdobeCompatStatus};

#[test]
fn rule_ids_are_unique() {
    let mut ids = BTreeSet::new();
    for rule in registry() {
        assert!(
            ids.insert(rule.id.as_str()),
            "duplicate rule id {}",
            rule.id.as_str()
        );
    }
}

#[test]
fn active_rules_have_sources_and_counterexample_fields() {
    for rule in registry() {
        if rule.status == AdobeCompatStatus::Active {
            assert!(
                !rule.source_docs.is_empty() || rule.statement.contains("TODO"),
                "active rule {} must have source docs or explicit TODO",
                rule.id.as_str()
            );
            let _counterexamples_field_is_present = rule.counterexamples;
        }
    }
}

#[test]
fn registry_order_is_deterministic() {
    let ids: Vec<&str> = registry().iter().map(|rule| rule.id.as_str()).collect();
    assert_eq!(
        ids,
        vec![
            "suppress_empty_pages_only_when_real_data_bound",
            "ignore_invisible_server_metadata_bindings_for_data_bound_signal",
            "exclude_non_data_widgets_from_page_suppression",
            "cap_suppression_by_form_dom_page_area_count",
            "trim_static_xfaf_excess_pages_when_layout_is_single_page_and_form_dom_allows",
            "exclude_bind_none_fields_from_page_data_suppression",
            "repeating_subform_instance_count_clamped_to_occur_range",
            "bind_none_subform_does_not_auto_expand",
            "form_dom_driven_repeat_instance_replication",
        ]
    );
}

#[test]
fn stable_metadata_formatting_is_pinned() {
    let summaries = registry()
        .iter()
        .map(|rule| rule.stable_summary())
        .collect::<Vec<_>>()
        .join("\n");

    assert_eq!(
        summaries,
        "suppress_empty_pages_only_when_real_data_bound|pagination|suppress|active|Suppress data-empty pages only after visible DataDom binding proves real submitted data is present.|examples:13275420,d9ec06f8|counterexamples:778a1138,e0909cf9|sources:benchmarks/runs/M3B_PAGECOUNT_FIDELITY_WAVE_RESULT.md,benchmarks/runs/M3B_PAGECOUNT_MISMATCH_BUCKETS.md,benchmarks/runs/M5_PAGE_SUPPRESSION_RULES_DOSSIER.md|trace:suppress_gated_by_data_bound_signal\n\
ignore_invisible_server_metadata_bindings_for_data_bound_signal|binding|bind|active|Bindings on invisible, hidden, or inactive fields do not set the global data-bound signal.|examples:M3B_PAGECOUNT_FIDELITY_WAVE_RESULT|counterexamples:XDP_VISIBLE_BOUND_DROPS_EMPTY_PAGE|sources:benchmarks/runs/M3B_PAGECOUNT_FIDELITY_WAVE_RESULT.md,benchmarks/runs/M5_SUPPRESSION_METADATA_RULES_DOSSIER.md|trace:invisible_field_binding_ignored\n\
exclude_non_data_widgets_from_page_suppression|pagination|suppress|active|Signature, button, and barcode widgets are structural unless another rule proves they are data-empty repeaters.|examples:778a1138,e0909cf9|counterexamples:XDP_VISIBLE_BOUND_DROPS_EMPTY_PAGE|sources:benchmarks/runs/M3_XFA_NEXT_FIDELITY_TARGETS.md,benchmarks/runs/M3B_PAGECOUNT_WAVE6_RESULT.md,benchmarks/runs/M5_SUPPRESSION_METADATA_RULES_DOSSIER.md|trace:non_data_widget_excluded_from_data_check\n\
cap_suppression_by_form_dom_page_area_count|pagination|suppress|active|When a saved form DOM declares a page-area count, page suppression must not reduce output below that count.|examples:322faac4|counterexamples:7dbbe9d9|sources:benchmarks/runs/M3B_PAGECOUNT_WAVE5_RESULT.md,benchmarks/runs/M3B_PAGECOUNT_CURRENT_STATE_AFTER_WAVE5B.md,benchmarks/runs/UX1_TRACE_COMPAT_DOSSIER.md|trace:suppress_capped_by_form_dom\n\
trim_static_xfaf_excess_pages_when_layout_is_single_page_and_form_dom_allows|static_preservation|write|active|Static XFAF surplus host pages may be trimmed only when a saved form DOM corroborates trim intent (form-DOM page count <= layout, or single-page collapse with form DOM present); without a form DOM the host PDF page count is authoritative and no trim is performed.|examples:fe5de953|counterexamples:322faac4,b5bd3a97,7dbbe9d9,0b86389a|sources:benchmarks/runs/M3B_PAGECOUNT_WAVE5_RESULT.md,benchmarks/runs/M3B_FIDELITY_WAVE7_RESULT.md,benchmarks/runs/M5_PAGE_SUPPRESSION_RULES_DOSSIER.md,benchmarks/runs/PHASE2_WAVE9_RESULT.md,benchmarks/runs/PHASE2_WAVE10_RESULT.md|trace:static_xfaf_trim_allowed\n\
exclude_bind_none_fields_from_page_data_suppression|pagination|suppress|active|Fields with <bind match=\"none\"> are template-only and never carry dataset values; they are excluded from the per-page \"has data field\" signal used by page suppression.|examples:XDP_BIND_NONE_PAGE_IS_NOT_DROPPED|counterexamples:XDP_VISIBLE_BOUND_DROPS_EMPTY_PAGE|sources:benchmarks/runs/M3B_PAGECOUNT_WAVE6_RESULT.md,benchmarks/runs/M5_PAGE_SUPPRESSION_RULES_DOSSIER.md|trace:bind_none_field_excluded_from_data_check\n\
repeating_subform_instance_count_clamped_to_occur_range|binding|bind|active|Repeating subform instance count is the matched dataset record count clamped to [occur.min, occur.max] (XFA \u{00A7}4.4.3, p186-192). When data exceeds occur.max the count is capped; when data is below occur.min the count is lifted.|examples:merger::tests::repeating_subform_clamps_to_occur_max,merger::tests::repeating_subform_respects_occur_min|counterexamples:merger::tests::repeating_subform_unbounded_uses_data_count,XDP_BIND_NONE_PAGE_IS_NOT_DROPPED|sources:benchmarks/runs/M5_OCCUR_RULE_DOSSIER.md|trace:data_count_clamped_by_occur_max\n\
bind_none_subform_does_not_auto_expand|binding|bind|active|Subforms marked <bind match=\"none\"> are not auto-expanded from datasets even when their <occur> would otherwise allow repetition. They remain as a single template instance; only the scriptable InstanceManager may add more (XFA \u{00A7}4.4.3).|examples:XDP_BIND_NONE_OCCUR_REPEATING|counterexamples:merger::tests::repeating_subform_expands_from_data,XDP_BIND_NONE_NON_REPEATING_OCCUR|sources:benchmarks/runs/M5_OCCUR_BIND_NONE_DOSSIER.md|trace:bind_none_subform_expansion_skipped\n\
form_dom_driven_repeat_instance_replication|binding|bind|active|When the saved form DOM records more repeating-subform instances than the template's initial expansion produced, the engine clones the template instance to match the form DOM's count. The form DOM is authoritative because it captures the runtime's InstanceManager decisions after scripts executed (XFA \u{00A7}4.4.3 + \u{00A7}6.4.3).|examples:XDP_FORM_DOM_THREE_INSTANCES|counterexamples:merger::tests::repeating_subform_expands_from_data,XDP_FORM_DOM_SAME_AS_TEMPLATE|sources:benchmarks/runs/M5_OCCUR_FORMDOM_REPEAT_DOSSIER.md|trace:subform_materialised_from_data"
    );
}
