#![allow(static_mut_refs)]

use log::*;

use crate::logging::RenderbugLogger;

#[derive(Debug)]
struct TracedTask {
    id: u32,
    name: &'static str,
    priority: u32,
    running: bool,
    ready: bool
}

impl TracedTask {
    fn new(id: u32) -> Self {
        Self {
            id,
            name: "<unnamed task>",
            priority: 0,
            running: false,
            ready: false
        }
    }
}

pub struct Tracer {}

struct TracerState {
    tasks: [core::mem::MaybeUninit<TracedTask>; 16],
    num_tasks: usize,
}

static mut TRACER_STATE: TracerState = TracerState::new();

impl TracerState {
    const fn new() -> Self {
        Self {
            tasks: [const { core::mem::MaybeUninit::uninit() }; 16],
            num_tasks: 0,
        }
    }

    fn get_task(&mut self, id: u32) -> &mut TracedTask {
        for i in 0..self.num_tasks {
            let info = unsafe { &mut *self.tasks[i].as_mut_ptr() };
            if info.id == id {
                return info;
            }
        }

        // Otherwise, we register a new task
        if self.num_tasks < self.tasks.len() {
            self.tasks[self.num_tasks].write(TracedTask::new(id));
            self.num_tasks += 1;
        } else {
            panic!("too many tasks registered");
        }

        unsafe { &mut *self.tasks[self.num_tasks - 1].as_mut_ptr() }
    }
}

impl rtos_trace::RtosTrace for Tracer {
    fn start() {
        warn!("rtos start");
    }

    fn stop() {
        warn!("rtos stop");
    }

    fn task_new(id: u32) {
        let task = unsafe { TRACER_STATE.get_task(id) };
        warn!("rtos new task {task:?}");
    }

    fn task_send_info(id: u32, info: rtos_trace::TaskInfo) {
        let task = unsafe { TRACER_STATE.get_task(id) };
        task.name = info.name;
        task.priority = info.priority;
        warn!("rtos task info for task {task:?}");
    }

    fn task_new_stackless(id: u32, name: &'static str, priority: u32) {
        let task = unsafe { TRACER_STATE.get_task(id) };
        task.name = name;
        task.priority = priority;
        warn!("rtos new task {task:?} {name}");
    }

    fn task_terminate(id: u32) {
        let task = unsafe { TRACER_STATE.get_task(id) };
        warn!("rtos terminate {task:?}")
    }

    fn task_exec_begin(id: u32) {
        let task = unsafe { TRACER_STATE.get_task(id) };
        task.running = true;
        warn!("rtos exec {task:?}")
    }

    fn task_exec_end() {
        warn!("rtos exec end");
    }

    fn task_ready_begin(id: u32) {
        let task = unsafe { TRACER_STATE.get_task(id) };
        task.ready = true;
        warn!("rtos ready {task:?}")
    }

    fn task_ready_end(id: u32) {
        let task = unsafe { TRACER_STATE.get_task(id) };
        task.ready = false;
        warn!("rtos suspend {task:?}")
    }

    fn system_idle() {
        warn!("rtos system idle");
    }

    fn isr_enter() {
        warn!("rtos isr enter");
    }

    fn isr_exit() {
        warn!("rtos isr exit");
    }

    fn isr_exit_to_scheduler() {
        warn!("rtos isr exit to scheduler");
    }

    fn name_marker(id: u32, name: &'static str) {
        warn!("rtos name marker {id}: {name}");
    }

    fn marker(id: u32) {
        warn!("rtos marker {}", Self::name_for_marker(id));
    }

    fn marker_begin(id: u32) {
        match id {
            //1..2 => trace!("rtos marker begin {}", Self::name_for_marker(id)),
            _ => {
                warn!("rtos marker begin {}", Self::name_for_marker(id));
                RenderbugLogger::set_level(LevelFilter::Trace);
            }
        }

    }

    fn marker_end(id: u32) {
        match id {
            //1..2 => trace!("rtos marker end {}", Self::name_for_marker(id)),
            _ => {
                warn!("rtos marker end {}", Self::name_for_marker(id));
                RenderbugLogger::reset_level();
            },
        }
    }
}

impl Tracer {
    const fn name_for_marker(id: u32) -> &'static str {
        match id {
            0 => "run scheduler",
            1 => "yield task",
            2 => "timer tick",
            3 => "process timer queue",
            4 => "process embassy timer queue",
            _ => "unknown",
        }
    }
}
