//! Shared HDR render-to-texture helpers for editor viewport panels.

use bevy::prelude::*;
use bevy::render::render_resource::{Extent3d, TextureFormat};

/// Offscreen render target displayed by the primary editor viewport.
#[derive(Debug, Clone)]
pub struct ViewportTarget {
    pub image: Handle<Image>,
}

/// Current primary viewport render target, if the panel has a valid size.
#[derive(Resource, Default, Debug, Clone)]
pub struct ViewportRenderTarget(pub Option<ViewportTarget>);

/// Allocates or resizes the HDR offscreen color target when the panel size changes.
///
/// The asset identity remains stable across ordinary panel resizing. Besides avoiding needless
/// camera and bind-group churn, this prevents Egui's strong image registration from retaining one
/// full-resolution HDR target for every splitter movement.
pub fn ensure_hdr_panel_target(
    physical_size: UVec2,
    last_size: &mut Option<UVec2>,
    current: Option<&Handle<Image>>,
    images: &mut Assets<Image>,
) -> Option<Handle<Image>> {
    if *last_size == Some(physical_size) {
        return None;
    }
    *last_size = Some(physical_size);

    if let Some(current) = current {
        if let Some(mut image) = images.get_mut(current) {
            image.resize(Extent3d {
                width: physical_size.x,
                height: physical_size.y,
                depth_or_array_layers: 1,
            });
            return None;
        }
    }

    Some(images.add(Image::new_target_texture(
        physical_size.x,
        physical_size.y,
        TextureFormat::Rgba16Float,
        None,
    )))
}

/// Standard HDR format for editor panel render targets.
pub const PANEL_TARGET_FORMAT: TextureFormat = TextureFormat::Rgba16Float;

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn repeated_panel_resize_reuses_one_hdr_image_asset() {
        let mut images = Assets::<Image>::default();
        let mut last_size = None;
        let initial =
            ensure_hdr_panel_target(UVec2::new(1920, 1080), &mut last_size, None, &mut images)
                .expect("first size allocates the viewport target");
        let initial_id = initial.id();

        for width in [1600, 1280, 900, 1280, 1600, 1920] {
            assert!(
                ensure_hdr_panel_target(
                    UVec2::new(width, 1080),
                    &mut last_size,
                    Some(&initial),
                    &mut images,
                )
                .is_none(),
                "resize should mutate the existing image"
            );
            assert_eq!(initial.id(), initial_id);
            assert_eq!(
                images.get(&initial).expect("target remains live").width(),
                width
            );
            assert_eq!(images.len(), 1);
        }
    }
}
