use crate::parts::mos6522_peripheral::Mos6522Peripheral;
use crate::parts::via6522::VIA6522;
use core::constants::constants_system::*;
use core::mos6502cpu::Mos6502Cpu;
use core::periph::at28c256::At28C256;
use core::traits::rom_chip::RomChip;
use core::constants::constants_via6522::*;

/// Backplane
///
/// A Backplane hold and coordinates the cpu with the
/// rest of the peripherals.
///
/// This system has
/// -> VIA6522 for peripherals
/// -> 322KB RAM
/// -> 32KB ROM
pub struct Backplane {
    // pub for dev
    pub cpu: Mos6502Cpu,
    pub via: VIA6522,
    pub memory: Box<[u8]>,
    pub rom: At28C256,
    data_bus: u8,
    address_bus: u16
}

impl Backplane {
    pub fn new() -> Self {
        Backplane {
            cpu: Mos6502Cpu::default(),
            via: VIA6522::default(),
            memory: Box::new([0x00; SIZE_32KB]),
            rom: At28C256::default(),
            data_bus: 0x00,
            address_bus: 0x0000
        }
    }

    pub fn load_rom(&mut self, to_load: &[u8; SIZE_32KB]) {
        self.rom.program((*to_load).into());
    }

    pub fn tick(&mut self) {
        // is the CPU in read or write state
        self.address_bus = self.cpu.address_bus();
        self.data_bus = self.cpu.data_bus();
        let rw = self.cpu.read_signal;
        println!("- TICK START:");
        println!("| CPU: Address: 0b{:016b} Data: 0b{:08b} CPU RW: {rw}", self.address_bus, self.data_bus);
        // via state
        println!(
            "| VIA 0b{:08b}/0b{:08b}/0b{:08b}/0b{:08b}/",
            self.via.read(VIA6522_ORA),
            self.via.read(VIA6522_ORA),
            self.via.read(VIA6522_DDRB),
            self.via.read(VIA6522_DDRA),
        );
        println!("| LCD");


        // if we are reading
        if rw {
            println!("CPU HAS SET READ FLAG FOR ADDRESS {:04x} with data 0x{:02x}", self.address_bus, self.data_bus);
            match self.address_bus {
                0x0000..=0x3fff => {
                    // read from ram

                },
                0x4000..=0x7fff => {
                    // read from ROM

                }
                _ => {
                    println!("READ OUTSIDE DATA RANGE");
                }
            }
        } else {
            println!("CPU HAS SET WRITE FLAG FOR ADDRESS 0x{:04x} with data 0x{:02x}", self.address_bus, self.data_bus);
            match self.address_bus {
                0x6000..=0x600f => {
                    self.via.write((self.address_bus - 0x6000) as u8, self.data_bus);
                },
                0x0000..=0x3fff => {
                    self.memory[self.address_bus as usize] = self.data_bus;
                }
                _ => {
                    println!("ATTEMPT TO WRITE OUTSIDE OF MEMORY");
                }
            }
        }

        //
        //
        // match address {
        //     /// VIA
        //     0x6000..=0x600f => {
        //         if self.cpu.read_signal {
        //             self.cpu
        //                 .set_data_bus(self.via.read((address - 0x6000) as u8));
        //         } else {
        //             self.via
        //                 .write((address - 0x6000) as u8, self.cpu.data_bus());
        //         }
        //         self.via.tick();
        //     }
        //     /// RAM
        //     0x0000..=0x3fff => {
        //         if self.cpu.read_signal {
        //             self.cpu.set_data_bus(self.memory[address as usize]);
        //         } else {
        //             self.memory[address as usize] = data;
        //         }
        //     }
        //     /// ROM
        //     0x4000..=0x7fff => {
        //         println!("ROM READ AT {address:04x} / ROM OFFSET {:04x}", address - 0x4000);
        //         self.rom.read(&(address - 0x4000));
        //     }
        //     /// The ether.  Scarrrrrrrryyyy......
        //     _ => {
        //         println!("XXXXLost READ:?{} to {:04x}", self.cpu.read_signal, address);
        //     }
        // }
        println!("- TICK DONE");
    }
}
