//! 调度实现

use alloc::{sync::Arc, vec::Vec};

use crate::{
    processor::this_processor_id,
    sched::{schedule::pelt::SchedAvg, task::Task},
    space::mm::MmStruct,
    time::sched_clock::sched_clock,
};

mod pelt;

bitflags::bitflags! {
    #[derive(Clone, Copy)]
    struct SchedClassFlags: u32 {
        const ENQUEUE_WAKEUP = 0b0000_0001;
        const DEQUEUE_SLEEP  = 0b0000_0010;
    }
}

#[allow(unused)]
trait SchedClass {
    fn next(&self) -> Option<impl SchedClass>;

    fn enqueue_task(&self, rq: &Rq, tsk: Arc<Task>, flags: SchedClassFlags);
    fn dequeue_task(&self, rq: &Rq, tsk: Arc<Task>, flags: SchedClassFlags);

    fn yield_task(&self, rq: &Rq);

    fn check_preempt_curr(&self, rq: &Rq, tsk: Arc<Task>, flags: SchedClassFlags);

    fn pick_next_task(&self, rq: &Rq, prev_tsk: Arc<Task>) -> Arc<Task>;
    fn put_prev_task(&self, rq: &Rq, prev_tsk: Arc<Task>);
    fn set_curr_task(&self, rq: &Rq, next_tsk: Arc<Task>);

    fn task_tick(&self, rq: &Rq);

    fn update_curr(&self, rq: &Rq);
}

#[repr(align(64))]
#[allow(unused)]
struct Rq {
    cpu: usize,
    nr_running: usize,
    clock: u64,
    sched_avg: SchedAvg,
    curr: Arc<Task>,
}

impl Rq {
    #[allow(unused)]
    fn init(cpu: usize, curr: Arc<Task>) -> Self {
        Self { cpu, nr_running: 0, clock: sched_clock(), sched_avg: SchedAvg::new(), curr }
    }
}

static mut RUNQUEUES: Vec<Rq> = Vec::new();

fn __schedule(_preempt: bool) {
    let cpu = this_processor_id().raw();
    let rq = unsafe { &RUNQUEUES[cpu] };
    let _prev = rq.curr.clone();
}

pub(crate) fn sched_init() {}

pub(crate) fn sched_init_cpu() {}

pub(crate) fn schedule_ipi() {
    sched_clock();
    let rq = unsafe { &mut RUNQUEUES[0] };
    rq.sched_avg.update_load_avg(sched_clock(), 1024, 2, 1);
}

/// 调度程序
///
/// # Panics
/// 内存不足将会 panic.
pub fn schedule() {
    let mm = MmStruct::create().unwrap();
    mm.switch_mm();
}

/// aaa
pub fn rq_load_avg(cpu: usize) -> u64 {
    let rq = unsafe { &RUNQUEUES[cpu] };
    rq.sched_avg.load_avg()
}

/// bbb
pub fn rq_runnable_avg(cpu: usize) -> u64 {
    let rq = unsafe { &RUNQUEUES[cpu] };
    rq.sched_avg.runnable_avg()
}

/// ccc
pub fn rq_util_avg(cpu: usize) -> u64 {
    let rq = unsafe { &RUNQUEUES[cpu] };
    rq.sched_avg.util_avg()
}
