use core::panic;

use serde_json::{Map, Value};

use crate::{
    CoreInstructionsBuilder, Executable,
    cpu::{CPU, crossbar},
    instruction_set::{
        InstructionsBuilder,
        instruction_data::{self, InstructionData, InstructionDataBuilder},
    },
    json_to_instruction::{self, json_isa},
    memory_manager::type_traits::TryToUsize,
};

pub fn json_to_executor<'a>(
    config: Value,
    mut cores: impl Iterator<Item = &'a Value>,
) -> Executable {
    let cell_precision = config.get("cell_precision").unwrap().as_i64().unwrap() as i32;
    let core_cnt = config.get("core_cnt").unwrap().as_i64().unwrap() as i32;
    let xbar_count = config.get("xbar_array_count").unwrap().as_i64().unwrap() as i32;
    let xbar_size = config.get("xbar_size").unwrap().as_array().unwrap();
    let rows_crossbar = xbar_size[0].as_i64().unwrap() as i32;
    let column_corssbar = xbar_size[1].as_i64().unwrap() as i32;
    let mut cpu = CPU::new(core_cnt);
    cpu.reserve_crossbar(xbar_count, column_corssbar * 4, rows_crossbar);
    let mut core_insts_builder = CoreInstructionsBuilder::new(core_cnt as usize);
    cores.next();
    for core_indx in 1..=core_cnt {
        let mut insts_builder = InstructionsBuilder::new();
        let mut inst_data_builder = InstructionDataBuilder::new();
        inst_data_builder.set_core_indx(core_indx).fix_core_indx();
        let json_core = cores
            .next()
            .unwrap_or_else(|| panic!("cores files less than {}", core_indx ));
        let json_core_insts = json_core
            .as_array()
            .unwrap_or_else(|| panic!("core{} has not a list of instruction", core_indx));
        for json_inst in json_core_insts {
            json_isa::json_to_instruction(&mut insts_builder, &mut inst_data_builder, json_inst);
        }
        core_insts_builder.set_core(core_indx, insts_builder.build());
    }
    Executable::new(cpu, core_insts_builder.build())
}
