#include <unordered_map>
#include <vector>
#include <string>

namespace CoborVM
{
    enum Instruction
    {
        EMPTY,

        SET,
        CLR,
        MOV,
        SWP,

        ADD,
        SUB,
        MUL,
        DIV,

        SKIP,
        JMP,
        JMPTO,

        EQL,
        BIGR,
        SMLR,
        ZERO,
    };

    struct ExecutableStep
    {
        Instruction instruction = Instruction::EMPTY;
        int arg1;
        int arg2;
        int arg3;

        int lineNumber;
    };

    // Map from string to instruction
    const std::unordered_map<std::string, Instruction> stringToInstructionMap = {
        {"SET", SET},
        {"CLR", CLR},
        {"MOV", MOV},
        {"SWP", SWP},
        {"ADD", ADD},
        {"SUB", SUB},
        {"MUL", MUL},
        {"DIV", DIV},
        {"SKIP", SKIP},
        {"JMP", JMP},
        {"JMPTO", JMPTO},
        {"EQL", EQL},
        {"BIGR", BIGR},
        {"SMLR", SMLR},
        {"ZERO", ZERO}};

    // Map from instruction to string
    const std::unordered_map<Instruction, std::string> InstructionToStringMap = {
        {SET, "SET"},
        {CLR, "CLR"},
        {MOV, "MOV"},
        {SWP, "SWP"},
        {ADD, "ADD"},
        {SUB, "SUB"},
        {MUL, "MUL"},
        {DIV, "DIV"},
        {SKIP, "SKIP"},
        {JMP, "JMP"},
        {JMPTO, "JMPTO"},
        {EQL, "EQL"},
        {BIGR, "BIGR"},
        {SMLR, "SMLR"},
        {ZERO, "ZERO"}};

    // Define the expected argument types for each instruction (true = pointer, false = literal)
    const std::unordered_map<Instruction, std::vector<bool>> instructionPatterns = {
        {Instruction::SKIP, {}},     // No arguments
        {Instruction::EMPTY, {}},     
        {Instruction::JMP, {false}}, // One literal argument
        {Instruction::JMPTO, {false}},
        {Instruction::CLR, {true}}, // One pointer argument
        {Instruction::ZERO, {true}},
        {Instruction::SET, {false, true}}, // One literal and one pointer argument
        {Instruction::MOV, {true, true}},  // Two pointer arguments
        {Instruction::SWP, {true, true}},
        {Instruction::EQL, {true, true}},
        {Instruction::BIGR, {true, true}},
        {Instruction::SMLR, {true, true}},
        {Instruction::ADD, {true, true, true}}, // Three pointer arguments
        {Instruction::SUB, {true, true, true}},
        {Instruction::MUL, {true, true, true}},
        {Instruction::DIV, {true, true, true}},
    };
}