use crate::mir::function::MirFunction;
use crate::mir::verification_types::VerificationError;
use crate::mir::ValueId;

/// Verify SSA form: single assignment and all uses defined
pub fn check_ssa_form(function: &MirFunction) -> Result<(), Vec<VerificationError>> {
    use std::collections::HashMap;
    let mut errors = Vec::new();
    let mut definitions: HashMap<ValueId, (crate::mir::BasicBlockId, usize)> = HashMap::new();

    // Treat parameters as defined at the entry block.
    for pid in &function.params {
        definitions.insert(*pid, (function.entry_block, 0));
    }

    for (block_id, block) in &function.blocks {
        for (inst_idx, sp) in block.all_spanned_instructions_enumerated() {
            if let Some(dst) = sp.inst.dst_value() {
                if let Some((first_block, _)) = definitions.insert(dst, (*block_id, inst_idx)) {
                    errors.push(VerificationError::MultipleDefinition {
                        value: dst,
                        first_block,
                        second_block: *block_id,
                    });
                }
            }
        }
    }

    for (block_id, block) in &function.blocks {
        for (inst_idx, sp) in block.all_spanned_instructions_enumerated() {
            for used_value in sp.inst.used_values() {
                if !definitions.contains_key(&used_value) {
                    eprintln!(
                        "[ssa-undef-debug] fn={} bb={:?} inst_idx={} used={:?} inst={:?}",
                        function.signature.name, block_id, inst_idx, used_value, sp.inst
                    );
                    errors.push(VerificationError::UndefinedValue {
                        value: used_value,
                        block: *block_id,
                        instruction_index: inst_idx,
                    });
                }
            }
        }
    }

    if errors.is_empty() {
        Ok(())
    } else {
        Err(errors)
    }
}
