#![feature(never_type, allocator_api, slice_ptr_get)]
use std::{
    alloc::{Allocator, Global, Layout},
    marker::PhantomData,
    sync::atomic::{AtomicBool, Ordering},
};

use device_api::dma::{DmaAllocation, DmaAllocator};
use kernel_arch_interface::{
    cpu::{CpuData, IpiQueue},
    mem::{
        DeviceMemoryAttributes, KernelTableManager, PhysicalMemoryAllocator, RawDeviceMemoryMapping,
    },
    task::{Scheduler, TaskContext, UserContextInfo},
    Architecture,
};
use libk_mm_interface::{
    address::PhysicalAddress,
    process::ProcessAddressSpaceManager,
    table::{MapAttributes, TableAllocator},
};
use yggdrasil_abi::{
    error::Error,
    process::{ProcessGroupId, Signal},
};

pub struct ArchitectureImpl;

#[derive(Debug)]
pub struct KernelTableManagerImpl;

pub struct ProcessAddressSpaceImpl<TA: TableAllocator>(!, PhantomData<TA>);

pub struct TaskContextImpl<K: KernelTableManager, PA: PhysicalMemoryAllocator>(
    !,
    PhantomData<(K, PA)>,
);

static DUMMY_INTERRUPT_MASK: AtomicBool = AtomicBool::new(true);

pub struct DummyCpuData;

impl CpuData for DummyCpuData {}

impl Architecture for ArchitectureImpl {
    type PerCpuData = DummyCpuData;
    type CpuFeatures = ();
    type BreakpointType = u8;
    const BREAKPOINT_VALUE: Self::BreakpointType = 0x00;

    fn local_cpu() -> *mut () {
        unimplemented!()
    }

    unsafe fn set_local_cpu(_cpu: *mut ()) {
        unimplemented!()
    }

    unsafe fn init_local_cpu<S: Scheduler + 'static>(_id: Option<u32>, _data: Self::PerCpuData) {
        unimplemented!()
    }

    unsafe fn init_ipi_queues(_queues: Vec<IpiQueue<Self>>) {
        unimplemented!()
    }

    fn idle_task() -> extern "C" fn(usize) -> ! {
        unimplemented!()
    }

    fn cpu_count() -> usize {
        unimplemented!()
    }

    fn cpu_index<S: Scheduler + 'static>() -> u32 {
        unimplemented!()
    }

    unsafe fn set_interrupt_mask(mask: bool) -> bool {
        DUMMY_INTERRUPT_MASK.swap(mask, Ordering::Acquire)
    }

    fn interrupt_mask() -> bool {
        unimplemented!()
    }

    fn wait_for_interrupt() {
        unimplemented!()
    }

    fn halt() -> ! {
        unimplemented!()
    }

    fn cpu_enabled_features<S: Scheduler>(
        _cpu: &kernel_arch_interface::cpu::CpuImpl<Self, S>,
    ) -> Option<&Self::CpuFeatures> {
        unimplemented!()
    }

    fn cpu_available_features<S: Scheduler>(
        _cpu: &kernel_arch_interface::cpu::CpuImpl<Self, S>,
    ) -> Option<&Self::CpuFeatures> {
        unimplemented!()
    }

    fn ipi_queue(_cpu_id: u32) -> Option<&'static IpiQueue<Self>> {
        None
    }

    fn load_barrier() {}

    fn store_barrier() {}

    fn memory_barrier() {}

    fn flush_virtual_range(_range: std::ops::Range<usize>) {}
}

impl KernelTableManager for KernelTableManagerImpl {
    fn virtualize(phys: u64) -> usize {
        phys.try_into().unwrap()
    }

    fn physicalize(virt: usize) -> u64 {
        virt.try_into().unwrap()
    }

    unsafe fn map_device_pages(
        _base: u64,
        _count: usize,
        _attrs: DeviceMemoryAttributes,
    ) -> Result<RawDeviceMemoryMapping<Self>, Error> {
        unimplemented!()
    }

    unsafe fn unmap_device_pages(_mapping: &RawDeviceMemoryMapping<Self>) {
        unimplemented!()
    }
}

impl<TA: TableAllocator> ProcessAddressSpaceManager<TA> for ProcessAddressSpaceImpl<TA> {
    const LOWER_LIMIT_PFN: usize = 16;
    const UPPER_LIMIT_PFN: usize = 1024;

    fn new() -> Result<Self, Error> {
        unimplemented!()
    }

    unsafe fn clear(&mut self) {
        unimplemented!()
    }

    unsafe fn map_page(
        &mut self,
        _address: usize,
        _physical: PhysicalAddress,
        _flags: MapAttributes,
    ) -> Result<(), Error> {
        unimplemented!()
    }

    unsafe fn unmap_page(&mut self, _address: usize) -> Result<(PhysicalAddress, bool), Error> {
        unimplemented!()
    }

    fn translate(&self, _address: usize) -> Result<(PhysicalAddress, MapAttributes), Error> {
        unimplemented!()
    }

    fn as_address_with_asid(&self) -> (u64, u64) {
        unimplemented!()
    }
}

impl<K: KernelTableManager, PA: PhysicalMemoryAllocator> TaskContext<K, PA>
    for TaskContextImpl<K, PA>
{
    const USER_STACK_EXTRA_ALIGN: usize = 0;
    const SIGNAL_STACK_EXTRA_ALIGN: usize = 0;

    unsafe fn enter(&self) -> ! {
        unimplemented!()
    }

    unsafe fn switch(&self, _from: &Self) {
        unimplemented!()
    }

    unsafe fn switch_and_drop(&self, _thread: *const ()) {
        unimplemented!()
    }

    fn user(_info: UserContextInfo) -> Result<Self, Error> {
        unimplemented!()
    }

    fn kernel(_entry: extern "C" fn(usize) -> !, _arg: usize) -> Result<Self, Error> {
        unimplemented!()
    }

    fn kernel_closure<F: FnOnce() -> ! + Send + 'static>(_f: F) -> Result<Self, Error> {
        unimplemented!()
    }

    fn set_thread_pointer(&self, _tp: usize) {
        unimplemented!()
    }
}

#[no_mangle]
extern "Rust" fn __signal_process_group(_group_id: ProcessGroupId, _signal: Signal) {
    unimplemented!()
}

pub struct HostedDmaAllocator;

impl DmaAllocator for HostedDmaAllocator {
    fn allocate(&self, layout: Layout) -> Result<DmaAllocation, Error> {
        let ptr = Global.allocate(layout.align_to(0x1000).unwrap()).unwrap();
        let base = ptr.as_non_null_ptr();
        let addr: usize = base.addr().into();
        Ok(DmaAllocation {
            host_virtual: base.cast(),
            host_physical: addr as _,
            page_count: layout.size().div_ceil(0x1000),
            bus_address: addr as _,
        })
    }
}
