/// A texture view which can be targeted by draw calls in the command buffer, and then presented to the surface texture.
pub struct Frame{
	surface_texture:wgpu::SurfaceTexture,
	view:wgpu::TextureView,
}
impl Frame{
	pub const fn view(&self)->&wgpu::TextureView{
		&self.view
	}
	pub fn present(self){
		self.surface_texture.present();
	}
}

#[derive(Debug)]
pub enum FrameError{
	Skip,
	DeviceLost,
}
impl core::fmt::Display for FrameError{
	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
		write!(f,"{self:?}")
	}
}
impl core::error::Error for FrameError{}

/// A render surface configuration, containing information such as resolution and pixel format
pub struct Surface<'window>{
	surface:wgpu::Surface<'window>,
	config:wgpu::SurfaceConfiguration,
}

impl<'window> Surface<'window>{
	pub(crate) fn new(
		surface:wgpu::Surface<'window>,
		config:wgpu::SurfaceConfiguration,
	)->Self{
		Self{surface,config}
	}
	#[must_use]
	pub fn new_frame(&self,device:&wgpu::Device)->Result<Frame,FrameError>{
		let frame=loop{
			match self.surface.get_current_texture(){
				wgpu::CurrentSurfaceTexture::Success(surface_texture)=>break surface_texture,
				// Suboptimal -> surface_texture must be dropped and surface reconfigured
				wgpu::CurrentSurfaceTexture::Suboptimal(_)
				|wgpu::CurrentSurfaceTexture::Outdated=>{},
				wgpu::CurrentSurfaceTexture::Timeout
				|wgpu::CurrentSurfaceTexture::Occluded=>return Err(FrameError::Skip),
				wgpu::CurrentSurfaceTexture::Lost=>return Err(FrameError::DeviceLost),
				wgpu::CurrentSurfaceTexture::Validation=>unreachable!(),
			};
			self.surface.configure(device,&self.config);
		};
		let view=frame.texture.create_view(&wgpu::TextureViewDescriptor{
			format:Some(self.config.view_formats[0]),
			..wgpu::TextureViewDescriptor::default()
		});
		Ok(Frame{
			surface_texture:frame,
			view,
		})
	}
	pub const fn size(&self)->glam::UVec2{
		glam::uvec2(self.config.width,self.config.height)
	}
	pub fn view_format(&self)->wgpu::TextureFormat{
		self.config.view_formats[0]
	}
	pub fn configure(&mut self,device:&wgpu::Device,size:glam::UVec2){
		self.config.width=size.x.max(1);
		self.config.height=size.y.max(1);
		self.surface.configure(device,&self.config);
	}
}
