//! End-to-end test: EDIFACT fixture → split → assemble → map → Interchange hierarchy.

mod common;

use common::test_utils::discover_xml_paths;
use mig_bo4e::path_resolver::PathResolver;
use std::path::{Path, PathBuf};

fn fixture_path(name: &str) -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .parent()
        .unwrap()
        .parent()
        .unwrap()
        .join("example_market_communication_bo4e_transactions")
        .join(name)
}

const SCHEMA_DIR: &str = "../../crates/mig-types/src/generated/fv2504/utilmd/pids";

fn path_resolver() -> PathResolver {
    PathResolver::from_schema_dir(Path::new(SCHEMA_DIR))
}

fn mappings_dir() -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .parent()
        .unwrap()
        .parent()
        .unwrap()
        .join("mappings/FV2504/UTILMD_Strom")
}

#[test]
fn test_interchange_hierarchy_from_55001_fixture() {
    // Load a real UTILMD fixture
    let fixture = fixture_path("UTILMD/FV2504/55001_UTILMD_S2.1_ALEXANDE121980.edi");
    if !fixture.exists() {
        eprintln!("Skipping: fixture not found at {}", fixture.display());
        return;
    }
    let input = std::fs::read_to_string(&fixture).unwrap();

    // Tokenize and split
    let segments = mig_assembly::tokenize::parse_to_segments(input.as_bytes()).unwrap();
    let chunks = mig_assembly::split_messages(segments).unwrap();

    // Should be single message
    assert_eq!(chunks.messages.len(), 1, "Expected 1 message in fixture");

    // Verify UNH fields
    let msg = &chunks.messages[0];
    let (unh_ref, msg_type) = mig_bo4e::model::extract_unh_fields(&msg.unh);
    assert!(!unh_ref.is_empty(), "UNH reference should not be empty");
    assert_eq!(msg_type, "UTILMD");

    // Verify nachrichtendaten extraction
    let nd = mig_bo4e::model::extract_nachrichtendaten(&chunks.envelope);
    assert!(
        nd.get("absenderCode").is_some(),
        "Should extract sender from UNB"
    );
    assert!(
        nd.get("empfaengerCode").is_some(),
        "Should extract recipient from UNB"
    );
    assert!(
        nd.get("interchangeRef").is_some(),
        "Should extract interchange reference from UNB"
    );

    // Test split engine loading and mapping (if mapping dirs exist)
    let msg_dir = mappings_dir().join("message");
    let tx_dir = mappings_dir().join("pid_55001");
    if msg_dir.is_dir() && tx_dir.is_dir() {
        let (msg_engine, tx_engine) =
            mig_bo4e::MappingEngine::load_split(&msg_dir, &tx_dir).unwrap();
        let resolver = path_resolver();
        let msg_engine = msg_engine.with_path_resolver(resolver.clone());
        let tx_engine = tx_engine.with_path_resolver(resolver);

        // Load MIG XML and assemble the message for full pipeline test
        if let Some((mig_xml, _ahb_xml)) = discover_xml_paths("FV2504", "UTILMD", Some("Strom")) {
            let service =
                mig_assembly::ConversionService::new(&mig_xml, "UTILMD", Some("Strom"), "FV2504")
                    .unwrap();

            // Assemble the message
            let all_segments = msg.all_segments();
            let tree = mig_assembly::assembler::Assembler::new(service.mig())
                .assemble_generic(&all_segments)
                .unwrap();

            // Map with split engines
            let mapped = mig_bo4e::MappingEngine::map_interchange(
                &msg_engine,
                &tx_engine,
                &tree,
                "SG4",
                true,
            );

            // Verify message-level stammdaten
            assert!(
                mapped.stammdaten.is_object(),
                "Message stammdaten should be an object"
            );

            // Verify at least one transaction
            assert!(
                !mapped.transaktionen.is_empty(),
                "Should have at least one transaction"
            );

            // Build the full DynamicInterchange
            let interchangedaten = mig_bo4e::model::extract_interchangedaten(&chunks.envelope);
            let interchange: mig_bo4e::DynamicInterchange = mig_bo4e::Interchange {
                interchangedaten,
                nachrichten: vec![mig_bo4e::Nachricht {
                    nachrichtendaten: mig_bo4e::Nachrichtendaten {
                        unh_referenz: unh_ref,
                        nachrichten_typ: msg_type,
                    },
                    stammdaten: mapped.stammdaten,
                    transaktionen: mapped
                        .transaktionen
                        .into_iter()
                        .map(|t| t.stammdaten)
                        .collect(),
                }],
            };

            // Verify it serializes to valid JSON
            let json = serde_json::to_string_pretty(&interchange).unwrap();
            let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
            assert!(parsed["nachrichten"].is_array());
            assert_eq!(parsed["nachrichten"].as_array().unwrap().len(), 1);
            assert_eq!(
                parsed["nachrichten"][0]["nachrichtendaten"]["nachrichtenTyp"]
                    .as_str()
                    .unwrap(),
                "UTILMD"
            );
        }
    }
}
