Add support for more instruction a.k.a ( 20 of the most common ones )
And also make it more advanced.

instruction.rs:
use std::fmt;

/// Defines the CPU registers.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Register {
    R0,
    R1,
    R2,
    R3,
    R4,
    R5,
    R6,
    R7,
    // Additional registers can be added here
    Unknown(u8),
}

impl fmt::Display for Register {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Register::R0 => write!(f, "R0"),
            Register::R1 => write!(f, "R1"),
            Register::R2 => write!(f, "R2"),
            Register::R3 => write!(f, "R3"),
            Register::R4 => write!(f, "R4"),
            Register::R5 => write!(f, "R5"),
            Register::R6 => write!(f, "R6"),
            Register::R7 => write!(f, "R7"),
            Register::Unknown(code) => write!(f, "R{}", code),
        }
    }
}

/// Defines various operand types for instructions.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Operand {
    Register(Register),
    Immediate(u16),
    Address(u16),
    Memory {
        base: Register,
        displacement: i16,
    },
    Indirect {
        register: Register,
    },
    // Future extensions can include more complex operands
}

impl fmt::Display for Operand {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Operand::Register(reg) => write!(f, "{}", reg),
            Operand::Immediate(val) => write!(f, "0x{:04X}", val),
            Operand::Address(addr) => write!(f, "0x{:04X}", addr),
            Operand::Memory { base, displacement } => {
                if *displacement == 0 {
                    write!(f, "[{}]", base)
                } else {
                    write!(f, "[{} + {}]", base, displacement)
                }
            }
            Operand::Indirect { register } => write!(f, "*{}", register),
        }
    }
}

/// Defines the complete set of instructions supported by the CPU.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Instruction {
    /// LOAD Register, Immediate
    Load { register: Register, value: u16 },
    /// LOAD Register, Address
    LoadAddress { register: Register, address: u16 },
    /// LOAD Register, Memory
    LoadMemory {
        register: Register,
        memory: Operand,
    },
    /// STORE Register, Address
    Store { register: Register, address: u16 },
    /// STORE Register, Memory
    StoreMemory {
        register: Register,
        memory: Operand,
    },
    /// ADD Register, Register
    Add { dest: Register, src: Register },
    /// ADD Register, Immediate
    AddImmediate { dest: Register, value: u16 },
    /// SUB Register, Register
    Sub { dest: Register, src: Register },
    /// SUB Register, Immediate
    SubImmediate { dest: Register, value: u16 },
    /// MUL Register, Register
    Mul { dest: Register, src: Register },
    /// DIV Register, Register
    Div { dest: Register, src: Register },
    /// AND Register, Register
    And { dest: Register, src: Register },
    /// OR Register, Register
    Or { dest: Register, src: Register },
    /// XOR Register, Register
    Xor { dest: Register, src: Register },
    /// NOT Register
    Not { register: Register },
    /// SHL Register, Immediate
    Shl { register: Register, shift: u8 },
    /// SHR Register, Immediate
    Shr { register: Register, shift: u8 },
    /// MOV Register, Register
    Mov { dest: Register, src: Register },
    /// MOV Register, Immediate
    MovImmediate { dest: Register, value: u16 },
    /// INC Register
    Inc { register: Register },
    /// DEC Register
    Dec { register: Register },
    /// JMP Address
    Jmp { address: u16 },
    /// CALL Address
    Call { address: u16 },
    /// RET
    Ret,
    /// CMP Register, Register
    Cmp { reg1: Register, reg2: Register },
    /// JE Address
    Je { address: u16 },
    /// JNE Address
    Jne { address: u16 },
    /// PUSH Register
    Push { register: Register },
    /// POP Register
    Pop { register: Register },
    /// PUSHF
    Pushf,
    /// POPF
    Popf,
    /// NOP
    Nop,
    /// HALT
    Halt,
    /// UNKNOWN or invalid instruction
    Unknown { opcode: u8, bytes: Vec<u8> },
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Instruction::Load { register, value } => write!(f, "LOAD {}, {}", register, value),
            Instruction::LoadAddress { register, address } => {
                write!(f, "LOAD {}, {}", register, address)
            }
            Instruction::LoadMemory { register, memory } => {
                write!(f, "LOAD {}, {}", register, memory)
            }
            Instruction::Store { register, address } => write!(f, "STORE {}, {}", register, address),
            Instruction::StoreMemory { register, memory } => {
                write!(f, "STORE {}, {}", register, memory)
            }
            Instruction::Add { dest, src } => write!(f, "ADD {}, {}", dest, src),
            Instruction::AddImmediate { dest, value } => write!(f, "ADDI {}, {}", dest, value),
            Instruction::Sub { dest, src } => write!(f, "SUB {}, {}", dest, src),
            Instruction::SubImmediate { dest, value } => write!(f, "SUBI {}, {}", dest, value),
            Instruction::Mul { dest, src } => write!(f, "MUL {}, {}", dest, src),
            Instruction::Div { dest, src } => write!(f, "DIV {}, {}", dest, src),
            Instruction::And { dest, src } => write!(f, "AND {}, {}", dest, src),
            Instruction::Or { dest, src } => write!(f, "OR {}, {}", dest, src),
            Instruction::Xor { dest, src } => write!(f, "XOR {}, {}", dest, src),
            Instruction::Not { register } => write!(f, "NOT {}", register),
            Instruction::Shl { register, shift } => write!(f, "SHL {}, {}", register, shift),
            Instruction::Shr { register, shift } => write!(f, "SHR {}, {}", register, shift),
            Instruction::Mov { dest, src } => write!(f, "MOV {}, {}", dest, src),
            Instruction::MovImmediate { dest, value } => write!(f, "MOVI {}, {}", dest, value),
            Instruction::Inc { register } => write!(f, "INC {}", register),
            Instruction::Dec { register } => write!(f, "DEC {}", register),
            Instruction::Jmp { address } => write!(f, "JMP {}", address),
            Instruction::Call { address } => write!(f, "CALL {}", address),
            Instruction::Ret => write!(f, "RET"),
            Instruction::Cmp { reg1, reg2 } => write!(f, "CMP {}, {}", reg1, reg2),
            Instruction::Je { address } => write!(f, "JE {}", address),
            Instruction::Jne { address } => write!(f, "JNE {}", address),
            Instruction::Push { register } => write!(f, "PUSH {}", register),
            Instruction::Pop { register } => write!(f, "POP {}", register),
            Instruction::Pushf => write!(f, "PUSHF"),
            Instruction::Popf => write!(f, "POPF"),
            Instruction::Nop => write!(f, "NOP"),
            Instruction::Halt => write!(f, "HALT"),
            Instruction::Unknown { opcode, bytes } => {
                write!(f, "UNKNOWN 0x{:02X} {:?}", opcode, bytes)
            }
        }
    }
}

disassembler.rs:
use crate::instruction::{Instruction, Register, Operand};
use std::fmt;
use std::collections::{HashMap, HashSet};
use std::error::Error;

/// Opcode definitions for the instruction set.
mod opcodes {
    pub const LOAD: u8 = 0x01;
    pub const LOAD_ADDR: u8 = 0x02;
    pub const LOAD_MEM: u8 = 0x03;
    pub const STORE: u8 = 0x04;
    pub const STORE_MEM: u8 = 0x05;
    pub const ADD: u8 = 0x06;
    pub const ADDI: u8 = 0x07;
    pub const SUB: u8 = 0x08;
    pub const SUBI: u8 = 0x09;
    pub const MUL: u8 = 0x0A;
    pub const DIV: u8 = 0x0B;
    pub const AND: u8 = 0x0C;
    pub const OR: u8 = 0x0D;
    pub const XOR: u8 = 0x0E;
    pub const NOT: u8 = 0x0F;
    pub const SHL: u8 = 0x10;
    pub const SHR: u8 = 0x11;
    pub const MOV: u8 = 0x12;
    pub const MOVI: u8 = 0x13;
    pub const INC: u8 = 0x14;
    pub const DEC: u8 = 0x15;
    pub const JMP: u8 = 0x16;
    pub const CALL: u8 = 0x17;
    pub const RET: u8 = 0x18;
    pub const CMP: u8 = 0x19;
    pub const JE: u8 = 0x1A;
    pub const JNE: u8 = 0x1B;
    pub const PUSH: u8 = 0x1C;
    pub const POP: u8 = 0x1D;
    pub const PUSHF: u8 = 0x1E;
    pub const POPF: u8 = 0x1F;
    pub const NOP: u8 = 0x20;
    pub const HALT: u8 = 0x21;
    // Add more opcodes as needed...
}

use opcodes::*;

/// Represents the possible errors during disassembly.
#[derive(Debug, Clone)]
pub enum DisassembleError {
    /// Occurs when there are insufficient bytes to decode an instruction.
    UnexpectedEndOfData {
        address: usize,
        expected: usize,
        found: usize,
    },
    /// Occurs when an unknown opcode is encountered.
    UnknownOpcode {
        address: usize,
        opcode: u8,
    },
}

impl fmt::Display for DisassembleError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            DisassembleError::UnexpectedEndOfData { address, expected, found } => {
                write!(
                    f,
                    "Unexpected end of data at address {}: expected {} bytes, found {}",
                    address, expected, found
                )
            }
            DisassembleError::UnknownOpcode { address, opcode } => {
                write!(
                    f,
                    "Unknown opcode 0x{:02X} encountered at address {}",
                    opcode, address
                )
            }
        }
    }
}

impl Error for DisassembleError {}

/// Represents a parsed instruction along with its address and size.
#[derive(Debug, Clone)]
pub struct ParsedInstruction {
    pub address: usize,
    pub instruction: Instruction,
    pub size: usize, // Number of bytes consumed
}

/// Decoding function type. Each opcode has an associated decoding function.
type DecodeFn = fn(&[u8], usize) -> Result<(Instruction, usize), DisassembleError>;

/// Lookup table mapping opcodes to their decoding functions.
fn get_opcode_table() -> [Option<DecodeFn>; 256] {
    // Initialize all entries to None
    let mut table: [Option<DecodeFn>; 256] = [None; 256];

    // Assign decoding functions to their respective opcodes
    table[LOAD as usize] = Some(decode_load);
    table[LOAD_ADDR as usize] = Some(decode_load_addr);
    table[LOAD_MEM as usize] = Some(decode_load_mem);
    table[STORE as usize] = Some(decode_store);
    table[STORE_MEM as usize] = Some(decode_store_mem);
    table[ADD as usize] = Some(decode_add);
    table[ADDI as usize] = Some(decode_addi);
    table[SUB as usize] = Some(decode_sub);
    table[SUBI as usize] = Some(decode_subi);
    table[MUL as usize] = Some(decode_mul);
    table[DIV as usize] = Some(decode_div);
    table[AND as usize] = Some(decode_and);
    table[OR as usize] = Some(decode_or);
    table[XOR as usize] = Some(decode_xor);
    table[NOT as usize] = Some(decode_not);
    table[SHL as usize] = Some(decode_shl);
    table[SHR as usize] = Some(decode_shr);
    table[MOV as usize] = Some(decode_mov);
    table[MOVI as usize] = Some(decode_movi);
    table[INC as usize] = Some(decode_inc);
    table[DEC as usize] = Some(decode_dec);
    table[JMP as usize] = Some(decode_jmp);
    table[CALL as usize] = Some(decode_call);
    table[RET as usize] = Some(decode_ret);
    table[CMP as usize] = Some(decode_cmp);
    table[JE as usize] = Some(decode_je);
    table[JNE as usize] = Some(decode_jne);
    table[PUSH as usize] = Some(decode_push);
    table[POP as usize] = Some(decode_pop);
    table[PUSHF as usize] = Some(decode_pushf);
    table[POPF as usize] = Some(decode_popf);
    table[NOP as usize] = Some(decode_nop);
    table[HALT as usize] = Some(decode_halt);

    table
}

/// Simple label resolver for addresses to labels.
/// Implements a two-pass disassembly process.
struct LabelResolver {
    labels: HashMap<u16, String>,
    resolved: bool,
}

impl LabelResolver {
    fn new() -> Self {
        Self {
            labels: HashMap::new(),
            resolved: false,
        }
    }

    /// Adds a label for the given address.
    fn add_label(&mut self, address: u16) {
        if !self.labels.contains_key(&address) {
            let label = format!("label_{:04X}", address);
            self.labels.insert(address, label);
        }
    }

    /// Retrieves the label for the given address, if it exists.
    fn get_label(&self, address: u16) -> Option<&String> {
        self.labels.get(&address)
    }
}

/// Disassembles binary data into a vector of parsed instructions.
///
/// # Arguments
///
/// * `data` - A slice of bytes representing the binary code.
///
/// # Returns
///
/// * A vector of `ParsedInstruction` structs or a disassembly error.
pub fn disassemble(data: &[u8]) -> Result<Vec<ParsedInstruction>, DisassembleError> {
    let opcode_table = get_opcode_table();
    let mut instructions = Vec::new();
    let mut pc = 0;

    // First pass: Identify all branch/call targets to generate labels
    let mut label_resolver = LabelResolver::new();
    let mut temp_pc = 0;
    while temp_pc < data.len() {
        let opcode = data[temp_pc];
        if let Some(decode_fn) = opcode_table[opcode as usize] {
            match decode_fn(data, temp_pc) {
                Ok((instr, bytes_consumed)) => {
                    match &instr {
                        Instruction::Jmp { address }
                        | Instruction::Je { address }
                        | Instruction::Jne { address }
                        | Instruction::Call { address } => {
                            label_resolver.add_label(*address);
                        }
                        _ => {}
                    }
                    temp_pc += bytes_consumed;
                }
                Err(_) => {
                    // Unknown opcode or incomplete data; skip to next byte
                    temp_pc += 1;
                }
            }
        } else {
            // Unknown opcode; skip to next byte
            temp_pc += 1;
        }
    }

    // Second pass: Actual disassembly with labels
    while pc < data.len() {
        let address = pc;
        let opcode = data[pc];
        if let Some(decode_fn) = opcode_table[opcode as usize] {
            match decode_fn(data, pc) {
                Ok((instruction, size)) => {
                    instructions.push(ParsedInstruction {
                        address,
                        instruction,
                        size,
                    });
                    pc += size;
                }
                Err(e) => {
                    // Handle error by inserting Unknown instruction and skipping one byte
                    instructions.push(ParsedInstruction {
                        address,
                        instruction: Instruction::Unknown {
                            opcode,
                            bytes: data[pc..].iter().copied().take(1).collect(),
                        },
                        size: 1,
                    });
                    pc += 1;
                }
            }
        } else {
            // Handle unknown opcode
            instructions.push(ParsedInstruction {
                address,
                instruction: Instruction::Unknown {
                    opcode,
                    bytes: data[pc..].iter().copied().take(1).collect(),
                },
                size: 1,
            });
            pc += 1;
        }
    }

    Ok(instructions)
}

/// Decodes the LOAD instruction.
/// Format: LOAD Register, Immediate
fn decode_load(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // LOAD is 1 byte opcode + 1 byte register + 2 bytes immediate
    let expected_length = 4;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let reg_code = data[pc + 1];
    let reg = decode_register(reg_code);
    let imm = u16::from_be_bytes([data[pc + 2], data[pc + 3]]);
    Ok((
        Instruction::Load {
            register: reg,
            value: imm,
        },
        expected_length,
    ))
}

/// Decodes the LOAD_ADDR instruction.
/// Format: LOAD Register, Address
fn decode_load_addr(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // LOAD_ADDR is 1 byte opcode + 1 byte register + 2 bytes address
    let expected_length = 4;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let reg_code = data[pc + 1];
    let address = u16::from_be_bytes([data[pc + 2], data[pc + 3]]);
    let reg = decode_register(reg_code);
    Ok((
        Instruction::LoadAddress {
            register: reg,
            address,
        },
        expected_length,
    ))
}

/// Decodes the LOAD_MEM instruction.
/// Format: LOAD Register, Memory
fn decode_load_mem(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // LOAD_MEM is 1 byte opcode + 1 byte register + 1 byte base register + 2 bytes displacement
    let expected_length = 5;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let reg_code = data[pc + 1];
    let base_code = data[pc + 2];
    let disp = i16::from_be_bytes([data[pc + 3], data[pc + 4]]);
    let reg = decode_register(reg_code);
    let base = decode_register(base_code);
    let memory = Operand::Memory {
        base,
        displacement: disp,
    };
    Ok((
        Instruction::LoadMemory {
            register: reg,
            memory,
        },
        expected_length,
    ))
}

/// Decodes the STORE instruction.
/// Format: STORE Register, Address
fn decode_store(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // STORE is 1 byte opcode + 1 byte register + 2 bytes address
    let expected_length = 4;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let reg_code = data[pc + 1];
    let address = u16::from_be_bytes([data[pc + 2], data[pc + 3]]);
    let reg = decode_register(reg_code);
    Ok((
        Instruction::Store {
            register: reg,
            address,
        },
        expected_length,
    ))
}

/// Decodes the STORE_MEM instruction.
/// Format: STORE Register, Memory
fn decode_store_mem(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // STORE_MEM is 1 byte opcode + 1 byte register + 1 byte base register + 2 bytes displacement
    let expected_length = 5;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let reg_code = data[pc + 1];
    let base_code = data[pc + 2];
    let disp = i16::from_be_bytes([data[pc + 3], data[pc + 4]]);
    let reg = decode_register(reg_code);
    let base = decode_register(base_code);
    let memory = Operand::Memory {
        base,
        displacement: disp,
    };
    Ok((
        Instruction::StoreMemory {
            register: reg,
            memory,
        },
        expected_length,
    ))
}

/// Decodes the ADD instruction.
/// Format: ADD Register, Register
fn decode_add(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // ADD is 1 byte opcode + 1 byte dest + 1 byte src
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let dest_code = data[pc + 1];
    let src_code = data[pc + 2];
    let dest = decode_register(dest_code);
    let src = decode_register(src_code);
    Ok((
        Instruction::Add { dest, src },
        expected_length,
    ))
}

/// Decodes the ADDI instruction.
/// Format: ADDI Register, Immediate
fn decode_addi(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // ADDI is 1 byte opcode + 1 byte dest + 2 bytes immediate
    let expected_length = 4;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let dest_code = data[pc + 1];
    let imm = u16::from_be_bytes([data[pc + 2], data[pc + 3]]);
    let dest = decode_register(dest_code);
    Ok((
        Instruction::AddImmediate {
            dest,
            value: imm,
        },
        expected_length,
    ))
}

/// Decodes the SUB instruction.
/// Format: SUB Register, Register
fn decode_sub(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // Similar to ADD
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let dest_code = data[pc + 1];
    let src_code = data[pc + 2];
    let dest = decode_register(dest_code);
    let src = decode_register(src_code);
    Ok((
        Instruction::Sub { dest, src },
        expected_length,
    ))
}

/// Decodes the SUBI instruction.
/// Format: SUBI Register, Immediate
fn decode_subi(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // Similar to ADDI
    let expected_length = 4;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let dest_code = data[pc + 1];
    let imm = u16::from_be_bytes([data[pc + 2], data[pc + 3]]);
    let dest = decode_register(dest_code);
    Ok((
        Instruction::SubImmediate {
            dest,
            value: imm,
        },
        expected_length,
    ))
}

/// Decodes the MUL instruction.
/// Format: MUL Register, Register
fn decode_mul(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // Similar to ADD
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let dest_code = data[pc + 1];
    let src_code = data[pc + 2];
    let dest = decode_register(dest_code);
    let src = decode_register(src_code);
    Ok((
        Instruction::Mul { dest, src },
        expected_length,
    ))
}

/// Decodes the DIV instruction.
/// Format: DIV Register, Register
fn decode_div(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // Similar to ADD
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }
    let dest_code = data[pc + 1];
    let src_code = data[pc + 2];
    let dest = decode_register(dest_code);
    let src = decode_register(src_code);
    Ok((
        Instruction::Div { dest, src },
        expected_length,
    ))
}

/// Decodes the AND instruction.
/// Format: AND Register, Register
fn decode_and(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // Similar to ADD
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let dest_code = data[pc + 1];
    let src_code = data[pc + 2];
    let dest = decode_register(dest_code);
    let src = decode_register(src_code);
    Ok((
        Instruction::And { dest, src },
        expected_length,
    ))
}

/// Decodes the OR instruction.
/// Format: OR Register, Register
fn decode_or(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // Similar to ADD
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let dest_code = data[pc + 1];
    let src_code = data[pc + 2];
    let dest = decode_register(dest_code);
    let src = decode_register(src_code);
    Ok((
        Instruction::Or { dest, src },
        expected_length,
    ))
}

/// Decodes the XOR instruction.
/// Format: XOR Register, Register
fn decode_xor(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // Similar to ADD
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let dest_code = data[pc + 1];
    let src_code = data[pc + 2];
    let dest = decode_register(dest_code);
    let src = decode_register(src_code);
    Ok((
        Instruction::Xor { dest, src },
        expected_length,
    ))
}

/// Decodes the NOT instruction.
/// Format: NOT Register
fn decode_not(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // NOT is 1 byte opcode + 1 byte register
    let expected_length = 2;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let reg_code = data[pc + 1];
    let reg = decode_register(reg_code);
    Ok((
        Instruction::Not { register: reg },
        expected_length,
    ))
}

/// Decodes the SHL instruction.
/// Format: SHL Register, Immediate
fn decode_shl(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // SHL is 1 byte opcode + 1 byte register + 1 byte shift amount
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let reg_code = data[pc + 1];
    let shift = data[pc + 2];
    let reg = decode_register(reg_code);
    Ok((
        Instruction::Shl {
            register: reg,
            shift,
        },
        expected_length,
    ))
}

/// Decodes the SHR instruction.
/// Format: SHR Register, Immediate
fn decode_shr(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // SHR is 1 byte opcode + 1 byte register + 1 byte shift amount
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let reg_code = data[pc + 1];
    let shift = data[pc + 2];
    let reg = decode_register(reg_code);
    Ok((
        Instruction::Shr {
            register: reg,
            shift,
        },
        expected_length,
    ))
}

/// Decodes the MOV instruction.
/// Format: MOV Register, Register
fn decode_mov(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // MOV is 1 byte opcode + 1 byte dest + 1 byte src
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let dest_code = data[pc + 1];
    let src_code = data[pc + 2];
    let dest = decode_register(dest_code);
    let src = decode_register(src_code);
    Ok((
        Instruction::Mov { dest, src },
        expected_length,
    ))
}

/// Decodes the MOVI instruction.
/// Format: MOVI Register, Immediate
fn decode_movi(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // MOVI is 1 byte opcode + 1 byte dest + 2 bytes immediate
    let expected_length = 4;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let dest_code = data[pc + 1];
    let imm = u16::from_be_bytes([data[pc + 2], data[pc + 3]]);
    let dest = decode_register(dest_code);
    Ok((
        Instruction::MovImmediate {
            dest,
            value: imm,
        },
        expected_length,
    ))
}

/// Decodes the INC instruction.
/// Format: INC Register
fn decode_inc(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // INC is 1 byte opcode + 1 byte register
    let expected_length = 2;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let reg_code = data[pc + 1];
    let reg = decode_register(reg_code);
    Ok((
        Instruction::Inc { register: reg },
        expected_length,
    ))
}

/// Decodes the DEC instruction.
/// Format: DEC Register
fn decode_dec(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // DEC is 1 byte opcode + 1 byte register
    let expected_length = 2;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let reg_code = data[pc + 1];
    let reg = decode_register(reg_code);
    Ok((
        Instruction::Dec { register: reg },
        expected_length,
    ))
}

/// Decodes the JMP instruction.
/// Format: JMP Address
fn decode_jmp(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // JMP is 1 byte opcode + 2 bytes address
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let addr = u16::from_be_bytes([data[pc + 1], data[pc + 2]]);
    Ok((
        Instruction::Jmp { address: addr },
        expected_length,
    ))
}

/// Decodes the CALL instruction.
/// Format: CALL Address
fn decode_call(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // CALL is 1 byte opcode + 2 bytes address
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let addr = u16::from_be_bytes([data[pc + 1], data[pc + 2]]);
    Ok((
        Instruction::Call { address: addr },
        expected_length,
    ))
}

/// Decodes the RET instruction.
/// Format: RET
fn decode_ret(_data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // RET is 1 byte opcode
    Ok((Instruction::Ret, 1))
}

/// Decodes the CMP instruction.
/// Format: CMP Register, Register
fn decode_cmp(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // CMP is 1 byte opcode + 1 byte reg1 + 1 byte reg2
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let reg1_code = data[pc + 1];
    let reg2_code = data[pc + 2];
    let reg1 = decode_register(reg1_code);
    let reg2 = decode_register(reg2_code);
    Ok((
        Instruction::Cmp { reg1, reg2 },
        expected_length,
    ))
}

/// Decodes the JE instruction.
/// Format: JE Address
fn decode_je(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // JE is 1 byte opcode + 2 bytes address
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let addr = u16::from_be_bytes([data[pc + 1], data[pc + 2]]);
    Ok((
        Instruction::Je { address: addr },
        expected_length,
    ))
}

/// Decodes the JNE instruction.
/// Format: JNE Address
fn decode_jne(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // JNE is 1 byte opcode + 2 bytes address
    let expected_length = 3;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let addr = u16::from_be_bytes([data[pc + 1], data[pc + 2]]);
    Ok((
        Instruction::Jne { address: addr },
        expected_length,
    ))
}

/// Decodes the PUSH instruction.
/// Format: PUSH Register
fn decode_push(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // PUSH is 1 byte opcode + 1 byte register
    let expected_length = 2;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let reg_code = data[pc + 1];
    let reg = decode_register(reg_code);
    Ok((
        Instruction::Push { register: reg },
        expected_length,
    ))
}

/// Decodes the POP instruction.
/// Format: POP Register
fn decode_pop(data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // POP is 1 byte opcode + 1 byte register
    let expected_length = 2;
    if pc + expected_length > data.len() {
        return Err(DisassembleError::UnexpectedEndOfData {
            address: pc,
            expected: expected_length,
            found: data.len() - pc,
        });
    }

    let reg_code = data[pc + 1];
    let reg = decode_register(reg_code);
    Ok((
        Instruction::Pop { register: reg },
        expected_length,
    ))
}

/// Decodes the PUSHF instruction.
/// Format: PUSHF
fn decode_pushf(_data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // PUSHF is 1 byte opcode
    Ok((Instruction::Pushf, 1))
}

/// Decodes the POPF instruction.
/// Format: POPF
fn decode_popf(_data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // POPF is 1 byte opcode
    Ok((Instruction::Popf, 1))
}

/// Decodes the NOP instruction.
/// Format: NOP
fn decode_nop(_data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // NOP is 1 byte opcode
    Ok((Instruction::Nop, 1))
}

/// Decodes the HALT instruction.
/// Format: HALT
fn decode_halt(_data: &[u8], pc: usize) -> Result<(Instruction, usize), DisassembleError> {
    // HALT is 1 byte opcode
    Ok((Instruction::Halt, 1))
}

/// Decodes a register code into a `Register` enum.
///
/// # Arguments
///
/// * `code` - The register code as a `u8`.
///
/// # Returns
///
/// * A `Register` enum variant.
fn decode_register(code: u8) -> Register {
    match code {
        0x00 => Register::R0,
        0x01 => Register::R1,
        0x02 => Register::R2,
        0x03 => Register::R3,
        0x04 => Register::R4,
        0x05 => Register::R5,
        0x06 => Register::R6,
        0x07 => Register::R7,
        unknown => Register::Unknown(unknown),
    }
}

/// Formats the disassembled instructions with labels.
///
/// # Arguments
///
/// * `instructions` - A slice of `ParsedInstruction` structs.
///
/// # Returns
///
/// * A formatted string representing the disassembled code.
pub fn format_disassembly(instructions: &[ParsedInstruction]) -> String {
    let mut output = String::new();
    let mut label_map: HashMap<u16, String> = HashMap::new();

    // First pass: Collect labels
    for instr in instructions {
        match &instr.instruction {
            Instruction::Jmp { address }
            | Instruction::Je { address }
            | Instruction::Jne { address }
            | Instruction::Call { address } => {
                if !label_map.contains_key(address) {
                    let label = format!("label_{:04X}", address);
                    label_map.insert(*address, label);
                }
            }
            _ => {}
        }
    }

    // Second pass: Print instructions with labels
    for instr in instructions {
        // Check if current address has a label
        if let Some(label) = label_map.get(&(instr.address as u16)) {
            output.push_str(&format!("{}:\n", label));
        }
        // Format instruction
        output.push_str(&format!("    {}    ; 0x{:04X}\n", instr.instruction, instr.address));
    }

    output
}