Enhance this massively. Include full opcode coverage
use crate::disassembler::instruction::Instruction;
use crate::utils::helpers::{bytes_to_i32, bytes_to_u16, bytes_to_u32, bytes_to_u64};
use bitflags::bitflags;
use std::collections::HashMap;

/// Structure representing the Disassembler.
pub struct Disassembler {
    is_64_bit: bool,
    opcode_map: HashMap<Vec<u8>, OpCode>,
}

impl Disassembler {
    /// Creates a new `Disassembler` instance.
    pub fn new(is_64_bit: bool) -> Self {
        let mut opcode_map = HashMap::new();

        // Populate the opcode map with an extended set of opcodes.
        // This is still a non-exhaustive list and can be expanded further.

        // Single-byte opcodes
        opcode_map.insert(
            vec![0x90],
            OpCode {
                mnemonic: "NOP",
                operand1: OperandType::None,
                operand2: OperandType::None,
                opcode_length: 1,
                needs_modrm: false,
            },
        );

        opcode_map.insert(
            vec![0xC3],
            OpCode {
                mnemonic: "RET",
                operand1: OperandType::None,
                operand2: OperandType::None,
                opcode_length: 1,
                needs_modrm: false,
            },
        );

        // MOV instructions (Register to/from Immediate)
        for reg in 0..8 {
            // MOV r32, imm32 or MOV r64, imm64 (with REX prefix for r8-r15 in 64-bit)
            let opcode = vec![0xB8 + reg];
            let reg_name = if is_64_bit {
                format!("R{}", reg)
            } else {
                format!("E{}", reg)
            };
            opcode_map.insert(
                opcode.clone(),
                OpCode {
                    mnemonic: "MOV",
                    operand1: OperandType::Register(reg_name.clone()),
                    operand2: OperandType::Immediate(0), // Placeholder, handled separately
                    opcode_length: 1,
                    needs_modrm: false,
                },
            );
        }

        // ADD instructions
        opcode_map.insert(
            vec![0x01],
            OpCode {
                mnemonic: "ADD",
                operand1: OperandType::None, // To be determined by ModRM
                operand2: OperandType::None, // To be determined by ModRM
                opcode_length: 1,
                needs_modrm: true,
            },
        );

        // SUB instructions
        opcode_map.insert(
            vec![0x29],
            OpCode {
                mnemonic: "SUB",
                operand1: OperandType::None, // To be determined by ModRM
                operand2: OperandType::None, // To be determined by ModRM
                opcode_length: 1,
                needs_modrm: true,
            },
        );

        // XOR instructions
        opcode_map.insert(
            vec![0x31],
            OpCode {
                mnemonic: "XOR",
                operand1: OperandType::None, // To be determined by ModRM
                operand2: OperandType::None, // To be determined by ModRM
                opcode_length: 1,
                needs_modrm: true,
            },
        );

        // AND instructions
        opcode_map.insert(
            vec![0x21],
            OpCode {
                mnemonic: "AND",
                operand1: OperandType::None, // To be determined by ModRM
                operand2: OperandType::None, // To be determined by ModRM
                opcode_length: 1,
                needs_modrm: true,
            },
        );

        // OR instructions
        opcode_map.insert(
            vec![0x09],
            OpCode {
                mnemonic: "OR",
                operand1: OperandType::None, // To be determined by ModRM
                operand2: OperandType::None, // To be determined by ModRM
                opcode_length: 1,
                needs_modrm: true,
            },
        );

        // CMP instructions
        opcode_map.insert(
            vec![0x39],
            OpCode {
                mnemonic: "CMP",
                operand1: OperandType::None, // To be determined by ModRM
                operand2: OperandType::None, // To be determined by ModRM
                opcode_length: 1,
                needs_modrm: true,
            },
        );

        // IMUL instructions (two-byte opcode)
        opcode_map.insert(
            vec![0x0F, 0xAF],
            OpCode {
                mnemonic: "IMUL",
                operand1: OperandType::None, // To be determined by ModRM
                operand2: OperandType::None, // To be determined by ModRM
                opcode_length: 2,
                needs_modrm: true,
            },
        );

        // Two-byte opcodes (0x0F xx)
        opcode_map.insert(
            vec![0x0F, 0x85],
            OpCode {
                mnemonic: "JNE",
                operand1: OperandType::RelativeOffset(0),
                operand2: OperandType::None,
                opcode_length: 2,
                needs_modrm: false,
            },
        );

        opcode_map.insert(
            vec![0x0F, 0x84],
            OpCode {
                mnemonic: "JE",
                operand1: OperandType::RelativeOffset(0),
                operand2: OperandType::None,
                opcode_length: 2,
                needs_modrm: false,
            },
        );

        // Conditional Jump Short (e.g., 0x74 JZ, 0x75 JNZ, etc.)
        for (i, mnemonic) in [
            "JO",  // 0x70
            "JNO", // 0x71
            "JB",  // 0x72
            "JAE", // 0x73
            "JZ",  // 0x74
            "JNZ", // 0x75
            "JBE", // 0x76
            "JA",  // 0x77
            "JS",  // 0x78
            "JNS", // 0x79
            "JP",  // 0x7A
            "JNP", // 0x7B
            "JL",  // 0x7C
            "JGE", // 0x7D
            "JLE", // 0x7E
            "JG",  // 0x7F
        ]
        .iter()
        .enumerate()
        {
            let opcode = vec![0x70 + i as u8];
            opcode_map.insert(
                opcode.clone(),
                OpCode {
                    mnemonic,
                    operand1: OperandType::RelativeOffset(0), // Placeholder, handled separately
                    operand2: OperandType::None,
                    opcode_length: 1,
                    needs_modrm: false,
                },
            );
        }

        // CALL instructions
        opcode_map.insert(
            vec![0xE8],
            OpCode {
                mnemonic: "CALL",
                operand1: OperandType::RelativeOffset(0),
                operand2: OperandType::None,
                opcode_length: 1,
                needs_modrm: false,
            },
        );

        // JMP instructions
        opcode_map.insert(
            vec![0xE9],
            OpCode {
                mnemonic: "JMP",
                operand1: OperandType::RelativeOffset(0),
                operand2: OperandType::None,
                opcode_length: 1,
                needs_modrm: false,
            },
        );

        // PUSH instructions
        for reg in 0..8 {
            let opcode = vec![0x50 + reg];
            let reg_name = if is_64_bit {
                format!("R{}", reg)
            } else {
                format!("E{}", reg)
            };
            opcode_map.insert(
                opcode.clone(),
                OpCode {
                    mnemonic: "PUSH",
                    operand1: OperandType::Register(reg_name.clone()),
                    operand2: OperandType::None,
                    opcode_length: 1,
                    needs_modrm: false,
                },
            );
        }

        // POP instructions
        for reg in 0..8 {
            let opcode = vec![0x58 + reg];
            let reg_name = if is_64_bit {
                format!("R{}", reg)
            } else {
                format!("E{}", reg)
            };
            opcode_map.insert(
                opcode.clone(),
                OpCode {
                    mnemonic: "POP",
                    operand1: OperandType::Register(reg_name.clone()),
                    operand2: OperandType::None,
                    opcode_length: 1,
                    needs_modrm: false,
                },
            );
        }

        // LEA instructions
        opcode_map.insert(
            vec![0x8D],
            OpCode {
                mnemonic: "LEA",
                operand1: OperandType::None, // To be determined by ModRM
                operand2: OperandType::None, // To be determined by ModRM
                opcode_length: 1,
                needs_modrm: true,
            },
        );

        // INC instructions
        for reg in 0..8 {
            let opcode = vec![0x40 + reg];
            let reg_name = if is_64_bit {
                format!("R{}", reg)
            } else {
                format!("E{}", reg)
            };
            opcode_map.insert(
                opcode.clone(),
                OpCode {
                    mnemonic: "INC",
                    operand1: OperandType::Register(reg_name.clone()),
                    operand2: OperandType::None,
                    opcode_length: 1,
                    needs_modrm: false,
                },
            );
        }

        // DEC instructions
        for reg in 0..8 {
            let opcode = vec![0x48 + reg];
            let reg_name = if is_64_bit {
                format!("R{}", reg)
            } else {
                format!("E{}", reg)
            };
            opcode_map.insert(
                opcode.clone(),
                OpCode {
                    mnemonic: "DEC",
                    operand1: OperandType::Register(reg_name.clone()),
                    operand2: OperandType::None,
                    opcode_length: 1,
                    needs_modrm: false,
                },
            );
        }

        // More instructions can be added here...

        Disassembler {
            is_64_bit,
            opcode_map,
        }
    }

    /// Disassembles the given code bytes into a vector of `Instruction`s.
    pub fn disassemble(&self, code: &[u8], base_address: u32) -> Vec<Instruction> {
        let mut instructions = Vec::new();
        let mut offset: usize = 0;
        let code_len = code.len();

        while offset < code_len {
            let current_address = base_address + offset as u32;
            let start_offset = offset;

            // Handle prefixes
            let mut prefixes = Prefixes::empty();
            while offset < code_len {
                let byte = code[offset];
                match byte {
                    0xF0 | 0xF2 | 0xF3 | 0x2E | 0x36 | 0x3E | 0x26 | 0x64 | 0x65 | 0x40..=0x4F => {
                        prefixes |= Prefixes::from_bits_truncate(byte);
                        offset += 1;
                    }
                    _ => break,
                }
            }

            // Handle REX prefix for 64-bit
            let rex_prefix = if self.is_64_bit && prefixes.contains(Prefixes::REX) {
                Some(code[offset - 1])
            } else {
                None
            };

            // Determine the opcode length (1 or 2 bytes)
            let mut opcode_bytes = Vec::new();
            if offset < code_len {
                let first_byte = code[offset];
                if first_byte == 0x0F {
                    // Two-byte opcode
                    if offset + 1 < code_len {
                        opcode_bytes.push(first_byte);
                        opcode_bytes.push(code[offset + 1]);
                        offset += 2;
                    } else {
                        // Incomplete opcode
                        opcode_bytes.push(first_byte);
                        offset += 1;
                    }
                } else {
                    // Single-byte opcode
                    opcode_bytes.push(first_byte);
                    offset += 1;
                }
            }

            // Look up the opcode in the map
            let opcode_info = self.opcode_map.get(&opcode_bytes).cloned();

            match opcode_info {
                Some(opcode) => {
                    let mut instr = Instruction {
                        offset: current_address,
                        bytes: code[start_offset..offset].to_vec(),
                        mnemonic: opcode.mnemonic.to_string(),
                        operands: String::new(),
                    };

                    // Handle operands based on the opcode
                    if opcode.needs_modrm {
                        if offset >= code.len() {
                            instr.operands = "Missing ModRM byte".to_string();
                            instructions.push(instr);
                            break;
                        }

                        let modrm = parse_modrm(code[offset]);
                        instr.bytes.push(code[offset]);
                        offset += 1;

                        // Decode operands based on ModRM
                        let (reg, rm) = decode_modrm(&modrm, rex_prefix, self.is_64_bit);
                        instr.operands = format!("{}, {}", reg, rm);

                        // Additional operand decoding can be handled here based on specific instructions
                    } else {
                        match opcode.mnemonic {
                            "MOV" => {
                                // Handle MOV r32/r64, imm32/imm64
                                let imm_size = if self.is_64_bit { 8 } else { 4 };
                                if offset + imm_size <= code.len() {
                                    let imm_bytes = &code[offset..offset + imm_size];
                                    let imm = if self.is_64_bit {
                                        bytes_to_u64(imm_bytes)
                                    } else {
                                        bytes_to_u32(imm_bytes) as u64
                                    };
                                    instr.operands =
                                        format!("{}, 0x{:X}", reg_string(&opcode.operand1), imm);
                                    instr
                                        .bytes
                                        .extend_from_slice(&code[offset..offset + imm_size]);
                                    offset += imm_size;
                                } else {
                                    instr.operands = "Incomplete immediate".to_string();
                                }
                            }
                            "JNE" | "JE" | "JO" | "JNO" | "JB" | "JAE" | "JZ" | "JNZ" | "JBE"
                            | "JA" | "JS" | "JNS" | "JP" | "JNP" | "JL" | "JGE" | "JLE" | "JG" => {
                                // Handle relative jumps
                                let imm_size = 4;
                                if offset + imm_size <= code.len() {
                                    let imm_bytes = &code[offset..offset + imm_size];
                                    let imm = bytes_to_i32(imm_bytes);
                                    let target_addr = (current_address as i64)
                                        .wrapping_add(imm as i64)
                                        .wrapping_add(imm_size as i64)
                                        as u32;
                                    instr.operands = format!("0x{:X}", target_addr);
                                    instr
                                        .bytes
                                        .extend_from_slice(&code[offset..offset + imm_size]);
                                    offset += imm_size;
                                } else {
                                    instr.operands = "Incomplete relative offset".to_string();
                                }
                            }
                            "CALL" | "JMP" => {
                                // Handle CALL and JMP with relative offsets
                                let imm_size = 4;
                                if offset + imm_size <= code.len() {
                                    let imm_bytes = &code[offset..offset + imm_size];
                                    let imm = bytes_to_i32(imm_bytes);
                                    let target_addr = (current_address as i64)
                                        .wrapping_add(imm as i64)
                                        .wrapping_add(imm_size as i64)
                                        as u32;
                                    instr.operands = format!("0x{:X}", target_addr);
                                    instr
                                        .bytes
                                        .extend_from_slice(&code[offset..offset + imm_size]);
                                    offset += imm_size;
                                } else {
                                    instr.operands = "Incomplete relative offset".to_string();
                                }
                            }
                            "IMUL" => {
                                // Handle IMUL with ModRM and immediate
                                // Example: IMUL r/m32, imm32
                                let imm_size = 4;
                                if offset + imm_size <= code.len() {
                                    let imm_bytes = &code[offset..offset + imm_size];
                                    let imm = bytes_to_i32(imm_bytes);
                                    instr.operands = format!("{}, 0x{:X}", "Operand", imm);
                                    instr
                                        .bytes
                                        .extend_from_slice(&code[offset..offset + imm_size]);
                                    offset += imm_size;
                                } else {
                                    instr.operands = "Incomplete immediate".to_string();
                                }
                            }
                            "ADD" | "SUB" | "XOR" | "AND" | "OR" | "CMP" => {
                                // These opcodes require ModRM to determine operands
                                // Already handled above
                                // Additional operand size handling can be implemented here
                            }
                            "PUSH" | "POP" | "INC" | "DEC" => {
                                // These instructions do not require ModRM operands
                                // Operand has already been set in the opcode map
                            }
                            "LEA" => {
                                // Handle LEA with ModRM
                                // Deep operand parsing can be implemented here based on ModRM and SIB
                            }
                            _ => {
                                // Generic handling or leave operands empty
                                // For a more comprehensive disassembler, implement detailed operand parsing
                            }
                        }
                    }

                    instructions.push(instr);
                }
                None => {
                    // Unknown or unhandled opcode
                    let unknown_byte = code[start_offset];
                    let instr = Instruction {
                        offset: current_address,
                        bytes: vec![unknown_byte],
                        mnemonic: "UNKNOWN".to_string(),
                        operands: "".to_string(),
                    };
                    instructions.push(instr);
                }
            }
        }

        instructions
    }
}

/// Parses the ModRM byte and returns a ModRM struct.
fn parse_modrm(byte: u8) -> ModRM {
    ModRM {
        mod_field: (byte & 0b11000000) >> 6,
        reg_field: (byte & 0b00111000) >> 3,
        rm_field: byte & 0b00000111,
    }
}

/// Decodes the ModRM fields into operand strings.
fn decode_modrm(modrm: &ModRM, rex: Option<u8>, is_64_bit: bool) -> (String, String) {
    let reg = get_register_name(modrm.reg_field, rex, is_64_bit);
    let rm = match modrm.mod_field {
        0 => {
            if modrm.rm_field == 5 {
                // Direct memory addressing with 32-bit displacement
                "[disp32]".to_string()
            } else if modrm.rm_field == 4 {
                // SIB byte follows
                "[SIB]".to_string()
            } else {
                get_register_name(modrm.rm_field, rex, is_64_bit)
            }
        }
        1 => {
            // Memory addressing with 8-bit displacement
            format!(
                "[{}, disp8]",
                get_register_name(modrm.rm_field, rex, is_64_bit)
            )
        }
        2 => {
            // Memory addressing with 32-bit displacement
            format!(
                "[{}, disp32]",
                get_register_name(modrm.rm_field, rex, is_64_bit)
            )
        }
        3 => {
            // Register-direct addressing
            get_register_name(modrm.rm_field, rex, is_64_bit)
        }
        _ => "Invalid".to_string(),
    };

    (reg, rm)
}

/// Retrieves the register name based on the field and REX prefix.
fn get_register_name(field: u8, rex: Option<u8>, is_64_bit: bool) -> String {
    let extended = if let Some(rex_byte) = rex {
        (rex_byte & 0x04) != 0
    } else {
        false
    };

    let registers_32 = ["EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"];

    let registers_64 = ["RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI"];

    let extended_registers_32 = ["R8D", "R9D", "R10D", "R11D", "R12D", "R13D", "R14D", "R15D"];

    let extended_registers_64 = ["R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"];

    if extended {
        if is_64_bit {
            registers_64
                .get(field as usize)
                .unwrap_or(&"INVALID")
                .to_string()
        } else {
            extended_registers_32
                .get(field as usize)
                .unwrap_or(&"INVALID")
                .to_string()
        }
    } else {
        if is_64_bit {
            registers_64
                .get(field as usize)
                .unwrap_or(&"INVALID")
                .to_string()
        } else {
            registers_32
                .get(field as usize)
                .unwrap_or(&"INVALID")
                .to_string()
        }
    }
}

/// Converts OperandType to string representation.
fn reg_string(operand: &OperandType) -> String {
    match operand {
        OperandType::Register(reg) => reg.clone(),
        OperandType::RegisterIndirect(reg) => format!("[{}]", reg),
        OperandType::Immediate(val) => format!("0x{:X}", val),
        OperandType::RelativeOffset(off) => format!("0x{:X}", off),
        OperandType::None => "".to_string(),
    }
}

/// Structure representing the ModRM byte.
#[derive(Debug)]
struct ModRM {
    mod_field: u8,
    reg_field: u8,
    rm_field: u8,
}

/// Represents an opcode with its mnemonic and operand types.
#[derive(Debug, Clone)]
struct OpCode {
    mnemonic: &'static str,
    operand1: OperandType,
    operand2: OperandType,
    opcode_length: usize, // Number of bytes in the opcode
    needs_modrm: bool,
}

/// Enumerates the types of operands an instruction can have.
#[derive(Debug, Clone, PartialEq)]
enum OperandType {
    Register(String),
    RegisterIndirect(String),
    Immediate(u64),
    RelativeOffset(i32),
    None,
}

/// Flags for instruction prefixes.
bitflags! {
    struct Prefixes: u8 {
        const LOCK = 0xF0;
        const REPNE = 0xF2;
        const REP = 0xF3;
        const CS = 0x2E;
        const SS = 0x36;
        const DS = 0x3E;
        const ES = 0x26;
        const FS = 0x64;
        const GS = 0x65;
        const REX = 0x40; // REX prefixes start with 0100
    }
}
Provide the full code. You have essentially unlimited output tokens