use crate::write_log;

use self::{rendering::Rendering, rfactor_data::RFactorData};

mod pipeline;
mod rendering;
mod rfactor_data;

use anyhow::Result;
use std::sync::{Arc, Mutex};
use vulkan_rs::prelude::*;

pub struct Overlay {
    instance: Option<Arc<Instance>>,
    device: Option<Arc<Device>>,
    queue: Option<Arc<Mutex<Queue>>>,
    rendering: Option<Rendering>,

    rfactor_data: Option<RFactorData>,
}

impl Overlay {
    pub const fn new() -> Self {
        Self {
            instance: None,
            device: None,
            queue: None,
            rendering: None,

            rfactor_data: None,
        }
    }

    pub fn set_instance(&mut self, instance: Arc<Instance>) {
        self.instance = Some(instance);
    }

    pub fn instance(&self) -> Arc<Instance> {
        self.instance.as_ref().unwrap().clone()
    }

    pub fn set_device(&mut self, device: Arc<Device>) {
        self.device = Some(device);
    }

    pub fn device(&self) -> Arc<Device> {
        self.device.as_ref().unwrap().clone()
    }

    pub fn has_queue(&self) -> bool {
        self.queue.is_some()
    }

    pub fn add_queue(&mut self, queue: Arc<Mutex<Queue>>) {
        self.queue = Some(queue);
    }

    pub fn queue(&self) -> Arc<Mutex<Queue>> {
        self.queue.as_ref().unwrap().clone()
    }

    pub fn swapchain(&self, swapchain: VkSwapchainKHR) -> Option<&Arc<Swapchain>> {
        let sc = self.rendering.as_ref().unwrap().swapchain();

        if sc.vk_handle() == swapchain {
            Some(sc)
        } else {
            None
        }
    }

    pub fn create_rendering(&mut self, swapchain: Arc<Swapchain>) -> Result<()> {
        write_log("-> create rendering: start");

        self.rendering = None;

        write_log("-> create rendering: old cleared");

        self.rendering = Some(Rendering::new(self.device(), self.queue(), swapchain)?);

        write_log("-> create rendering: new created");

        write_log("-> create rendering: end");

        Ok(())
    }

    pub fn render(&mut self) -> Result<VkCommandBuffer> {
        if self.rfactor_data.is_none() {
            // self.rfactor_data = RFactorData::new(
            //     self.device(),
            //     self.rendering
            //         .as_mut()
            //         .unwrap()
            //         .single_color_pipeline()
            //         .descriptor_layout(),
            // )
            // .ok();
        }

        // check twice for rfactor data, because of borrowing rules
        if let Some(rfactor) = &mut self.rfactor_data {
            rfactor.update()?;
        }

        let objects = match &self.rfactor_data {
            Some(rfactor) => rfactor.objects(),
            None => Vec::new(),
        };

        let swapchain = self.rendering.as_ref().unwrap().swapchain().clone();

        self.rendering.as_mut().unwrap().render(swapchain, &objects)
    }
}