use crate::texture::{DitherTextures, FlowmapTexture};
use std::num::NonZeroU64;

use super::types::Uniforms;
use super::Renderer;

impl Renderer
{
    pub(super) fn create_bind_group_from_parts(
        device: &wgpu::Device,
        layout: &wgpu::BindGroupLayout,
        uniform_buffer: &wgpu::Buffer,
        shadow_map_view: &wgpu::TextureView,
        shadow_map_sampler: &wgpu::Sampler,
        dither_textures: &DitherTextures,
        flowmap_texture: &FlowmapTexture,
        blue_noise_view: &wgpu::TextureView,
        blue_noise_sampler: &wgpu::Sampler,
        snow_light_view: &wgpu::TextureView,
        snow_light_sampler: &wgpu::Sampler,
    ) -> wgpu::BindGroup
    {
        device.create_bind_group(&wgpu::BindGroupDescriptor {
            label: Some("Bind Group"),
            layout,
            entries: &[
                wgpu::BindGroupEntry {
                    binding: 0,
                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {
                        buffer: uniform_buffer,
                        offset: 0,
                        size: NonZeroU64::new(std::mem::size_of::<Uniforms>() as u64),
                    }),
                },
                wgpu::BindGroupEntry {
                    binding: 1,
                    resource: wgpu::BindingResource::TextureView(shadow_map_view),
                },
                wgpu::BindGroupEntry {
                    binding: 2,
                    resource: wgpu::BindingResource::Sampler(shadow_map_sampler),
                },
                wgpu::BindGroupEntry {
                    binding: 3,
                    resource: wgpu::BindingResource::TextureView(&dither_textures.view),
                },
                wgpu::BindGroupEntry {
                    binding: 4,
                    resource: wgpu::BindingResource::Sampler(&dither_textures.sampler),
                },
                wgpu::BindGroupEntry {
                    binding: 5,
                    resource: wgpu::BindingResource::TextureView(&flowmap_texture.view),
                },
                wgpu::BindGroupEntry {
                    binding: 6,
                    resource: wgpu::BindingResource::Sampler(&flowmap_texture.sampler),
                },
                wgpu::BindGroupEntry {
                    binding: 7,
                    resource: wgpu::BindingResource::TextureView(blue_noise_view),
                },
                wgpu::BindGroupEntry {
                    binding: 8,
                    resource: wgpu::BindingResource::Sampler(blue_noise_sampler),
                },
                wgpu::BindGroupEntry {
                    binding: 9,
                    resource: wgpu::BindingResource::TextureView(snow_light_view),
                },
                wgpu::BindGroupEntry {
                    binding: 10,
                    resource: wgpu::BindingResource::Sampler(snow_light_sampler),
                },
            ],
        })
    }

    pub(super) fn rebuild_bind_group_with_snow_light(&mut self)
    {
        let dither_textures = self
            .dither_textures
            .as_ref()
            .expect("Dither textures required");
        let flowmap_texture = self
            .flowmap_texture
            .as_ref()
            .expect("Flowmap texture required");

        let snow_light_sampler = self.device.create_sampler(&wgpu::SamplerDescriptor {
            label: Some("Snow Light Sampler"),
            address_mode_u: wgpu::AddressMode::ClampToEdge,
            address_mode_v: wgpu::AddressMode::ClampToEdge,
            mag_filter: wgpu::FilterMode::Linear,
            min_filter: wgpu::FilterMode::Linear,
            ..Default::default()
        });

        let snow_light_view = self
            .snow_light_accumulation
            .as_ref()
            .map(|s| s.read_view())
            .unwrap_or(&self.dummy_snow_light_view);

        self.bind_group = Self::create_bind_group_from_parts(
            &self.device,
            &self.bind_group_layout,
            &self.uniform_buffer,
            &self.shadow_map_view,
            &self.shadow_map_sampler,
            dither_textures,
            flowmap_texture,
            &self.blue_noise_view,
            &self.blue_noise_sampler,
            snow_light_view,
            &snow_light_sampler,
        );
    }
}
