use egui::{Context};
use egui_wgpu::Renderer;
use egui_winit::{EventResponse, State};
use wgpu::{CommandEncoder, Operations, RenderPassDescriptor, TextureView};
use winit::{event::WindowEvent, window::{Theme, Window}};

use crate::wgpuctx::WgpuCtx;


pub struct EguiCtx {
    state: State,
    renderer: Renderer,
    context: Context,
    ready: bool
}

impl EguiCtx
{
    pub fn new(
        window: &winit::window::Window,
        wgpuctx: &WgpuCtx)
    -> Self {
        let ctx = egui::Context::default();

        let viewport_id = ctx.viewport_id();
        let state = egui_winit::State::new(
            ctx.clone(),
            viewport_id,
            window,
            Some(window.scale_factor() as _),
            Some(Theme::Light),
            None);

        let renderer = Renderer::new(
            wgpuctx.device(),
            wgpuctx.surface_config().format,
            egui_wgpu::RendererOptions {
                depth_stencil_format: None,
                msaa_samples: 1,
                ..Default::default()
            }
        );

        Self {
            context: ctx,
            state: state,
            renderer: renderer,
            ready: false
        }
    }

    pub fn context(&self) -> &Context
    { self.state.egui_ctx() }

    pub fn window_event(
        &mut self,
        window: &Window,
        event: &WindowEvent)
    -> EventResponse
    {
        self.state.on_window_event(window, event)
    }

    pub fn prepare(
        &mut self,
        window: &Window)
    {
        let raw_input = self.state.take_egui_input(window);
        self.context().begin_pass(raw_input);
        self.ready = true;
    }

    pub fn present(
        &mut self,
        window: &Window,
        wgpuctx: &WgpuCtx,
        encoder: &mut CommandEncoder,
        view: &TextureView)

    {
        if !self.ready {
            return;
        }
        self.ready = false;

        let full_output = self.context().end_pass();
        self.state.handle_platform_output(window, full_output.platform_output);

        let jobs = self.context().tessellate(
            full_output.shapes,
            full_output.pixels_per_point
            );
        
        let screen_descriptor = {
            let view_size = view.texture().size();
            let (width, height) = (view_size.width, view_size.height);
            egui_wgpu::ScreenDescriptor {
                size_in_pixels: [width, height],
                pixels_per_point: full_output.pixels_per_point
            }
        };

        for (id, image_delta) in full_output.textures_delta.set {
            self.renderer.update_texture(wgpuctx.device(), wgpuctx.queue(), id, &image_delta);
        }

        self.renderer.update_buffers(
            wgpuctx.device(),
            wgpuctx.queue(),
            encoder,
            &jobs,
            &screen_descriptor
        );
        
        {
        let render_pass = encoder.begin_render_pass(&RenderPassDescriptor {
            label: Some("EguiCtx render pass"),
            color_attachments: &[Some(wgpu::RenderPassColorAttachment {
                view: view,
                resolve_target: None,
                ops: Operations {
                    load: wgpu::LoadOp::Load,
                    store: wgpu::StoreOp::Store
                },
                depth_slice: None
            })],
            depth_stencil_attachment: None,
            timestamp_writes: None,
            occlusion_query_set: None,
            multiview_mask: None
        });

        self.renderer.render(
            &mut render_pass.forget_lifetime(), 
            &jobs, 
            &screen_descriptor
            );
        }

        for id in &full_output.textures_delta.free {
            self.renderer.free_texture(id);
        }
    }
}
