use super::constructor_families::build_constructor_family_evidence;
use super::live_entry_directory::build_live_entry_directory_evidence;
use super::save_side_corpus::build_save_side_corpus_evidence;
use crate::inspect::smp::services::*;

pub(super) fn build_attach_rebuild_hypothesis(
    analysis: &SmpSaveCompanyChairmanAnalysisReport,
    scan: &super::super::super::family_scan::InfrastructureFamilyScan,
) -> SmpServiceConsumerHypothesis {
    let side_buffer = analysis.placed_structure_dynamic_side_buffer.as_ref();
    let mut evidence = vec![
        "atlas already bounds these helpers under the literal Infrastructure owner".to_string(),
        "the side-buffer corpus is disjoint from the placed-structure triplet corpus, so a separate child/rebuild family is more plausible than a compact alias".to_string(),
        "direct disassembly now shows 0x00493be0 opening tag family 0x38a5/0x38a6/0x38a7, reading one shared dword into the owner-local 0x90/0x94 lane, iterating each live collection entry, and dispatching every loaded infrastructure record through 0x0048dcf0 before the later follow-on owners run".to_string(),
        "direct disassembly now also shows 0x00491c60 as the serializer sibling of 0x00493be0: it writes tags 0x38a5/0x38a6/0x38a7, serializes the shared owner-local dword from [this+0x90], iterates live entries through 0x00518380/0x00518140, and dispatches each entry to 0x0048a6c0".to_string(),
    ];
    evidence.extend(build_constructor_family_evidence());
    evidence.push("objdump on 0x52ec50 now also makes the short footer bytes literal: it serializes one byte from bit 5 of [this+0x20] and one byte from bit 6 of [this+0x20] through 0x531030, so the residual compact-prefix ambiguity still lives in how those footer bits compose with the next-record prelude rather than in the seeded name lanes themselves".to_string());
    evidence.push("direct disassembly now also grounds one concrete consumer strip below those footer bits: 0x00528d90 only admits the child when the explicit caller override is set, the surrounding global override byte [owner+0x3692] is set, or bit 0x20 in [child+0x20] is set; the sibling loop at 0x00529730 only takes the later 0x530280 follow-on when bit 0x40 in [child+0x20] is set".to_string());
    evidence.push("that footer-bit consumer strip is tied to a broader higher-layer owner family now too: the same 0x005295f0..0x005297b7 loop repopulates a candidate cell set through 0x00533ba0, walks candidate child lists through 0x00556ef0/0x00556f00, and honors the same controller mode byte [owner+0x3692] that the checked-in atlas already ties to the world-window presentation dispatcher. So the remaining bit-0x20 question belongs to that nearby-presentation/controller family rather than to a free-floating serializer flag".to_string());
    evidence.push("the neighboring helpers tighten that owner family further: atlas-backed 0x00533ba0 is the nearby-presentation cell-table helper under the layout/presenter strip, direct disassembly shows 0x00548da0 walking list root [layout+0x2593], and direct disassembly of 0x0054bab0 mutates layout slots [layout+0x2637/+0x263b/+0x2643]. That means the 0x005295f0..0x005297b7 footer-bit consumer is sitting in layout/presentation state, not in a simulation-owned infrastructure service".to_string());
    evidence.push("objdump on 0x531030/0x5a464d/0x5a44a8 now also shows the infrastructure writer is not hiding another per-owner transform there: 0x531030 just forwards the caller-supplied pointer and byte count into the generic stream backend, and 0x5a44a8 is the shared chunked stream write path keyed by the stream handle rather than an infrastructure-specific encoder".to_string());
    evidence.push("that caller-matrix split now rules out one easy explanation for the mixed save-side prefixes: the shared 0xff0000ff/0x0001/0xff class cannot come from selector-copy state alone, because its dominant TrackCap rows come from mode-0x0b callers that bypass selector-copy entirely while the tunnel residue comes from mode-0x02 callers that necessarily flow through it".to_string());
    evidence.extend(build_save_side_corpus_evidence(analysis, scan));
    evidence.extend(build_live_entry_directory_evidence());
    evidence.push("direct disassembly now also shows the shared child payload callback 0x00455fc0 opening 0x55f1, parsing three len-prefixed strings through 0x531380, opening 0x55f2, seeding the child through 0x455b70, dispatching slot +0x48, and then opening 0x55f3".to_string());
    evidence.push("direct disassembly now also shows 0x00455b70 storing those three payload strings into [this+0x206/+0x20a/+0x20e], defaulting the second lane through a fixed literal when absent and defaulting the third lane back to the first string when absent".to_string());
    evidence.push("direct disassembly now also shows the post-+0x48 helper pair 0x52ebd0/0x52ec50 loading and serializing two single-byte lanes around the trailing 0x55f3 tag while folding them into bits 0x20 and 0x40 of [this+0x20]".to_string());
    evidence.push("direct disassembly now also shows 0x455870 consuming six 4-byte lanes from the fixed 0x55f2 chunk and forwarding them into 0x530720 then 0x52e8b0, while 0x455930 serializes the same six dword lanes back through 0x531030".to_string());
    evidence.push("direct disassembly now also shows 0x530720 publishing the first fixed-triplet lane into [this+0x1e2/+0x1e6/+0x1ea], while 0x52e8b0 publishes the second fixed-triplet lane into [this+0x4b/+0x4f/+0x53] and sets bit 0x02".to_string());
    evidence.push("direct disassembly now also shows the outer owner at 0x0048dcf0 reading one u16 child count through 0x531150 into the stream prelude, zeroing [this+0x08], and conditionally reading one saved primary-child byte before the per-child callback loop runs".to_string());
    evidence.push(
        side_buffer
            .and_then(|probe| probe.live_entry_prelude_summary.as_ref())
            .map(|summary| {
                format!(
                    "the widened save-side probe now also decodes {} live-entry payload starts inside the records span; dominant child count={} x{}, dominant saved primary-child byte={} x{}, and {} payloads reach the first 0x55f1 child callback at offset +0x3",
                    summary.rows_with_payload_pointer_inside_records_span,
                    summary.dominant_child_count.unwrap_or_default(),
                    summary.dominant_child_count_count,
                    summary
                        .dominant_saved_primary_child_byte_hex
                        .as_deref()
                        .unwrap_or("0x00"),
                    summary.dominant_saved_primary_child_byte_count,
                    summary.rows_with_first_name_tag_at_offset_3
                )
            })
            .unwrap_or_else(|| {
                "no live-entry payload-start summary was available for the outer prelude"
                    .to_string()
            }),
    );
    evidence.push("local .rdata at 0x005cfd00 now also proves the infrastructure child table uses the shared tagged callback strip directly: slot +0x40 = 0x455fc0, slot +0x44 = 0x4559d0, slot +0x48 = 0x455870, and slot +0x4c = 0x455930".to_string());
    evidence.push("direct disassembly now shows 0x0048a1e0 cloning the first child triplet bands through 0x52e880/0x52e720, destroying the prior child, seeding a new literal Infrastructure child through 0x455b70 with payload seed 0x5c87a8, attaching through 0x5395d0 or 0x53a5d0, and republishing the two bands through 0x52e8b0/0x530720".to_string());
    evidence.push("direct disassembly now also shows the outer owner at 0x0048dcf0 reading a child count plus optional primary-child ordinal from the tagged stream through 0x531150, zeroing [this+0x08], dispatching each fresh child through 0x455a50 -> vtable slot +0x40, culling ordinals above 5, and restoring cached primary-child slot [this+0x248] from the saved ordinal".to_string());
    evidence.push("the smaller attach primitive 0x00490a3c no longer looks like the semantic fork by itself: it just allocates one literal Infrastructure child, seeds it through 0x455b70 with caller-provided stem input, attaches it through 0x5395d0, seeds position lanes through 0x539530/0x53a5b0, and optionally caches it as primary child".to_string());

    SmpServiceConsumerHypothesis {
        label: "infrastructure child attach/rebuild path".to_string(),
        status: if side_buffer.is_some() {
            "highest_priority_static_mapping_target".to_string()
        } else {
            "possible_consumer_family".to_string()
        },
        candidate_consumers: vec![
            "0x00493be0 infrastructure tagged side-buffer collection load owner".to_string(),
            "0x0048a1e0 infrastructure child attach helper".to_string(),
            "0x0048dcf0 infrastructure tagged child-stream restore outer owner".to_string(),
            "0x0048dd50 infrastructure child rebuild loop".to_string(),
            "0x00490a3c infrastructure payload attach helper".to_string(),
        ],
        evidence,
        blockers: vec![
            "how the remaining mixed exact compact-prefix classes map back onto constructor semantics now that the whole prelude corpus is split directly: 0xff0000ff/0x0002/0xff is pure bridge, 0xff000000/{0x0001,0x0002}/0xff are pure bridge, 0xf3010100/0x0055/0x00 is pure ballast-cap, and 0x0005d368/0x0001/0xff is pure track-cap, leaving only 0xff0000ff/0x0001/0xff and 0x000055f3/0x0001/0xff as the mixed residual classes".to_string(),
            "how the payload streams reached through 0x00518380 -> 0x00518140 align with the embedded 0x55f1 name-pair groups and compact-prefix regimes surfaced by the save-side probe".to_string(),
            "how the observed 0x55f3-to-next-0x55f1 gaps partition between the two 0x52ebd0 flag bytes and the next-record prelude now that 0x0048a6c0 is grounded as the writer for the outer child-count / primary-child prelude".to_string(),
            "which fields written through the grounded 0x00490960 -> 0x004559d0 -> slot +0x4c -> 0x52ec50 chain retain the 0x38a5 embedded name-pair semantics before route/local-runtime follow-ons take over".to_string(),
        ],
    }
}
