//! Simple "passthrough" bus device

// use device_tree::{device_tree_driver, dt::DevTreeIndexNodeExt};
// use libk::device::manager::DEVICE_REGISTRY;

use core::ops::Range;

use abi::error::Error;
use alloc::{sync::Arc, vec::Vec};
use device_api::{
    bus::Bus,
    device::{Device, DeviceInitContext},
};
use device_tree::{
    driver::{device_tree_driver, Node, ProbeContext},
    DeviceTreePropertyRead,
};

struct SimpleBus {
    ranges: Vec<(Range<u64>, u64)>,
}

impl Device for SimpleBus {
    unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
        Ok(())
    }

    fn as_bus(self: Arc<Self>) -> Option<Arc<dyn Bus>> {
        Some(self)
    }

    fn display_name(&self) -> &str {
        "simple-bus"
    }
}

impl Bus for SimpleBus {
    fn map_range(&self, bus_range: Range<u64>) -> Option<Range<u64>> {
        if self.ranges.is_empty() {
            return Some(bus_range);
        }

        let start = bus_range.start;
        let end = bus_range.end;

        for (range, offset) in self.ranges.iter() {
            if range.contains(&start) && range.contains(&end) {
                let start = start - range.start + *offset;
                let end = end - range.start + *offset;
                return Some(start..end);
            }
        }

        None
    }
}

device_tree_driver! {
    compatible: ["simple-bus"],
    driver: {
        fn probe(&self, node: &Arc<Node>, _context: &mut ProbeContext) -> Option<Arc<dyn Device>> {
            // Format per DT spec: (child-bus-address, parent-bus-address, length)
            // Where:
            //  child-bus-address: #address-cells of this node
            //  parent-bus-address: #address-cells of parent bus
            //  length: #size-cells of this node
            let ranges = node.property("ranges")?;

            let parent_address_cells = node.bus_address_cells();
            let child_address_cells = node.self_address_cells()?;
            let child_size_cells = node.self_size_cells()?;

            let cell_sizes = (child_address_cells, parent_address_cells, child_size_cells);

            let mut items = Vec::new();

            for (child_address, parent_address, length) in ranges.iter_cells(cell_sizes) {
                let child_range = child_address..child_address + length;
                items.push((child_range, parent_address));
            }

            Some(Arc::new(SimpleBus {
                ranges: items,
            }))
        }
    }
}
