//! Asset Library pane - browse and manage project assets
//!
//! Displays all clips in the document organized by category:
//! - Vector Clips (animations)
//! - Video Clips (imported video files)
//! - Audio Clips (sampled audio and MIDI)
//! - Image Assets (static images)

use eframe::egui;
use lightningbeam_core::clip::{AudioClipType, VectorClip};
use lightningbeam_core::document::Document;
use lightningbeam_core::layer::AnyLayer;
use lightningbeam_core::shape::ShapeColor;
use std::collections::{HashMap, HashSet};
use uuid::Uuid;

use super::{DragClipType, DraggingAsset, NodePath, PaneRenderer, SharedPaneState};
use crate::widgets::ImeTextField;

/// Derive min/max peak pairs from raw audio samples for thumbnail rendering.
/// Downsamples to `num_peaks` (min, max) pairs by scanning chunks of samples.
fn peaks_from_raw_audio(
    raw: &(Vec<f32>, u32, u32), // (samples, sample_rate, channels)
    num_peaks: usize,
) -> Vec<(f32, f32)> {
    let (samples, _sr, channels) = raw;
    let ch = (*channels as usize).max(1);
    let total_frames = samples.len() / ch;
    if total_frames == 0 || num_peaks == 0 {
        return vec![];
    }
    let frames_per_peak = (total_frames as f64 / num_peaks as f64).max(1.0);
    let mut peaks = Vec::with_capacity(num_peaks);
    for i in 0..num_peaks {
        let start = (i as f64 * frames_per_peak) as usize;
        let end = (((i + 1) as f64 * frames_per_peak) as usize).min(total_frames);
        let mut min_val = f32::MAX;
        let mut max_val = f32::MIN;
        for frame in start..end {
            // Mix all channels together for the thumbnail
            let mut sample = 0.0f32;
            for c in 0..ch {
                sample += samples[frame * ch + c];
            }
            sample /= ch as f32;
            min_val = min_val.min(sample);
            max_val = max_val.max(sample);
        }
        if min_val <= max_val {
            peaks.push((min_val, max_val));
        }
    }
    peaks
}

// Thumbnail constants
const THUMBNAIL_SIZE: u32 = 64;
const THUMBNAIL_PREVIEW_SECONDS: f64 = 10.0;

// Layout constants
const SEARCH_BAR_HEIGHT: f32 = 30.0;
const CATEGORY_TAB_HEIGHT: f32 = 28.0;
const BREADCRUMB_HEIGHT: f32 = 24.0;
const ITEM_HEIGHT: f32 = 40.0;
#[allow(dead_code)]
const ITEM_PADDING: f32 = 4.0;
const LIST_THUMBNAIL_SIZE: f32 = 32.0;
const GRID_ITEM_SIZE: f32 = 80.0;
const GRID_SPACING: f32 = 8.0;

/// View mode for the asset library
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum AssetViewMode {
    #[default]
    List,
    Grid,
}

/// Cache for thumbnail textures
pub struct ThumbnailCache {
    /// Cached egui textures keyed by asset UUID
    textures: HashMap<Uuid, egui::TextureHandle>,
    /// Track which assets need regeneration
    dirty: HashSet<Uuid>,
}

impl Default for ThumbnailCache {
    fn default() -> Self {
        Self::new()
    }
}

impl ThumbnailCache {
    pub fn new() -> Self {
        Self {
            textures: HashMap::new(),
            dirty: HashSet::new(),
        }
    }

    /// Get a cached thumbnail or create one using the provided generator
    pub fn get_or_create<F>(
        &mut self,
        ctx: &egui::Context,
        asset_id: Uuid,
        generator: F,
    ) -> Option<&egui::TextureHandle>
    where
        F: FnOnce() -> Option<Vec<u8>>,
    {
        // Check if we need to regenerate
        if self.dirty.contains(&asset_id) {
            self.textures.remove(&asset_id);
            self.dirty.remove(&asset_id);
        }

        // Return cached texture if available
        if self.textures.contains_key(&asset_id) {
            return self.textures.get(&asset_id);
        }

        // Generate new thumbnail
        if let Some(rgba_data) = generator() {
            let color_image = egui::ColorImage::from_rgba_unmultiplied(
                [THUMBNAIL_SIZE as usize, THUMBNAIL_SIZE as usize],
                &rgba_data,
            );
            let texture = ctx.load_texture(
                format!("thumbnail_{}", asset_id),
                color_image,
                egui::TextureOptions::LINEAR,
            );
            self.textures.insert(asset_id, texture);
            return self.textures.get(&asset_id);
        }

        None
    }

    /// Check if a thumbnail is already cached (and not dirty)
    #[allow(dead_code)]
    pub fn has(&self, asset_id: &Uuid) -> bool {
        self.textures.contains_key(asset_id) && !self.dirty.contains(asset_id)
    }

    /// Mark an asset's thumbnail as needing regeneration
    pub fn invalidate(&mut self, asset_id: &Uuid) {
        self.dirty.insert(*asset_id);
    }

}

// ============================================================================
// Thumbnail Generation Functions
// ============================================================================

/// Generate a 64x64 RGBA thumbnail for an image asset
fn generate_image_thumbnail(asset: &lightningbeam_core::clip::ImageAsset) -> Option<Vec<u8>> {
    let data = asset.data.as_ref()?;

    // Decode the image
    let img = image::load_from_memory(data).ok()?;

    // Resize to thumbnail size using Lanczos3 filter for quality
    let thumbnail = img.resize_exact(
        THUMBNAIL_SIZE,
        THUMBNAIL_SIZE,
        image::imageops::FilterType::Lanczos3,
    );

    // Convert to RGBA8
    Some(thumbnail.to_rgba8().into_raw())
}

/// Generate a placeholder thumbnail with a solid color and optional icon indication
fn generate_placeholder_thumbnail(category: AssetCategory, bg_alpha: u8) -> Vec<u8> {
    let size = THUMBNAIL_SIZE as usize;
    let mut rgba = vec![0u8; size * size * 4];

    // Get category color for the placeholder
    let color = category.color();

    // Fill with semi-transparent background
    for pixel in rgba.chunks_mut(4) {
        pixel[0] = 40;
        pixel[1] = 40;
        pixel[2] = 40;
        pixel[3] = bg_alpha;
    }

    // Draw a simple icon/indicator in the center based on category
    let center = size / 2;
    let icon_size = size / 3;

    match category {
        AssetCategory::Video => {
            // Draw a play triangle
            for y in 0..icon_size {
                let row_width = (y * icon_size / icon_size).max(1);
                for x in 0..row_width {
                    let px = center - icon_size / 4 + x;
                    let py = center - icon_size / 2 + y;
                    if px < size && py < size {
                        let idx = (py * size + px) * 4;
                        rgba[idx] = color.r();
                        rgba[idx + 1] = color.g();
                        rgba[idx + 2] = color.b();
                        rgba[idx + 3] = 255;
                    }
                }
            }
        }
        _ => {
            // Draw a simple rectangle
            let half = icon_size / 2;
            for y in (center - half)..(center + half) {
                for x in (center - half)..(center + half) {
                    if x < size && y < size {
                        let idx = (y * size + x) * 4;
                        rgba[idx] = color.r();
                        rgba[idx + 1] = color.g();
                        rgba[idx + 2] = color.b();
                        rgba[idx + 3] = 200;
                    }
                }
            }
        }
    }

    rgba
}

/// Helper function to fill a thumbnail buffer with a background color
fn fill_thumbnail_background(rgba: &mut [u8], color: egui::Color32) {
    for pixel in rgba.chunks_mut(4) {
        pixel[0] = color.r();
        pixel[1] = color.g();
        pixel[2] = color.b();
        pixel[3] = color.a();
    }
}

/// Helper function to draw a rectangle on the thumbnail buffer
fn draw_thumbnail_rect(
    rgba: &mut [u8],
    width: usize,
    x: usize,
    y: usize,
    w: usize,
    h: usize,
    color: egui::Color32,
) {
    for dy in 0..h {
        for dx in 0..w {
            let px = x + dx;
            let py = y + dy;
            if px < width && py < width {
                let idx = (py * width + px) * 4;
                if idx + 3 < rgba.len() {
                    rgba[idx] = color.r();
                    rgba[idx + 1] = color.g();
                    rgba[idx + 2] = color.b();
                    rgba[idx + 3] = color.a();
                }
            }
        }
    }
}

/// Generate a waveform thumbnail for sampled audio
/// Shows the first THUMBNAIL_PREVIEW_SECONDS of audio to avoid solid blobs for long clips
fn generate_waveform_thumbnail(
    waveform_peaks: &[(f32, f32)], // (min, max) pairs
    bg_color: egui::Color32,
    wave_color: egui::Color32,
) -> Vec<u8> {
    let size = THUMBNAIL_SIZE as usize;
    let mut rgba = vec![0u8; size * size * 4];

    // Fill background
    fill_thumbnail_background(&mut rgba, bg_color);

    // Draw waveform
    let center_y = size / 2;
    let _num_peaks = waveform_peaks.len().min(size);

    for (x, &(min_val, max_val)) in waveform_peaks.iter().take(size).enumerate() {
        // Scale peaks to pixel range (center ± half height)
        let min_y = (center_y as f32 + min_val * center_y as f32) as usize;
        let max_y = (center_y as f32 + max_val * center_y as f32) as usize;

        let y_start = min_y.min(max_y).min(size - 1);
        let y_end = min_y.max(max_y).min(size - 1);

        for y in y_start..=y_end {
            let idx = (y * size + x) * 4;
            if idx + 3 < rgba.len() {
                rgba[idx] = wave_color.r();
                rgba[idx + 1] = wave_color.g();
                rgba[idx + 2] = wave_color.b();
                rgba[idx + 3] = 255;
            }
        }
    }

    rgba
}

/// Generate a video thumbnail by decoding the first frame
/// Returns a 64x64 RGBA thumbnail with letterboxing to maintain aspect ratio
fn generate_video_thumbnail(
    clip_id: &uuid::Uuid,
    video_manager: &std::sync::Arc<std::sync::Mutex<lightningbeam_core::video::VideoManager>>,
) -> Option<Vec<u8>> {
    // Get a frame from the video (at 1 second to skip potential black intros)
    let timestamp = 1.0;

    let frame = {
        let mut video_mgr = video_manager.lock().ok()?;
        video_mgr.get_frame(clip_id, timestamp)?
    };

    let src_width = frame.width as usize;
    let src_height = frame.height as usize;
    let dst_size = THUMBNAIL_SIZE as usize;

    // Calculate letterboxing dimensions to maintain aspect ratio
    let src_aspect = src_width as f32 / src_height as f32;
    let (scaled_width, scaled_height, offset_x, offset_y) = if src_aspect > 1.0 {
        // Wide video - letterbox top and bottom
        let scaled_width = dst_size;
        let scaled_height = (dst_size as f32 / src_aspect) as usize;
        let offset_y = (dst_size - scaled_height) / 2;
        (scaled_width, scaled_height, 0, offset_y)
    } else {
        // Tall video - letterbox left and right
        let scaled_height = dst_size;
        let scaled_width = (dst_size as f32 * src_aspect) as usize;
        let offset_x = (dst_size - scaled_width) / 2;
        (scaled_width, scaled_height, offset_x, 0)
    };

    // Create thumbnail with black letterbox bars
    let mut rgba = vec![0u8; dst_size * dst_size * 4];

    let x_ratio = src_width as f32 / scaled_width as f32;
    let y_ratio = src_height as f32 / scaled_height as f32;

    // Fill the scaled region
    for dst_y in 0..scaled_height {
        for dst_x in 0..scaled_width {
            let src_x = (dst_x as f32 * x_ratio) as usize;
            let src_y = (dst_y as f32 * y_ratio) as usize;
            let src_idx = (src_y * src_width + src_x) * 4;

            let final_x = dst_x + offset_x;
            let final_y = dst_y + offset_y;
            let dst_idx = (final_y * dst_size + final_x) * 4;

            // Copy RGBA bytes
            if src_idx + 3 < frame.rgba_data.len() && dst_idx + 3 < rgba.len() {
                rgba[dst_idx] = frame.rgba_data[src_idx];
                rgba[dst_idx + 1] = frame.rgba_data[src_idx + 1];
                rgba[dst_idx + 2] = frame.rgba_data[src_idx + 2];
                rgba[dst_idx + 3] = frame.rgba_data[src_idx + 3];
            }
        }
    }

    Some(rgba)
}

/// Generate a piano roll thumbnail for MIDI clips
/// Shows notes as horizontal bars with Y position = note % 12 (one octave)
fn generate_midi_thumbnail(
    events: &[(f64, u8, u8, bool)], // (timestamp, note_number, velocity, is_note_on)
    duration: f64,
    bg_color: egui::Color32,
    note_color: egui::Color32,
) -> Vec<u8> {
    let size = THUMBNAIL_SIZE as usize;
    let mut rgba = vec![0u8; size * size * 4];

    // Fill background
    fill_thumbnail_background(&mut rgba, bg_color);

    // Limit to first 10 seconds
    let preview_duration = duration.min(THUMBNAIL_PREVIEW_SECONDS);
    if preview_duration <= 0.0 {
        return rgba;
    }

    // Draw note events
    for &(timestamp, note_number, _velocity, is_note_on) in events {
        if !is_note_on || timestamp > preview_duration {
            continue;
        }

        let x = ((timestamp / preview_duration) * size as f64) as usize;

        // Note position: modulo 12 (one octave), mapped to full height
        // Note 0 (C) at bottom, Note 11 (B) at top
        let note_in_octave = note_number % 12;
        let y = size - 1 - (note_in_octave as usize * size / 12);

        // Draw a small rectangle for the note
        draw_thumbnail_rect(&mut rgba, size, x.min(size - 2), y.saturating_sub(2), 2, 4, note_color);
    }

    rgba
}

/// Generate a 64x64 RGBA thumbnail for a vector clip
/// Renders frame 0 of the clip using tiny-skia for software rendering
fn generate_vector_thumbnail(clip: &VectorClip, bg_color: egui::Color32) -> Vec<u8> {
    use kurbo::PathEl;
    use tiny_skia::{Paint, PathBuilder, Pixmap, Transform as TsTransform};

    let size = THUMBNAIL_SIZE as usize;
    let mut pixmap = Pixmap::new(THUMBNAIL_SIZE, THUMBNAIL_SIZE)
        .unwrap_or_else(|| Pixmap::new(1, 1).unwrap());

    // Fill background
    pixmap.fill(tiny_skia::Color::from_rgba8(
        bg_color.r(),
        bg_color.g(),
        bg_color.b(),
        bg_color.a(),
    ));

    // Calculate scale to fit clip dimensions into thumbnail
    let scale_x = THUMBNAIL_SIZE as f64 / clip.width.max(1.0);
    let scale_y = THUMBNAIL_SIZE as f64 / clip.height.max(1.0);
    let scale = scale_x.min(scale_y) * 0.9; // 90% to leave a small margin

    // Center offset
    let offset_x = (THUMBNAIL_SIZE as f64 - clip.width * scale) / 2.0;
    let offset_y = (THUMBNAIL_SIZE as f64 - clip.height * scale) / 2.0;

    // Iterate through layers and render shapes
    for layer_node in clip.layers.iter() {
        if let AnyLayer::Vector(vector_layer) = &layer_node.data {
            // Render each shape instance
            for shape_instance in &vector_layer.shape_instances {
                if let Some(shape) = vector_layer.shapes.get(&shape_instance.shape_id) {
                    // Get the path (frame 0)
                    let kurbo_path = shape.path();

                    // Convert kurbo BezPath to tiny-skia PathBuilder
                    let mut path_builder = PathBuilder::new();
                    for el in kurbo_path.iter() {
                        match el {
                            PathEl::MoveTo(p) => {
                                let x = (p.x * scale + offset_x) as f32;
                                let y = (p.y * scale + offset_y) as f32;
                                path_builder.move_to(x, y);
                            }
                            PathEl::LineTo(p) => {
                                let x = (p.x * scale + offset_x) as f32;
                                let y = (p.y * scale + offset_y) as f32;
                                path_builder.line_to(x, y);
                            }
                            PathEl::QuadTo(p1, p2) => {
                                let x1 = (p1.x * scale + offset_x) as f32;
                                let y1 = (p1.y * scale + offset_y) as f32;
                                let x2 = (p2.x * scale + offset_x) as f32;
                                let y2 = (p2.y * scale + offset_y) as f32;
                                path_builder.quad_to(x1, y1, x2, y2);
                            }
                            PathEl::CurveTo(p1, p2, p3) => {
                                let x1 = (p1.x * scale + offset_x) as f32;
                                let y1 = (p1.y * scale + offset_y) as f32;
                                let x2 = (p2.x * scale + offset_x) as f32;
                                let y2 = (p2.y * scale + offset_y) as f32;
                                let x3 = (p3.x * scale + offset_x) as f32;
                                let y3 = (p3.y * scale + offset_y) as f32;
                                path_builder.cubic_to(x1, y1, x2, y2, x3, y3);
                            }
                            PathEl::ClosePath => {
                                path_builder.close();
                            }
                        }
                    }

                    if let Some(ts_path) = path_builder.finish() {
                        // Draw fill if present
                        if let Some(fill_color) = &shape.fill_color {
                            let mut paint = Paint::default();
                            paint.set_color(shape_color_to_tiny_skia(fill_color));
                            paint.anti_alias = true;
                            pixmap.fill_path(
                                &ts_path,
                                &paint,
                                tiny_skia::FillRule::Winding,
                                TsTransform::identity(),
                                None,
                            );
                        }

                        // Draw stroke if present
                        if let Some(stroke_color) = &shape.stroke_color {
                            if let Some(stroke_style) = &shape.stroke_style {
                                let mut paint = Paint::default();
                                paint.set_color(shape_color_to_tiny_skia(stroke_color));
                                paint.anti_alias = true;

                                let stroke = tiny_skia::Stroke {
                                    width: (stroke_style.width * scale) as f32,
                                    ..Default::default()
                                };

                                pixmap.stroke_path(
                                    &ts_path,
                                    &paint,
                                    &stroke,
                                    TsTransform::identity(),
                                    None,
                                );
                            }
                        }
                    }
                }
            }
        }
    }

    // Convert to RGBA bytes
    let data = pixmap.data();
    // tiny-skia uses premultiplied RGBA, need to convert to straight alpha for egui
    let mut rgba = Vec::with_capacity(size * size * 4);
    for chunk in data.chunks(4) {
        let a = chunk[3] as f32 / 255.0;
        if a > 0.0 {
            // Unpremultiply
            rgba.push((chunk[0] as f32 / a).min(255.0) as u8);
            rgba.push((chunk[1] as f32 / a).min(255.0) as u8);
            rgba.push((chunk[2] as f32 / a).min(255.0) as u8);
            rgba.push(chunk[3]);
        } else {
            rgba.extend_from_slice(chunk);
        }
    }
    rgba
}

/// Convert ShapeColor to tiny_skia Color
fn shape_color_to_tiny_skia(color: &ShapeColor) -> tiny_skia::Color {
    tiny_skia::Color::from_rgba8(color.r, color.g, color.b, color.a)
}

/// Generate a simple effect thumbnail with a pink gradient
#[allow(dead_code)]
fn generate_effect_thumbnail() -> Vec<u8> {
    let size = THUMBNAIL_SIZE as usize;
    let mut rgba = vec![0u8; size * size * 4];

    // Pink gradient background with "FX" visual indicator
    for y in 0..size {
        for x in 0..size {
            let brightness = 1.0 - (y as f32 / size as f32) * 0.3;
            let idx = (y * size + x) * 4;
            rgba[idx] = (220.0 * brightness) as u8;     // R
            rgba[idx + 1] = (80.0 * brightness) as u8;  // G
            rgba[idx + 2] = (160.0 * brightness) as u8; // B
            rgba[idx + 3] = 200;                         // A
        }
    }

    // Draw a simple "FX" pattern in the center using darker pixels
    let center = size / 2;
    let letter_size = size / 4;

    // Draw "F" - vertical bar
    for y in (center - letter_size)..(center + letter_size) {
        let x = center - letter_size;
        let idx = (y * size + x) * 4;
        rgba[idx] = 255;
        rgba[idx + 1] = 255;
        rgba[idx + 2] = 255;
        rgba[idx + 3] = 255;
    }
    // Draw "F" - top horizontal
    for x in (center - letter_size)..(center - 2) {
        let y = center - letter_size;
        let idx = (y * size + x) * 4;
        rgba[idx] = 255;
        rgba[idx + 1] = 255;
        rgba[idx + 2] = 255;
        rgba[idx + 3] = 255;
    }
    // Draw "F" - middle horizontal
    for x in (center - letter_size)..(center - 4) {
        let y = center;
        let idx = (y * size + x) * 4;
        rgba[idx] = 255;
        rgba[idx + 1] = 255;
        rgba[idx + 2] = 255;
        rgba[idx + 3] = 255;
    }

    // Draw "X" - diagonal lines
    for i in 0..letter_size {
        // Top-left to bottom-right
        let x1 = center + 2 + i;
        let y1 = center - letter_size + i * 2;
        if x1 < size && y1 < size {
            let idx = (y1 * size + x1) * 4;
            rgba[idx] = 255;
            rgba[idx + 1] = 255;
            rgba[idx + 2] = 255;
            rgba[idx + 3] = 255;
        }
        // Top-right to bottom-left
        let x2 = center + letter_size - i;
        let y2 = center - letter_size + i * 2;
        if x2 < size && y2 < size {
            let idx = (y2 * size + x2) * 4;
            rgba[idx] = 255;
            rgba[idx + 1] = 255;
            rgba[idx + 2] = 255;
            rgba[idx + 3] = 255;
        }
    }

    rgba
}

/// Ellipsize a string to fit within a maximum character count
#[allow(dead_code)]
fn ellipsize(s: &str, max_chars: usize) -> String {
    if s.chars().count() <= max_chars {
        s.to_string()
    } else {
        let truncated: String = s.chars().take(max_chars.saturating_sub(3)).collect();
        format!("{}...", truncated)
    }
}

/// Asset category for filtering
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AssetCategory {
    All,
    Vector,
    Video,
    Audio,
    Images,
    Effects,
}

impl AssetCategory {
    pub fn display_name(&self) -> &'static str {
        match self {
            AssetCategory::All => "All",
            AssetCategory::Vector => "Vector",
            AssetCategory::Video => "Video",
            AssetCategory::Audio => "Audio",
            AssetCategory::Images => "Images",
            AssetCategory::Effects => "Effects",
        }
    }

    pub fn all() -> &'static [AssetCategory] {
        &[
            AssetCategory::All,
            AssetCategory::Vector,
            AssetCategory::Video,
            AssetCategory::Audio,
            AssetCategory::Images,
            AssetCategory::Effects,
        ]
    }

    /// Get the color associated with this category
    pub fn color(&self) -> egui::Color32 {
        match self {
            AssetCategory::All => egui::Color32::from_gray(150),
            AssetCategory::Vector => egui::Color32::from_rgb(100, 150, 255), // Blue
            AssetCategory::Video => egui::Color32::from_rgb(255, 150, 100),  // Orange
            AssetCategory::Audio => egui::Color32::from_rgb(100, 255, 150),  // Green
            AssetCategory::Images => egui::Color32::from_rgb(255, 200, 100), // Yellow/Gold
            AssetCategory::Effects => egui::Color32::from_rgb(220, 80, 160), // Pink
        }
    }
}

/// Unified asset entry for display
#[derive(Debug, Clone)]
pub struct AssetEntry {
    pub id: Uuid,
    pub name: String,
    pub category: AssetCategory,
    /// More specific clip type for drag-and-drop compatibility
    pub drag_clip_type: DragClipType,
    pub duration: f64,
    pub dimensions: Option<(f64, f64)>,
    pub extra_info: String,
    /// True for built-in effects from the registry (not editable/deletable)
    pub is_builtin: bool,
    /// Folder this asset belongs to (None = root)
    pub folder_id: Option<Uuid>,
}

/// Folder entry for display
#[derive(Debug, Clone)]
pub struct FolderEntry {
    pub id: Uuid,
    pub name: String,
    #[allow(dead_code)]
    pub category: AssetCategory,
    pub item_count: usize,
}

/// Library item - either a folder or an asset
#[derive(Debug, Clone)]
pub enum LibraryItem {
    Folder(FolderEntry),
    Asset(AssetEntry),
}

impl LibraryItem {
    #[allow(dead_code)]
    pub fn id(&self) -> Uuid {
        match self {
            LibraryItem::Folder(f) => f.id,
            LibraryItem::Asset(a) => a.id,
        }
    }

    pub fn name(&self) -> &str {
        match self {
            LibraryItem::Folder(f) => &f.name,
            LibraryItem::Asset(a) => &a.name,
        }
    }
}

/// Pending delete confirmation state
#[derive(Debug, Clone)]
struct PendingDelete {
    asset_id: Uuid,
    asset_name: String,
    category: AssetCategory,
    in_use: bool,
}

/// Inline rename editing state
#[derive(Debug, Clone)]
struct RenameState {
    asset_id: Uuid,
    category: AssetCategory,
    edit_text: String,
}

/// Inline folder rename editing state
#[derive(Debug, Clone)]
struct FolderRenameState {
    folder_id: Uuid,
    category: AssetCategory,
    edit_text: String,
}

/// Context menu state with position
#[derive(Debug, Clone)]
struct ContextMenuState {
    asset_id: Uuid,
    position: egui::Pos2,
}

#[derive(Debug, Clone)]
struct FolderContextMenuState {
    folder_id: Uuid,
    position: egui::Pos2,
}

pub struct AssetLibraryPane {
    /// Current search filter text
    search_filter: String,

    /// Currently selected category tab
    selected_category: AssetCategory,

    /// Currently selected asset ID (for future drag-to-timeline)
    selected_asset: Option<Uuid>,

    /// Context menu state with position (for assets)
    context_menu: Option<ContextMenuState>,

    /// Folder context menu state (for folders)
    folder_context_menu: Option<FolderContextMenuState>,

    /// Pane context menu position (for background right-click)
    pane_context_menu: Option<egui::Pos2>,

    /// Pending delete confirmation
    pending_delete: Option<PendingDelete>,

    /// Active rename state (for assets)
    rename_state: Option<RenameState>,

    /// Active folder rename state
    folder_rename_state: Option<FolderRenameState>,

    /// Current view mode (list or grid)
    view_mode: AssetViewMode,

    /// Thumbnail texture cache
    thumbnail_cache: ThumbnailCache,

    /// Current folder navigation per category (category index -> current folder ID)
    /// None means at root level
    current_folders: HashMap<u8, Option<Uuid>>,

    /// Set of expanded folder IDs (for tree view - future enhancement)
    #[allow(dead_code)]
    expanded_folders: HashSet<Uuid>,

    /// Cached folder icon texture
    folder_icon: Option<egui::TextureHandle>,
}

// Embedded folder icon SVG
const FOLDER_ICON_SVG: &[u8] = include_bytes!("../../../../src/assets/folder.svg");

impl AssetLibraryPane {
    pub fn new() -> Self {
        Self {
            search_filter: String::new(),
            selected_category: AssetCategory::All,
            selected_asset: None,
            context_menu: None,
            folder_context_menu: None,
            pane_context_menu: None,
            pending_delete: None,
            rename_state: None,
            folder_rename_state: None,
            view_mode: AssetViewMode::default(),
            thumbnail_cache: ThumbnailCache::new(),
            current_folders: HashMap::new(),
            expanded_folders: HashSet::new(),
            folder_icon: None,
        }
    }

    /// Get or load the folder icon texture
    fn get_folder_icon(&mut self, ctx: &egui::Context) -> Option<&egui::TextureHandle> {
        if self.folder_icon.is_none() {
            // Rasterize the embedded SVG
            let render_size = 32; // Render at 32px for list/grid views

            if let Ok(tree) = resvg::usvg::Tree::from_data(FOLDER_ICON_SVG, &resvg::usvg::Options::default()) {
                let pixmap_size = tree.size().to_int_size();
                let scale_x = render_size as f32 / pixmap_size.width() as f32;
                let scale_y = render_size as f32 / pixmap_size.height() as f32;
                let scale = scale_x.min(scale_y);

                if let Some(mut pixmap) = resvg::tiny_skia::Pixmap::new(render_size, render_size) {
                    let transform = resvg::tiny_skia::Transform::from_scale(scale, scale);
                    resvg::render(&tree, transform, &mut pixmap.as_mut());

                    let rgba_data = pixmap.data();
                    let size = [pixmap.width() as usize, pixmap.height() as usize];
                    let color_image = egui::ColorImage::from_rgba_unmultiplied(size, rgba_data);

                    let texture = ctx.load_texture(
                        "folder_icon",
                        color_image,
                        egui::TextureOptions::LINEAR,
                    );

                    self.folder_icon = Some(texture);
                }
            }
        }

        self.folder_icon.as_ref()
    }

    /// Get the current folder for the selected category
    fn get_current_folder(&self) -> Option<Uuid> {
        let category_index = match self.selected_category {
            AssetCategory::All => return None, // All category doesn't have folders
            AssetCategory::Vector => 1,
            AssetCategory::Video => 2,
            AssetCategory::Audio => 3,
            AssetCategory::Images => 4,
            AssetCategory::Effects => 5,
        };

        self.current_folders.get(&category_index).copied().flatten()
    }

    /// Set the current folder for the selected category
    fn set_current_folder(&mut self, folder_id: Option<Uuid>) {
        let category_index = match self.selected_category {
            AssetCategory::All => return, // All category doesn't have folders
            AssetCategory::Vector => 1,
            AssetCategory::Video => 2,
            AssetCategory::Audio => 3,
            AssetCategory::Images => 4,
            AssetCategory::Effects => 5,
        };

        self.current_folders.insert(category_index, folder_id);
    }

    /// Convert UI AssetCategory to core AssetCategory
    fn to_core_category(category: AssetCategory) -> Option<lightningbeam_core::document::AssetCategory> {
        match category {
            AssetCategory::All => None,
            AssetCategory::Vector => Some(lightningbeam_core::document::AssetCategory::Vector),
            AssetCategory::Video => Some(lightningbeam_core::document::AssetCategory::Video),
            AssetCategory::Audio => Some(lightningbeam_core::document::AssetCategory::Audio),
            AssetCategory::Images => Some(lightningbeam_core::document::AssetCategory::Images),
            AssetCategory::Effects => Some(lightningbeam_core::document::AssetCategory::Effects),
        }
    }

    /// Convert DragClipType to core AssetCategory
    fn drag_clip_type_to_core_category(clip_type: DragClipType) -> lightningbeam_core::document::AssetCategory {
        match clip_type {
            DragClipType::Vector => lightningbeam_core::document::AssetCategory::Vector,
            DragClipType::Video => lightningbeam_core::document::AssetCategory::Video,
            DragClipType::AudioSampled | DragClipType::AudioMidi => lightningbeam_core::document::AssetCategory::Audio,
            DragClipType::Image => lightningbeam_core::document::AssetCategory::Images,
            DragClipType::Effect => lightningbeam_core::document::AssetCategory::Effects,
        }
    }

    /// Convert DragClipType to UI AssetCategory
    fn drag_clip_type_to_category(clip_type: DragClipType) -> AssetCategory {
        match clip_type {
            DragClipType::Vector => AssetCategory::Vector,
            DragClipType::Video => AssetCategory::Video,
            DragClipType::AudioSampled | DragClipType::AudioMidi => AssetCategory::Audio,
            DragClipType::Image => AssetCategory::Images,
            DragClipType::Effect => AssetCategory::Effects,
        }
    }

    /// Collect all assets from the document into a unified list
    fn collect_assets(&self, document: &Document) -> Vec<AssetEntry> {
        let mut assets = Vec::new();

        // Collect vector clips
        for (id, clip) in &document.vector_clips {
            assets.push(AssetEntry {
                id: *id,
                name: clip.name.clone(),
                category: AssetCategory::Vector,
                drag_clip_type: DragClipType::Vector,
                duration: clip.duration,
                dimensions: Some((clip.width, clip.height)),
                extra_info: format!("{}x{}", clip.width as u32, clip.height as u32),
                is_builtin: false,
                folder_id: clip.folder_id,
            });
        }

        // Collect video clips
        for (id, clip) in &document.video_clips {
            assets.push(AssetEntry {
                id: *id,
                name: clip.name.clone(),
                category: AssetCategory::Video,
                drag_clip_type: DragClipType::Video,
                duration: clip.duration,
                dimensions: Some((clip.width, clip.height)),
                extra_info: format!("{:.0}fps", clip.frame_rate),
                is_builtin: false,
                folder_id: clip.folder_id,
            });
        }

        // Build set of audio clip IDs that are linked to videos
        let linked_audio_ids: std::collections::HashSet<uuid::Uuid> = document.video_clips.values()
            .filter_map(|video| video.linked_audio_clip_id)
            .collect();

        // Collect audio clips (skip those linked to videos)
        for (id, clip) in &document.audio_clips {
            // Skip if this audio clip is linked to a video
            if linked_audio_ids.contains(id) {
                continue;
            }

            let (extra_info, drag_clip_type) = match &clip.clip_type {
                AudioClipType::Sampled { .. } => ("Sampled".to_string(), DragClipType::AudioSampled),
                AudioClipType::Midi { .. } => ("MIDI".to_string(), DragClipType::AudioMidi),
                AudioClipType::Recording => {
                    // Skip recording-in-progress clips from asset library
                    continue;
                }
            };

            assets.push(AssetEntry {
                id: *id,
                name: clip.name.clone(),
                category: AssetCategory::Audio,
                drag_clip_type,
                duration: clip.duration,
                dimensions: None,
                extra_info,
                is_builtin: false,
                folder_id: clip.folder_id,
            });
        }

        // Collect image assets
        for (id, asset) in &document.image_assets {
            assets.push(AssetEntry {
                id: *id,
                name: asset.name.clone(),
                category: AssetCategory::Images,
                drag_clip_type: DragClipType::Image,
                duration: 0.0, // Images don't have duration
                dimensions: Some((asset.width as f64, asset.height as f64)),
                extra_info: format!("{}x{}", asset.width, asset.height),
                is_builtin: false,
                folder_id: asset.folder_id,
            });
        }

        // Collect built-in effects from registry
        for effect_def in lightningbeam_core::effect_registry::EffectRegistry::get_all() {
            assets.push(AssetEntry {
                id: effect_def.id,
                name: effect_def.name.clone(),
                category: AssetCategory::Effects,
                drag_clip_type: DragClipType::Effect,
                duration: 5.0, // Default duration when dropped
                dimensions: None,
                extra_info: format!("{:?}", effect_def.category),
                is_builtin: true, // Built-in from registry
                folder_id: None, // Built-in effects are at root
            });
        }

        // Collect user-edited effects from document (that aren't in registry)
        let registry_ids: HashSet<Uuid> = lightningbeam_core::effect_registry::EffectRegistry::get_all()
            .iter()
            .map(|e| e.id)
            .collect();

        for effect_def in document.effect_definitions.values() {
            if !registry_ids.contains(&effect_def.id) {
                // User-created/modified effect
                assets.push(AssetEntry {
                    id: effect_def.id,
                    name: effect_def.name.clone(),
                    category: AssetCategory::Effects,
                    drag_clip_type: DragClipType::Effect,
                    duration: 5.0,
                    dimensions: None,
                    extra_info: format!("{:?}", effect_def.category),
                    is_builtin: false, // User effect
                    folder_id: effect_def.folder_id,
                });
            }
        }

        // Sort alphabetically by name
        assets.sort_by(|a, b| a.name.to_lowercase().cmp(&b.name.to_lowercase()));

        assets
    }

    /// Collect folders and assets for the current view (folder-aware)
    fn collect_items(&self, document: &Document) -> Vec<LibraryItem> {
        let mut items = Vec::new();

        // For "All" category, return all assets except built-in effects (no folders)
        if self.selected_category == AssetCategory::All {
            let assets = self.collect_assets(document);
            return assets.into_iter()
                .filter(|asset| {
                    // Exclude built-in effects from "All" category
                    !(asset.category == AssetCategory::Effects && asset.is_builtin)
                })
                .map(LibraryItem::Asset)
                .collect();
        }

        // Get the core category and folder tree
        let Some(core_category) = Self::to_core_category(self.selected_category) else {
            return items;
        };

        let folder_tree = document.get_folder_tree(core_category);
        let current_folder = self.get_current_folder();

        // Collect folders at the current level
        let folders = if let Some(parent_id) = current_folder {
            folder_tree.children_of(&parent_id)
        } else {
            folder_tree.root_folders()
        };

        for folder in folders {
            // Count items in this folder (subfolders + assets)
            let subfolder_count = folder_tree.children_of(&folder.id).len();

            // Count assets in this folder
            let asset_count = match self.selected_category {
                AssetCategory::Vector => document
                    .vector_clips
                    .values()
                    .filter(|c| c.folder_id == Some(folder.id))
                    .count(),
                AssetCategory::Video => document
                    .video_clips
                    .values()
                    .filter(|c| c.folder_id == Some(folder.id))
                    .count(),
                AssetCategory::Audio => document
                    .audio_clips
                    .values()
                    .filter(|c| c.folder_id == Some(folder.id))
                    .count(),
                AssetCategory::Images => document
                    .image_assets
                    .values()
                    .filter(|a| a.folder_id == Some(folder.id))
                    .count(),
                AssetCategory::Effects => document
                    .effect_definitions
                    .values()
                    .filter(|e| e.folder_id == Some(folder.id))
                    .count(),
                AssetCategory::All => 0,
            };

            items.push(LibraryItem::Folder(FolderEntry {
                id: folder.id,
                name: folder.name.clone(),
                category: self.selected_category,
                item_count: subfolder_count + asset_count,
            }));
        }

        // Collect assets at the current level
        match self.selected_category {
            AssetCategory::Vector => {
                for (id, clip) in &document.vector_clips {
                    if clip.folder_id == current_folder {
                        items.push(LibraryItem::Asset(AssetEntry {
                            id: *id,
                            name: clip.name.clone(),
                            category: AssetCategory::Vector,
                            drag_clip_type: DragClipType::Vector,
                            duration: clip.duration,
                            dimensions: Some((clip.width, clip.height)),
                            extra_info: format!("{}x{}", clip.width as u32, clip.height as u32),
                            is_builtin: false,
                            folder_id: clip.folder_id,
                        }));
                    }
                }
            }
            AssetCategory::Video => {
                for (id, clip) in &document.video_clips {
                    if clip.folder_id == current_folder {
                        items.push(LibraryItem::Asset(AssetEntry {
                            id: *id,
                            name: clip.name.clone(),
                            category: AssetCategory::Video,
                            drag_clip_type: DragClipType::Video,
                            duration: clip.duration,
                            dimensions: Some((clip.width, clip.height)),
                            extra_info: format!("{:.0}fps", clip.frame_rate),
                            is_builtin: false,
                            folder_id: clip.folder_id,
                        }));
                    }
                }
            }
            AssetCategory::Audio => {
                // Build set of linked audio IDs to skip
                let linked_audio_ids: HashSet<Uuid> = document
                    .video_clips
                    .values()
                    .filter_map(|v| v.linked_audio_clip_id)
                    .collect();

                for (id, clip) in &document.audio_clips {
                    if !linked_audio_ids.contains(id) && clip.folder_id == current_folder {
                        let (extra_info, drag_clip_type) = match &clip.clip_type {
                            AudioClipType::Sampled { .. } => {
                                ("Sampled".to_string(), DragClipType::AudioSampled)
                            }
                            AudioClipType::Midi { .. } => {
                                ("MIDI".to_string(), DragClipType::AudioMidi)
                            }
                            AudioClipType::Recording => {
                                // Skip recording-in-progress clips
                                continue;
                            }
                        };

                        items.push(LibraryItem::Asset(AssetEntry {
                            id: *id,
                            name: clip.name.clone(),
                            category: AssetCategory::Audio,
                            drag_clip_type,
                            duration: clip.duration,
                            dimensions: None,
                            extra_info,
                            is_builtin: false,
                            folder_id: clip.folder_id,
                        }));
                    }
                }
            }
            AssetCategory::Images => {
                for (id, asset) in &document.image_assets {
                    if asset.folder_id == current_folder {
                        items.push(LibraryItem::Asset(AssetEntry {
                            id: *id,
                            name: asset.name.clone(),
                            category: AssetCategory::Images,
                            drag_clip_type: DragClipType::Image,
                            duration: 0.0,
                            dimensions: Some((asset.width as f64, asset.height as f64)),
                            extra_info: format!("{}x{}", asset.width, asset.height),
                            is_builtin: false,
                            folder_id: asset.folder_id,
                        }));
                    }
                }
            }
            AssetCategory::Effects => {
                // Built-in effects always appear at root level
                if current_folder.is_none() {
                    for effect_def in lightningbeam_core::effect_registry::EffectRegistry::get_all() {
                        items.push(LibraryItem::Asset(AssetEntry {
                            id: effect_def.id,
                            name: effect_def.name.clone(),
                            category: AssetCategory::Effects,
                            drag_clip_type: DragClipType::Effect,
                            duration: 0.0,
                            dimensions: None,
                            extra_info: format!("{:?}", effect_def.category),
                            is_builtin: true,
                            folder_id: None, // Built-in effects are always at root
                        }));
                    }
                }

                // User effects
                for (id, effect) in &document.effect_definitions {
                    if effect.folder_id == current_folder {
                        items.push(LibraryItem::Asset(AssetEntry {
                            id: *id,
                            name: effect.name.clone(),
                            category: AssetCategory::Effects,
                            drag_clip_type: DragClipType::Effect,
                            duration: 0.0,
                            dimensions: None,
                            extra_info: format!("{:?}", effect.category),
                            is_builtin: false,
                            folder_id: effect.folder_id,
                        }));
                    }
                }
            }
            AssetCategory::All => {
                // Already handled above
            }
        }

        // Sort: folders first (alphabetically), then assets (alphabetically)
        items.sort_by(|a, b| {
            match (a, b) {
                (LibraryItem::Folder(f1), LibraryItem::Folder(f2)) => {
                    f1.name.to_lowercase().cmp(&f2.name.to_lowercase())
                }
                (LibraryItem::Asset(a1), LibraryItem::Asset(a2)) => {
                    a1.name.to_lowercase().cmp(&a2.name.to_lowercase())
                }
                (LibraryItem::Folder(_), LibraryItem::Asset(_)) => std::cmp::Ordering::Less,
                (LibraryItem::Asset(_), LibraryItem::Folder(_)) => std::cmp::Ordering::Greater,
            }
        });

        items
    }

    /// Filter assets based on current category and search text
    #[allow(dead_code)]
    fn filter_assets<'a>(&self, assets: &'a [AssetEntry]) -> Vec<&'a AssetEntry> {
        let search_lower = self.search_filter.to_lowercase();

        assets
            .iter()
            .filter(|asset| {
                // Category filter
                let category_matches = if self.selected_category == AssetCategory::All {
                    // "All" tab: show everything EXCEPT built-in effects
                    // (built-in effects only appear in the Effects tab)
                    !(asset.category == AssetCategory::Effects && asset.is_builtin)
                } else {
                    asset.category == self.selected_category
                };

                // Search filter
                let search_matches =
                    search_lower.is_empty() || asset.name.to_lowercase().contains(&search_lower);

                category_matches && search_matches
            })
            .collect()
    }

    /// Check if an asset is currently in use (has clip instances on layers)
    fn is_asset_in_use(document: &Document, asset_id: Uuid, category: AssetCategory) -> bool {
        // Check all layers for clip instances referencing this asset
        for layer in &document.root.children {
            match layer {
                lightningbeam_core::layer::AnyLayer::Vector(vl) => {
                    if category == AssetCategory::Vector {
                        for instance in &vl.clip_instances {
                            if instance.clip_id == asset_id {
                                return true;
                            }
                        }
                    }
                }
                lightningbeam_core::layer::AnyLayer::Video(vl) => {
                    if category == AssetCategory::Video {
                        for instance in &vl.clip_instances {
                            if instance.clip_id == asset_id {
                                return true;
                            }
                        }
                    }
                }
                lightningbeam_core::layer::AnyLayer::Audio(al) => {
                    if category == AssetCategory::Audio {
                        for instance in &al.clip_instances {
                            if instance.clip_id == asset_id {
                                return true;
                            }
                        }
                    }
                }
                lightningbeam_core::layer::AnyLayer::Effect(el) => {
                    if category == AssetCategory::Effects {
                        for instance in &el.clip_instances {
                            if instance.clip_id == asset_id {
                                return true;
                            }
                        }
                    }
                }
            }
        }
        false
    }

    /// Delete an asset from the document
    fn delete_asset(document: &mut Document, asset_id: Uuid, category: AssetCategory) {
        match category {
            AssetCategory::Vector => {
                document.remove_vector_clip(&asset_id);
            }
            AssetCategory::Video => {
                document.remove_video_clip(&asset_id);
            }
            AssetCategory::Audio => {
                document.remove_audio_clip(&asset_id);
            }
            AssetCategory::Images => {
                document.remove_image_asset(&asset_id);
            }
            AssetCategory::Effects => {
                document.effect_definitions.remove(&asset_id);
            }
            AssetCategory::All => {} // Not a real category for deletion
        }
    }

    /// Rename an asset in the document
    fn rename_asset(document: &mut Document, asset_id: Uuid, category: AssetCategory, new_name: &str) {
        match category {
            AssetCategory::Vector => {
                if let Some(clip) = document.get_vector_clip_mut(&asset_id) {
                    clip.name = new_name.to_string();
                }
            }
            AssetCategory::Video => {
                if let Some(clip) = document.get_video_clip_mut(&asset_id) {
                    clip.name = new_name.to_string();
                }
            }
            AssetCategory::Audio => {
                if let Some(clip) = document.get_audio_clip_mut(&asset_id) {
                    clip.name = new_name.to_string();
                }
            }
            AssetCategory::Images => {
                if let Some(asset) = document.get_image_asset_mut(&asset_id) {
                    asset.name = new_name.to_string();
                }
            }
            AssetCategory::Effects => {
                if let Some(effect) = document.effect_definitions.get_mut(&asset_id) {
                    effect.name = new_name.to_string();
                }
            }
            AssetCategory::All => {} // Not a real category for renaming
        }
    }

    /// Render the search bar at the top with view toggle buttons
    fn render_search_bar(&mut self, ui: &mut egui::Ui, rect: egui::Rect, shared: &SharedPaneState) {
        let search_rect =
            egui::Rect::from_min_size(rect.min, egui::vec2(rect.width(), SEARCH_BAR_HEIGHT));

        // Background
        let bg_style = shared.theme.style(".panel-header", ui.ctx());
        let bg_color = bg_style
            .background_color
            .unwrap_or(egui::Color32::from_rgb(30, 30, 30));
        ui.painter().rect_filled(search_rect, 0.0, bg_color);

        // View toggle buttons on the right (list and grid icons)
        let button_size = 20.0;
        let button_padding = 4.0;
        let buttons_width = button_size * 2.0 + button_padding * 3.0;

        // Grid view button (rightmost)
        let grid_button_rect = egui::Rect::from_min_size(
            egui::pos2(
                search_rect.max.x - button_size - button_padding,
                search_rect.min.y + (SEARCH_BAR_HEIGHT - button_size) / 2.0,
            ),
            egui::vec2(button_size, button_size),
        );

        // List view button
        let list_button_rect = egui::Rect::from_min_size(
            egui::pos2(
                grid_button_rect.min.x - button_size - button_padding,
                search_rect.min.y + (SEARCH_BAR_HEIGHT - button_size) / 2.0,
            ),
            egui::vec2(button_size, button_size),
        );

        // Draw and handle list button
        let list_selected = self.view_mode == AssetViewMode::List;
        let list_response = ui.allocate_rect(list_button_rect, egui::Sense::click());
        let list_bg = if list_selected {
            egui::Color32::from_rgb(70, 90, 110)
        } else if list_response.hovered() {
            egui::Color32::from_rgb(50, 50, 50)
        } else {
            egui::Color32::TRANSPARENT
        };
        ui.painter().rect_filled(list_button_rect, 3.0, list_bg);

        // Draw list icon (three horizontal lines)
        let list_icon_color = if list_selected {
            egui::Color32::WHITE
        } else {
            egui::Color32::from_gray(150)
        };
        let line_spacing = 4.0;
        let line_width = 10.0;
        let line_x = list_button_rect.center().x - line_width / 2.0;
        for i in 0..3 {
            let line_y = list_button_rect.center().y - line_spacing + (i as f32 * line_spacing);
            ui.painter().line_segment(
                [
                    egui::pos2(line_x, line_y),
                    egui::pos2(line_x + line_width, line_y),
                ],
                egui::Stroke::new(1.5, list_icon_color),
            );
        }

        if list_response.clicked() {
            self.view_mode = AssetViewMode::List;
        }

        // Draw and handle grid button
        let grid_selected = self.view_mode == AssetViewMode::Grid;
        let grid_response = ui.allocate_rect(grid_button_rect, egui::Sense::click());
        let grid_bg = if grid_selected {
            egui::Color32::from_rgb(70, 90, 110)
        } else if grid_response.hovered() {
            egui::Color32::from_rgb(50, 50, 50)
        } else {
            egui::Color32::TRANSPARENT
        };
        ui.painter().rect_filled(grid_button_rect, 3.0, grid_bg);

        // Draw grid icon (2x2 squares)
        let grid_icon_color = if grid_selected {
            egui::Color32::WHITE
        } else {
            egui::Color32::from_gray(150)
        };
        let square_size = 4.0;
        let square_gap = 2.0;
        let grid_start_x = grid_button_rect.center().x - square_size - square_gap / 2.0;
        let grid_start_y = grid_button_rect.center().y - square_size - square_gap / 2.0;
        for row in 0..2 {
            for col in 0..2 {
                let square_rect = egui::Rect::from_min_size(
                    egui::pos2(
                        grid_start_x + col as f32 * (square_size + square_gap),
                        grid_start_y + row as f32 * (square_size + square_gap),
                    ),
                    egui::vec2(square_size, square_size),
                );
                ui.painter().rect_filled(square_rect, 1.0, grid_icon_color);
            }
        }

        if grid_response.clicked() {
            self.view_mode = AssetViewMode::Grid;
        }

        // Label position
        let label_pos = search_rect.min + egui::vec2(8.0, (SEARCH_BAR_HEIGHT - 14.0) / 2.0);
        ui.painter().text(
            label_pos,
            egui::Align2::LEFT_TOP,
            "Search:",
            egui::FontId::proportional(14.0),
            egui::Color32::from_gray(180),
        );

        // Text field using IME-safe widget (leave room for view toggle buttons)
        let text_edit_rect = egui::Rect::from_min_size(
            search_rect.min + egui::vec2(65.0, 4.0),
            egui::vec2(search_rect.width() - 75.0 - buttons_width, SEARCH_BAR_HEIGHT - 8.0),
        );

        let mut child_ui = ui.new_child(egui::UiBuilder::new().max_rect(text_edit_rect));
        ImeTextField::new(&mut self.search_filter)
            .placeholder("Filter assets...")
            .desired_width(text_edit_rect.width())
            .show(&mut child_ui);
    }

    /// Render category tabs
    fn render_category_tabs(
        &mut self,
        ui: &mut egui::Ui,
        rect: egui::Rect,
        shared: &SharedPaneState,
    ) {
        let tabs_rect =
            egui::Rect::from_min_size(rect.min, egui::vec2(rect.width(), CATEGORY_TAB_HEIGHT));

        // Background
        let bg_style = shared.theme.style(".panel-content", ui.ctx());
        let bg_color = bg_style
            .background_color
            .unwrap_or(egui::Color32::from_rgb(40, 40, 40));
        ui.painter().rect_filled(tabs_rect, 0.0, bg_color);

        // Tab buttons
        let tab_width = tabs_rect.width() / AssetCategory::all().len() as f32;

        for (i, category) in AssetCategory::all().iter().enumerate() {
            let tab_rect = egui::Rect::from_min_size(
                tabs_rect.min + egui::vec2(i as f32 * tab_width, 0.0),
                egui::vec2(tab_width, CATEGORY_TAB_HEIGHT),
            );

            let is_selected = self.selected_category == *category;

            // Tab background
            let tab_bg = if is_selected {
                egui::Color32::from_rgb(60, 60, 60)
            } else {
                egui::Color32::TRANSPARENT
            };
            ui.painter().rect_filled(tab_rect, 0.0, tab_bg);

            // Handle click
            let response = ui.allocate_rect(tab_rect, egui::Sense::click());
            if response.clicked() {
                self.selected_category = *category;
            }

            // Category color indicator
            let indicator_color = category.color();

            let text_color = if is_selected {
                indicator_color
            } else {
                egui::Color32::from_gray(150)
            };

            ui.painter().text(
                tab_rect.center(),
                egui::Align2::CENTER_CENTER,
                category.display_name(),
                egui::FontId::proportional(12.0),
                text_color,
            );

            // Underline for selected tab
            if is_selected {
                ui.painter().line_segment(
                    [
                        egui::pos2(tab_rect.min.x + 4.0, tab_rect.max.y - 2.0),
                        egui::pos2(tab_rect.max.x - 4.0, tab_rect.max.y - 2.0),
                    ],
                    egui::Stroke::new(2.0, indicator_color),
                );
            }
        }
    }

    /// Render breadcrumb navigation showing current folder path
    fn render_breadcrumbs(
        &mut self,
        ui: &mut egui::Ui,
        rect: egui::Rect,
        document: &Document,
        shared: &SharedPaneState,
    ) {
        // Only show breadcrumbs for specific categories (not "All")
        if self.selected_category == AssetCategory::All {
            return;
        }

        let Some(core_category) = Self::to_core_category(self.selected_category) else {
            return;
        };

        // Background
        let bg_style = shared.theme.style(".panel-header", ui.ctx());
        let bg_color = bg_style
            .background_color
            .unwrap_or(egui::Color32::from_rgb(25, 25, 25));
        ui.painter().rect_filled(rect, 0.0, bg_color);

        // Get folder tree and build path
        let folder_tree = document.get_folder_tree(core_category);
        let current_folder = self.get_current_folder();

        // Build path: category name -> folder1 -> folder2 -> ...
        let mut path_items = vec![self.selected_category.display_name().to_string()];
        let mut path_folder_ids = Vec::new();

        if let Some(folder_id) = current_folder {
            let folder_path_ids = folder_tree.path_to_folder(&folder_id);
            for fid in &folder_path_ids {
                if let Some(folder) = folder_tree.folders.get(fid) {
                    path_items.push(folder.name.clone());
                    path_folder_ids.push(*fid);
                }
            }
        }

        // Render breadcrumb items
        let mut x_offset = rect.min.x + 8.0;
        let y_center = rect.min.y + BREADCRUMB_HEIGHT / 2.0;

        for (i, item_name) in path_items.iter().enumerate() {
            let is_last = i == path_items.len() - 1;

            // Calculate text size
            let font_id = egui::FontId::proportional(12.0);
            let text_galley = ui.painter().layout_no_wrap(
                item_name.clone(),
                font_id.clone(),
                egui::Color32::WHITE,
            );

            let text_width = text_galley.size().x;
            let item_rect = egui::Rect::from_min_size(
                egui::pos2(x_offset, rect.min.y),
                egui::vec2(text_width + 8.0, BREADCRUMB_HEIGHT),
            );

            // Make clickable if not the last item
            let response = ui.allocate_rect(item_rect, egui::Sense::click());

            // Determine color based on state
            let text_color = if is_last {
                egui::Color32::WHITE
            } else if response.hovered() {
                egui::Color32::from_rgb(100, 150, 255)
            } else {
                egui::Color32::from_rgb(150, 150, 150)
            };

            // Draw text
            ui.painter().text(
                egui::pos2(x_offset, y_center),
                egui::Align2::LEFT_CENTER,
                item_name,
                font_id,
                text_color,
            );

            // Handle click to navigate up the hierarchy
            if response.clicked() && !is_last {
                if i == 0 {
                    // Clicked on category root - go to root
                    self.set_current_folder(None);
                } else {
                    // Clicked on a folder - navigate to it
                    // Get the folder at this index (i-1 because category is at 0)
                    if i - 1 < path_folder_ids.len() {
                        self.set_current_folder(Some(path_folder_ids[i - 1]));
                    }
                }
            }

            x_offset += text_width + 8.0;

            // Draw separator (>) if not last
            if !is_last {
                ui.painter().text(
                    egui::pos2(x_offset, y_center),
                    egui::Align2::LEFT_CENTER,
                    ">",
                    egui::FontId::proportional(12.0),
                    egui::Color32::from_rgb(100, 100, 100),
                );
                x_offset += 16.0;
            }
        }
    }

    /// Render a section header for effect categories
    #[allow(dead_code)] // Part of List/Grid view rendering subsystem, not yet wired
    fn render_section_header(ui: &mut egui::Ui, label: &str, color: egui::Color32) {
        ui.add_space(4.0);
        let (header_rect, _) = ui.allocate_exact_size(
            egui::vec2(ui.available_width(), 20.0),
            egui::Sense::hover(),
        );
        ui.painter().text(
            header_rect.min + egui::vec2(8.0, 2.0),
            egui::Align2::LEFT_TOP,
            label,
            egui::FontId::proportional(11.0),
            color,
        );
        ui.add_space(2.0);
    }

    /// Render a grid of asset items
    #[allow(clippy::too_many_arguments, dead_code)]
    fn render_grid_items(
        &mut self,
        ui: &mut egui::Ui,
        assets: &[&AssetEntry],
        columns: usize,
        item_height: f32,
        content_width: f32,
        shared: &mut SharedPaneState,
        document: &Document,
        text_color: egui::Color32,
        _secondary_text_color: egui::Color32,
    ) {
        if assets.is_empty() {
            return;
        }

        let rows = (assets.len() + columns - 1) / columns;
        // Grid height: matches the positioning formula used below
        // Items are at: GRID_SPACING + row * (item_height + GRID_SPACING)
        // Last item bottom: GRID_SPACING + (rows-1) * (item_height + GRID_SPACING) + item_height
        //                 = GRID_SPACING + rows * item_height + (rows-1) * GRID_SPACING
        //                 = rows * (item_height + GRID_SPACING) + GRID_SPACING - GRID_SPACING (for last row)
        // Simplified: GRID_SPACING + rows * (item_height + GRID_SPACING)
        let grid_height = GRID_SPACING + rows as f32 * (item_height + GRID_SPACING);

        // Reserve space for this grid section
        // We need to use allocate_space to properly advance the cursor by the full height,
        // then calculate the rect ourselves
        let cursor_before = ui.cursor().min;
        let _ = ui.allocate_space(egui::vec2(content_width, grid_height));
        let grid_rect = egui::Rect::from_min_size(cursor_before, egui::vec2(content_width, grid_height));

        for (idx, asset) in assets.iter().enumerate() {
            let col = idx % columns;
            let row = idx / columns;

            let item_x = grid_rect.min.x + GRID_SPACING + col as f32 * (GRID_ITEM_SIZE + GRID_SPACING);
            let item_y = grid_rect.min.y + GRID_SPACING + row as f32 * (item_height + GRID_SPACING);

            let item_rect = egui::Rect::from_min_size(
                egui::pos2(item_x, item_y),
                egui::vec2(GRID_ITEM_SIZE, item_height),
            );

            // Use interact() instead of allocate_rect() because we've already allocated the
            // entire grid space via allocate_exact_size above - allocate_rect would double-count
            let response = ui.interact(item_rect, egui::Id::new(("grid_item", asset.id)), egui::Sense::click_and_drag());

            let is_selected = self.selected_asset == Some(asset.id);
            let is_being_dragged = shared.dragging_asset.as_ref().map(|d| d.clip_id == asset.id).unwrap_or(false);

            // Item background
            let item_bg = if is_being_dragged {
                egui::Color32::from_rgb(80, 100, 120)
            } else if is_selected {
                egui::Color32::from_rgb(60, 80, 100)
            } else if response.hovered() {
                egui::Color32::from_rgb(45, 45, 45)
            } else {
                egui::Color32::from_rgb(35, 35, 35)
            };
            ui.painter().rect_filled(item_rect, 4.0, item_bg);

            // Thumbnail area
            let thumbnail_rect = egui::Rect::from_min_size(
                egui::pos2(
                    item_rect.min.x + (GRID_ITEM_SIZE - THUMBNAIL_SIZE as f32) / 2.0,
                    item_rect.min.y + 4.0,
                ),
                egui::vec2(THUMBNAIL_SIZE as f32, THUMBNAIL_SIZE as f32),
            );

            // Generate and display thumbnail
            let asset_id = asset.id;
            let asset_category = asset.category;
            let ctx = ui.ctx().clone();

            let prefetched_waveform: Option<Vec<(f32, f32)>> =
                if asset_category == AssetCategory::Audio && !self.thumbnail_cache.has(&asset_id) {
                    if let Some(clip) = document.audio_clips.get(&asset_id) {
                        if let AudioClipType::Sampled { audio_pool_index } = &clip.clip_type {
                            shared.raw_audio_cache.get(audio_pool_index)
                                .map(|raw| peaks_from_raw_audio(raw, THUMBNAIL_SIZE as usize))
                        } else {
                            None
                        }
                    } else {
                        None
                    }
                } else {
                    None
                };

            let texture = self.thumbnail_cache.get_or_create(&ctx, asset_id, || {
                match asset_category {
                    AssetCategory::Images => document.image_assets.get(&asset_id).and_then(generate_image_thumbnail),
                    AssetCategory::Vector => {
                        let bg_color = egui::Color32::from_rgba_unmultiplied(40, 40, 40, 200);
                        document.vector_clips.get(&asset_id).map(|clip| generate_vector_thumbnail(clip, bg_color))
                    }
                    AssetCategory::Video => generate_video_thumbnail(&asset_id, &shared.video_manager)
                        .or_else(|| Some(generate_placeholder_thumbnail(AssetCategory::Video, 200))),
                    AssetCategory::Audio => {
                        if let Some(clip) = document.audio_clips.get(&asset_id) {
                            let bg_color = egui::Color32::from_rgba_unmultiplied(40, 40, 40, 200);
                            match &clip.clip_type {
                                AudioClipType::Sampled { .. } => {
                                    let wave_color = egui::Color32::from_rgb(100, 200, 100);
                                    if let Some(ref peaks) = prefetched_waveform {
                                        Some(generate_waveform_thumbnail(peaks, bg_color, wave_color))
                                    } else {
                                        Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                    }
                                }
                                AudioClipType::Midi { midi_clip_id } => {
                                    let note_color = egui::Color32::from_rgb(100, 200, 100);
                                    if let Some(events) = shared.midi_event_cache.get(midi_clip_id) {
                                        Some(generate_midi_thumbnail(events, clip.duration, bg_color, note_color))
                                    } else {
                                        Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                    }
                                }
                                AudioClipType::Recording => {
                                    // Recording in progress - show placeholder
                                    Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                }
                            }
                        } else {
                            Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                        }
                    }
                    AssetCategory::Effects => {
                        // Use GPU-rendered effect thumbnail if available
                        if let Some(rgba) = shared.effect_thumbnail_cache.get(&asset_id) {
                            Some(rgba.clone())
                        } else {
                            // Request GPU thumbnail generation
                            shared.effect_thumbnail_requests.push(asset_id);
                            // Return None to avoid caching placeholder - will retry next frame
                            None
                        }
                    }
                    AssetCategory::All => None,
                }
            });

            // Either use cached texture or render placeholder directly for effects
            // Use painter().image() instead of ui.put() to avoid affecting the cursor
            if let Some(texture) = texture {
                ui.painter().image(
                    texture.id(),
                    thumbnail_rect,
                    egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)),
                    egui::Color32::WHITE,
                );
            } else if asset_category == AssetCategory::Effects {
                // Render effect placeholder directly (not cached) until GPU thumbnail ready
                let placeholder_rgba = generate_effect_thumbnail();
                let color_image = egui::ColorImage::from_rgba_unmultiplied(
                    [THUMBNAIL_SIZE as usize, THUMBNAIL_SIZE as usize],
                    &placeholder_rgba,
                );
                let texture = ctx.load_texture(
                    format!("effect_placeholder_{}", asset_id),
                    color_image,
                    egui::TextureOptions::LINEAR,
                );
                ui.painter().image(
                    texture.id(),
                    thumbnail_rect,
                    egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)),
                    egui::Color32::WHITE,
                );
            }

            // Category color indicator
            let indicator_rect = egui::Rect::from_min_size(
                egui::pos2(thumbnail_rect.min.x, thumbnail_rect.max.y - 3.0),
                egui::vec2(THUMBNAIL_SIZE as f32, 3.0),
            );
            ui.painter().rect_filled(indicator_rect, 0.0, asset.category.color());

            // Asset name
            let name_display = ellipsize(&asset.name, 12);
            ui.painter().text(
                egui::pos2(item_rect.center().x, thumbnail_rect.max.y + 8.0),
                egui::Align2::CENTER_TOP,
                &name_display,
                egui::FontId::proportional(10.0),
                text_color,
            );

            // Handle interactions
            if response.clicked() {
                self.selected_asset = Some(asset.id);
            }

            if response.secondary_clicked() {
                if let Some(pos) = ui.ctx().pointer_interact_pos() {
                    self.context_menu = Some(ContextMenuState { asset_id: asset.id, position: pos });
                }
            }

            if response.double_clicked() {
                if asset.category == AssetCategory::Effects {
                    *shared.effect_to_load = Some(asset.id);
                } else if !asset.is_builtin {
                    self.rename_state = Some(RenameState {
                        asset_id: asset.id,
                        category: asset.category,
                        edit_text: asset.name.clone(),
                    });
                }
            }

            if response.drag_started() {
                let linked_audio_clip_id = if asset.drag_clip_type == DragClipType::Video {
                    document.video_clips.get(&asset.id).and_then(|video| video.linked_audio_clip_id)
                } else {
                    None
                };
                *shared.dragging_asset = Some(DraggingAsset {
                    clip_id: asset.id,
                    clip_type: asset.drag_clip_type,
                    name: asset.name.clone(),
                    duration: asset.duration,
                    dimensions: asset.dimensions,
                    linked_audio_clip_id,
                });
            }
        }
    }

    /// Render items (folders and assets) based on current view mode
    fn render_items(
        &mut self,
        ui: &mut egui::Ui,
        rect: egui::Rect,
        path: &NodePath,
        shared: &mut SharedPaneState,
        items: &[&LibraryItem],
        document: &Document,
    ) {
        match self.view_mode {
            AssetViewMode::List => {
                self.render_items_list_view(ui, rect, path, shared, items, document);
            }
            AssetViewMode::Grid => {
                self.render_items_grid_view(ui, rect, path, shared, items, document);
            }
        }
    }

    /// Render items in list view (folders + assets)
    fn render_items_list_view(
        &mut self,
        ui: &mut egui::Ui,
        rect: egui::Rect,
        _path: &NodePath,
        shared: &mut SharedPaneState,
        items: &[&LibraryItem],
        document: &Document,
    ) {
        // Load folder icon if needed
        let folder_icon = self.get_folder_icon(ui.ctx()).cloned();

        let _scroll_area = egui::ScrollArea::vertical()
            .id_salt("asset_library_scroll")
            .show_viewport(ui, |ui, viewport| {
                ui.set_min_width(rect.width());

                for item in items {
                    match item {
                        LibraryItem::Folder(folder) => {
                            // Render folder item
                            let item_rect = egui::Rect::from_min_size(
                                egui::pos2(rect.min.x, ui.cursor().top()),
                                egui::vec2(rect.width(), ITEM_HEIGHT),
                            );

                            if viewport.intersects(item_rect) {
                                let response = ui.allocate_rect(item_rect, egui::Sense::click());

                                // Check if an asset is being dragged and matches this folder's category
                                let is_valid_drop_target = shared.dragging_asset.as_ref().map(|drag| {
                                    let drag_category = Self::drag_clip_type_to_category(drag.clip_type);
                                    drag_category == self.selected_category
                                }).unwrap_or(false);

                                let is_drop_hover = is_valid_drop_target && response.hovered();

                                // Background
                                let bg_color = if is_drop_hover {
                                    // Highlight as drop target
                                    egui::Color32::from_rgb(60, 100, 140)
                                } else if response.hovered() {
                                    egui::Color32::from_rgb(50, 50, 50)
                                } else {
                                    egui::Color32::from_rgb(35, 35, 35)
                                };
                                ui.painter().rect_filled(item_rect, 0.0, bg_color);

                                // Draw drop target indicator border
                                if is_drop_hover {
                                    ui.painter().rect_stroke(
                                        item_rect,
                                        0.0,
                                        egui::Stroke::new(2.0, egui::Color32::from_rgb(100, 180, 255)),
                                        egui::StrokeKind::Middle,
                                    );
                                }

                                // Folder icon
                                if let Some(ref icon) = folder_icon {
                                    let icon_size = LIST_THUMBNAIL_SIZE;
                                    let icon_rect = egui::Rect::from_min_size(
                                        item_rect.min + egui::vec2(4.0, (ITEM_HEIGHT - icon_size) / 2.0),
                                        egui::vec2(icon_size, icon_size),
                                    );
                                    ui.painter().image(
                                        icon.id(),
                                        icon_rect,
                                        egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)),
                                        egui::Color32::WHITE,
                                    );
                                }

                                // Folder name (or inline edit field)
                                let is_renaming = self.folder_rename_state.as_ref().map(|s| s.folder_id == folder.id).unwrap_or(false);

                                if is_renaming {
                                    // Inline rename text field
                                    let name_rect = egui::Rect::from_min_size(
                                        item_rect.min + egui::vec2(LIST_THUMBNAIL_SIZE + 8.0, (ITEM_HEIGHT - 22.0) / 2.0),
                                        egui::vec2(200.0, 22.0),
                                    );

                                    if let Some(ref mut state) = self.folder_rename_state {
                                        let mut child_ui = ui.new_child(egui::UiBuilder::new().max_rect(name_rect));
                                        ImeTextField::new(&mut state.edit_text)
                                            .font_size(13.0)
                                            .desired_width(name_rect.width())
                                            .request_focus()
                                            .show(&mut child_ui);
                                    }
                                } else {
                                    ui.painter().text(
                                        item_rect.min + egui::vec2(LIST_THUMBNAIL_SIZE + 12.0, ITEM_HEIGHT / 2.0),
                                        egui::Align2::LEFT_CENTER,
                                        &folder.name,
                                        egui::FontId::proportional(13.0),
                                        egui::Color32::WHITE,
                                    );
                                }

                                // Item count
                                let count_text = format!("{} items", folder.item_count);
                                ui.painter().text(
                                    item_rect.max - egui::vec2(8.0, ITEM_HEIGHT / 2.0),
                                    egui::Align2::RIGHT_CENTER,
                                    count_text,
                                    egui::FontId::proportional(11.0),
                                    egui::Color32::from_rgb(150, 150, 150),
                                );

                                // Handle drop: move asset to folder
                                if is_drop_hover && ui.input(|i| i.pointer.any_released()) {
                                    if let Some(ref drag) = shared.dragging_asset.clone() {
                                        let core_category = Self::drag_clip_type_to_core_category(drag.clip_type);
                                        let action = lightningbeam_core::actions::MoveAssetToFolderAction::new(
                                            core_category,
                                            drag.clip_id,
                                            Some(folder.id),
                                        );
                                        let _ = shared.action_executor.execute(Box::new(action));
                                        *shared.dragging_asset = None;
                                    }
                                }

                                // Handle double-click to navigate into folder
                                if response.double_clicked() {
                                    self.set_current_folder(Some(folder.id));
                                }

                                // Handle right-click for context menu
                                if response.secondary_clicked() {
                                    self.folder_context_menu = Some(FolderContextMenuState {
                                        folder_id: folder.id,
                                        position: ui.ctx().pointer_interact_pos().unwrap_or(egui::pos2(0.0, 0.0)),
                                    });
                                }
                            } else {
                                ui.allocate_space(egui::vec2(rect.width(), ITEM_HEIGHT));
                            }
                        }
                        LibraryItem::Asset(asset) => {
                            // Render asset item
                            let item_rect = egui::Rect::from_min_size(
                                egui::pos2(rect.min.x, ui.cursor().top()),
                                egui::vec2(rect.width(), ITEM_HEIGHT),
                            );

                            if viewport.intersects(item_rect) {
                                self.render_single_asset_list(ui, asset, item_rect, document, shared);
                            } else {
                                ui.allocate_space(egui::vec2(rect.width(), ITEM_HEIGHT));
                            }
                        }
                    }
                }
            });
    }

    /// Render items in grid view (folders + assets)
    fn render_items_grid_view(
        &mut self,
        ui: &mut egui::Ui,
        rect: egui::Rect,
        path: &NodePath,
        shared: &mut SharedPaneState,
        items: &[&LibraryItem],
        document: &Document,
    ) {
        // Load folder icon if needed
        let folder_icon = self.get_folder_icon(ui.ctx()).cloned();

        ui.scope_builder(egui::UiBuilder::new().max_rect(rect), |ui| {
            egui::ScrollArea::vertical()
                .id_salt(("asset_library_grid_scroll", path))
                .auto_shrink([false, false])
                .show(ui, |ui| {
                    ui.set_min_width(rect.width() - 16.0); // Account for scrollbar

                let items_per_row =
                    ((rect.width() - GRID_SPACING) / (GRID_ITEM_SIZE + GRID_SPACING)).floor() as usize;
                let items_per_row = items_per_row.max(1);

                for row_start in (0..items.len()).step_by(items_per_row) {
                    ui.horizontal(|ui| {
                        for i in 0..items_per_row {
                            let index = row_start + i;
                            if index >= items.len() {
                                break;
                            }

                            let item = items[index];
                            match item {
                                LibraryItem::Folder(folder) => {
                                    // Render folder in grid (with space for name and count below)
                                    let (rect, response) = ui.allocate_exact_size(
                                        egui::vec2(GRID_ITEM_SIZE, GRID_ITEM_SIZE + 20.0),
                                        egui::Sense::click(),
                                    );

                                    // Check if an asset is being dragged and matches this folder's category
                                    let is_valid_drop_target = shared.dragging_asset.as_ref().map(|drag| {
                                        let drag_category = Self::drag_clip_type_to_category(drag.clip_type);
                                        drag_category == self.selected_category
                                    }).unwrap_or(false);

                                    let is_drop_hover = is_valid_drop_target && response.hovered();

                                    // Background
                                    let bg_color = if is_drop_hover {
                                        // Highlight as drop target
                                        egui::Color32::from_rgb(60, 100, 140)
                                    } else if response.hovered() {
                                        egui::Color32::from_rgb(50, 50, 50)
                                    } else {
                                        egui::Color32::from_rgb(35, 35, 35)
                                    };
                                    ui.painter().rect_filled(rect, 4.0, bg_color);

                                    // Draw drop target indicator border
                                    if is_drop_hover {
                                        ui.painter().rect_stroke(
                                            rect,
                                            4.0,
                                            egui::Stroke::new(2.0, egui::Color32::from_rgb(100, 180, 255)),
                                            egui::StrokeKind::Middle,
                                        );
                                    }

                                    // Folder icon (centered)
                                    if let Some(ref icon) = folder_icon {
                                        let icon_size = 48.0;
                                        let icon_rect = egui::Rect::from_center_size(
                                            rect.center() - egui::vec2(0.0, 8.0),
                                            egui::vec2(icon_size, icon_size),
                                        );
                                        ui.painter().image(
                                            icon.id(),
                                            icon_rect,
                                            egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)),
                                            egui::Color32::WHITE,
                                        );
                                    }

                                    // Folder name (bottom, truncated)
                                    let name = if folder.name.len() > 12 {
                                        format!("{}...", &folder.name[..9])
                                    } else {
                                        folder.name.clone()
                                    };
                                    ui.painter().text(
                                        rect.center() + egui::vec2(0.0, 20.0),
                                        egui::Align2::CENTER_CENTER,
                                        name,
                                        egui::FontId::proportional(10.0),
                                        egui::Color32::WHITE,
                                    );

                                    // Item count
                                    ui.painter().text(
                                        rect.center() + egui::vec2(0.0, 32.0),
                                        egui::Align2::CENTER_CENTER,
                                        format!("{} items", folder.item_count),
                                        egui::FontId::proportional(9.0),
                                        egui::Color32::from_rgb(150, 150, 150),
                                    );

                                    // Handle drop: move asset to folder
                                    if is_drop_hover && ui.input(|i| i.pointer.any_released()) {
                                        if let Some(ref drag) = shared.dragging_asset.clone() {
                                            let core_category = Self::drag_clip_type_to_core_category(drag.clip_type);
                                            let action = lightningbeam_core::actions::MoveAssetToFolderAction::new(
                                                core_category,
                                                drag.clip_id,
                                                Some(folder.id),
                                            );
                                            let _ = shared.action_executor.execute(Box::new(action));
                                            *shared.dragging_asset = None;
                                        }
                                    }

                                    // Handle double-click to navigate into folder
                                    if response.double_clicked() {
                                        self.set_current_folder(Some(folder.id));
                                    }

                                    // Handle right-click for context menu
                                    if response.secondary_clicked() {
                                        self.folder_context_menu = Some(FolderContextMenuState {
                                            folder_id: folder.id,
                                            position: ui.ctx().pointer_interact_pos().unwrap_or(egui::pos2(0.0, 0.0)),
                                        });
                                    }
                                }
                                LibraryItem::Asset(asset) => {
                                    // Allocate rect for asset grid item (with space for name below)
                                    let (item_rect, _response) = ui.allocate_exact_size(
                                        egui::vec2(GRID_ITEM_SIZE, GRID_ITEM_SIZE + 20.0),
                                        egui::Sense::hover(),
                                    );
                                    self.render_single_asset_grid(ui, asset, item_rect, document, shared);
                                }
                            }
                        }
                    });
                    ui.add_space(GRID_SPACING);
                }
            });
        });
    }

    /// Helper to render a single asset in list view
    fn render_single_asset_list(
        &mut self,
        ui: &mut egui::Ui,
        asset: &AssetEntry,
        item_rect: egui::Rect,
        document: &Document,
        shared: &mut SharedPaneState,
    ) -> egui::Response {
        let response = ui.allocate_rect(item_rect, egui::Sense::click_and_drag());

        let is_selected = self.selected_asset == Some(asset.id);
        let is_being_dragged = shared
            .dragging_asset
            .as_ref()
            .map(|d| d.clip_id == asset.id)
            .unwrap_or(false);

        // Text colors
        let text_color = egui::Color32::from_gray(200);
        let secondary_text_color = egui::Color32::from_gray(120);

        // Item background
        let item_bg = if is_being_dragged {
            egui::Color32::from_rgb(80, 100, 120)
        } else if is_selected {
            egui::Color32::from_rgb(60, 80, 100)
        } else if response.hovered() {
            egui::Color32::from_rgb(45, 45, 45)
        } else {
            egui::Color32::from_rgb(35, 35, 35)
        };
        ui.painter().rect_filled(item_rect, 3.0, item_bg);

        // Category color indicator bar
        let indicator_color = asset.category.color();
        let indicator_rect = egui::Rect::from_min_size(
            item_rect.min,
            egui::vec2(4.0, ITEM_HEIGHT),
        );
        ui.painter().rect_filled(indicator_rect, 0.0, indicator_color);

        // Asset name
        ui.painter().text(
            item_rect.min + egui::vec2(12.0, 8.0),
            egui::Align2::LEFT_TOP,
            &asset.name,
            egui::FontId::proportional(13.0),
            text_color,
        );

        // Metadata line
        let metadata = if asset.category == AssetCategory::Images {
            asset.extra_info.clone()
        } else if let Some((w, h)) = asset.dimensions {
            format!(
                "{:.1}s | {}x{} | {}",
                asset.duration, w as u32, h as u32, asset.extra_info
            )
        } else {
            format!("{:.1}s | {}", asset.duration, asset.extra_info)
        };

        ui.painter().text(
            item_rect.min + egui::vec2(12.0, 24.0),
            egui::Align2::LEFT_TOP,
            &metadata,
            egui::FontId::proportional(10.0),
            secondary_text_color,
        );

        // Thumbnail on the right side
        let thumbnail_rect = egui::Rect::from_min_size(
            egui::pos2(
                item_rect.max.x - LIST_THUMBNAIL_SIZE - 4.0,
                item_rect.min.y + (ITEM_HEIGHT - LIST_THUMBNAIL_SIZE) / 2.0,
            ),
            egui::vec2(LIST_THUMBNAIL_SIZE, LIST_THUMBNAIL_SIZE),
        );

        // Generate and display thumbnail
        let asset_id = asset.id;
        let asset_category = asset.category;
        let ctx = ui.ctx().clone();

        let texture = self.thumbnail_cache.get_or_create(&ctx, asset_id, || {
            match asset_category {
                AssetCategory::Images => {
                    document.image_assets.get(&asset_id)
                        .and_then(generate_image_thumbnail)
                }
                AssetCategory::Vector => {
                    let bg_color = egui::Color32::from_rgba_unmultiplied(40, 40, 40, 200);
                    document.vector_clips.get(&asset_id)
                        .map(|clip| generate_vector_thumbnail(clip, bg_color))
                }
                AssetCategory::Video => {
                    generate_video_thumbnail(&asset_id, &shared.video_manager)
                        .or_else(|| Some(generate_placeholder_thumbnail(AssetCategory::Video, 200)))
                }
                AssetCategory::Audio => {
                    if let Some(clip) = document.audio_clips.get(&asset_id) {
                        let bg_color = egui::Color32::from_rgba_unmultiplied(40, 40, 40, 200);
                        match &clip.clip_type {
                            AudioClipType::Sampled { audio_pool_index } => {
                                let wave_color = egui::Color32::from_rgb(100, 200, 100);
                                let waveform: Option<Vec<(f32, f32)>> = shared.raw_audio_cache.get(audio_pool_index)
                                    .map(|raw| peaks_from_raw_audio(raw, THUMBNAIL_SIZE as usize));
                                if let Some(ref peaks) = waveform {
                                    Some(generate_waveform_thumbnail(peaks, bg_color, wave_color))
                                } else {
                                    Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                }
                            }
                            AudioClipType::Midi { midi_clip_id } => {
                                let note_color = egui::Color32::from_rgb(100, 200, 100);
                                if let Some(events) = shared.midi_event_cache.get(midi_clip_id) {
                                    Some(generate_midi_thumbnail(events, clip.duration, bg_color, note_color))
                                } else {
                                    Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                }
                            }
                            AudioClipType::Recording => {
                                Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                            }
                        }
                    } else {
                        None
                    }
                }
                AssetCategory::Effects => {
                    if let Some(rgba) = shared.effect_thumbnail_cache.get(&asset_id) {
                        Some(rgba.clone())
                    } else {
                        shared.effect_thumbnail_requests.push(asset_id);
                        None
                    }
                }
                AssetCategory::All => None,
            }
        });

        if let Some(texture) = texture {
            ui.painter().image(
                texture.id(),
                thumbnail_rect,
                egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)),
                egui::Color32::WHITE,
            );
        }

        // Handle drag start
        if response.drag_started() {
            let linked_audio_clip_id = if asset_category == AssetCategory::Video {
                document.video_clips.get(&asset_id)
                    .and_then(|clip| clip.linked_audio_clip_id)
            } else {
                None
            };

            *shared.dragging_asset = Some(DraggingAsset {
                clip_type: asset.drag_clip_type,
                clip_id: asset_id,
                name: asset.name.clone(),
                duration: asset.duration,
                dimensions: asset.dimensions,
                linked_audio_clip_id,
            });
        }

        // Handle right-click for context menu
        if response.secondary_clicked() {
            self.context_menu = Some(ContextMenuState {
                asset_id: asset.id,
                position: ui.ctx().pointer_interact_pos().unwrap_or(egui::pos2(0.0, 0.0)),
            });
        }

        // Handle selection
        if response.clicked() {
            self.selected_asset = Some(asset.id);
        }

        response
    }

    /// Helper to render a single asset in grid view
    fn render_single_asset_grid(
        &mut self,
        ui: &mut egui::Ui,
        asset: &AssetEntry,
        rect: egui::Rect,
        document: &Document,
        shared: &mut SharedPaneState,
    ) -> egui::Response {
        let response = ui.interact(rect, egui::Id::new(("grid_asset", asset.id)), egui::Sense::click_and_drag());

        let is_selected = self.selected_asset == Some(asset.id);
        let is_being_dragged = shared
            .dragging_asset
            .as_ref()
            .map(|d| d.clip_id == asset.id)
            .unwrap_or(false);

        // Background
        let bg_color = if is_being_dragged {
            egui::Color32::from_rgb(80, 100, 120)
        } else if is_selected {
            egui::Color32::from_rgb(60, 80, 100)
        } else if response.hovered() {
            egui::Color32::from_rgb(50, 50, 50)
        } else {
            egui::Color32::from_rgb(35, 35, 35)
        };
        ui.painter().rect_filled(rect, 4.0, bg_color);

        // Thumbnail
        let thumbnail_size = 64.0;
        let thumbnail_rect = egui::Rect::from_min_size(
            egui::pos2(
                rect.center().x - thumbnail_size / 2.0,
                rect.min.y + 8.0,
            ),
            egui::vec2(thumbnail_size, thumbnail_size),
        );

        let asset_id = asset.id;
        let asset_category = asset.category;
        let ctx = ui.ctx().clone();

        let texture = self.thumbnail_cache.get_or_create(&ctx, asset_id, || {
            match asset_category {
                AssetCategory::Images => {
                    document.image_assets.get(&asset_id)
                        .and_then(generate_image_thumbnail)
                }
                AssetCategory::Vector => {
                    let bg_color = egui::Color32::from_rgba_unmultiplied(40, 40, 40, 200);
                    document.vector_clips.get(&asset_id)
                        .map(|clip| generate_vector_thumbnail(clip, bg_color))
                }
                AssetCategory::Video => {
                    generate_video_thumbnail(&asset_id, &shared.video_manager)
                        .or_else(|| Some(generate_placeholder_thumbnail(AssetCategory::Video, 200)))
                }
                AssetCategory::Audio => {
                    if let Some(clip) = document.audio_clips.get(&asset_id) {
                        let bg_color = egui::Color32::from_rgba_unmultiplied(40, 40, 40, 200);
                        match &clip.clip_type {
                            AudioClipType::Sampled { audio_pool_index } => {
                                let wave_color = egui::Color32::from_rgb(100, 200, 100);
                                let waveform: Option<Vec<(f32, f32)>> = shared.raw_audio_cache.get(audio_pool_index)
                                    .map(|raw| peaks_from_raw_audio(raw, THUMBNAIL_SIZE as usize));
                                if let Some(ref peaks) = waveform {
                                    Some(generate_waveform_thumbnail(peaks, bg_color, wave_color))
                                } else {
                                    Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                }
                            }
                            AudioClipType::Midi { midi_clip_id } => {
                                let note_color = egui::Color32::from_rgb(100, 200, 100);
                                if let Some(events) = shared.midi_event_cache.get(midi_clip_id) {
                                    Some(generate_midi_thumbnail(events, clip.duration, bg_color, note_color))
                                } else {
                                    Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                }
                            }
                            AudioClipType::Recording => {
                                Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                            }
                        }
                    } else {
                        None
                    }
                }
                AssetCategory::Effects => {
                    if let Some(rgba) = shared.effect_thumbnail_cache.get(&asset_id) {
                        Some(rgba.clone())
                    } else {
                        shared.effect_thumbnail_requests.push(asset_id);
                        None
                    }
                }
                AssetCategory::All => None,
            }
        });

        if let Some(texture) = texture {
            ui.painter().image(
                texture.id(),
                thumbnail_rect,
                egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)),
                egui::Color32::WHITE,
            );
        }

        // Category indicator
        let indicator_rect = egui::Rect::from_min_size(
            egui::pos2(thumbnail_rect.min.x, thumbnail_rect.max.y - 3.0),
            egui::vec2(thumbnail_size, 3.0),
        );
        ui.painter().rect_filled(indicator_rect, 0.0, asset.category.color());

        // Asset name
        let name = if asset.name.len() > 12 {
            format!("{}...", &asset.name[..9])
        } else {
            asset.name.clone()
        };
        ui.painter().text(
            rect.center() + egui::vec2(0.0, 40.0),
            egui::Align2::CENTER_CENTER,
            name,
            egui::FontId::proportional(10.0),
            egui::Color32::WHITE,
        );

        // Handle interactions
        if response.clicked() {
            self.selected_asset = Some(asset.id);
        }

        if response.secondary_clicked() {
            self.context_menu = Some(ContextMenuState {
                asset_id: asset.id,
                position: ui.ctx().pointer_interact_pos().unwrap_or(egui::pos2(0.0, 0.0)),
            });
        }

        if response.drag_started() {
            let linked_audio_clip_id = if asset_category == AssetCategory::Video {
                document.video_clips.get(&asset_id)
                    .and_then(|clip| clip.linked_audio_clip_id)
            } else {
                None
            };

            *shared.dragging_asset = Some(DraggingAsset {
                clip_type: asset.drag_clip_type,
                clip_id: asset_id,
                name: asset.name.clone(),
                duration: asset.duration,
                dimensions: asset.dimensions,
                linked_audio_clip_id,
            });
        }

        response
    }

    /// Render assets based on current view mode
    #[allow(dead_code)]
    fn render_assets(
        &mut self,
        ui: &mut egui::Ui,
        rect: egui::Rect,
        path: &NodePath,
        shared: &mut SharedPaneState,
        assets: &[&AssetEntry],
        document: &Document,
    ) {
        match self.view_mode {
            AssetViewMode::List => {
                self.render_asset_list_view(ui, rect, path, shared, assets, document);
            }
            AssetViewMode::Grid => {
                self.render_asset_grid_view(ui, rect, path, shared, assets, document);
            }
        }
    }

    /// Render the asset list view
    #[allow(dead_code)]
    fn render_asset_list_view(
        &mut self,
        ui: &mut egui::Ui,
        rect: egui::Rect,
        path: &NodePath,
        shared: &mut SharedPaneState,
        assets: &[&AssetEntry],
        document: &Document,
    ) {
        // Background
        let bg_style = shared.theme.style(".panel-content", ui.ctx());
        let bg_color = bg_style
            .background_color
            .unwrap_or(egui::Color32::from_rgb(25, 25, 25));
        ui.painter().rect_filled(rect, 0.0, bg_color);

        // Text colors
        let text_style = shared.theme.style(".text-primary", ui.ctx());
        let text_color = text_style
            .text_color
            .unwrap_or(egui::Color32::from_gray(200));
        let secondary_text_color = egui::Color32::from_gray(120);

        // Show empty state message if no assets
        if assets.is_empty() {
            let message = if !self.search_filter.is_empty() {
                "No assets match your search"
            } else {
                "No assets in this category"
            };

            ui.painter().text(
                rect.center(),
                egui::Align2::CENTER_CENTER,
                message,
                egui::FontId::proportional(14.0),
                secondary_text_color,
            );
            return;
        }

        // Use egui's built-in ScrollArea for scrolling
        let scroll_area_rect = rect;
        ui.scope_builder(egui::UiBuilder::new().max_rect(scroll_area_rect), |ui| {
            egui::ScrollArea::vertical()
                .id_salt(("asset_list_scroll", path))
                .auto_shrink([false, false])
                .show(ui, |ui| {
                    ui.set_min_width(scroll_area_rect.width() - 16.0); // Account for scrollbar

                    // For Effects tab, reorder: built-in first, then custom, with headers
                    let ordered_assets: Vec<&AssetEntry>;
                    let show_effects_sections = self.selected_category == AssetCategory::Effects;

                    let assets_to_render = if show_effects_sections {
                        let builtin: Vec<_> = assets.iter().filter(|a| a.is_builtin).copied().collect();
                        let custom: Vec<_> = assets.iter().filter(|a| !a.is_builtin).copied().collect();
                        ordered_assets = builtin.into_iter().chain(custom.into_iter()).collect();
                        &ordered_assets[..]
                    } else {
                        assets
                    };

                    // Track whether we need to render section headers
                    let builtin_count = if show_effects_sections {
                        assets.iter().filter(|a| a.is_builtin).count()
                    } else {
                        0
                    };
                    let custom_count = if show_effects_sections {
                        assets.iter().filter(|a| !a.is_builtin).count()
                    } else {
                        0
                    };
                    let mut rendered_builtin_header = false;
                    let mut rendered_custom_header = false;
                    let mut _builtin_rendered = 0;

                    for asset in assets_to_render {
                        // Render section headers for Effects tab
                        if show_effects_sections {
                            if asset.is_builtin && !rendered_builtin_header && builtin_count > 0 {
                                Self::render_section_header(ui, "Built-in Effects", secondary_text_color);
                                rendered_builtin_header = true;
                            }
                            if !asset.is_builtin && !rendered_custom_header && custom_count > 0 {
                                // Add separator before custom section if there were built-in effects
                                if builtin_count > 0 {
                                    ui.add_space(8.0);
                                    let separator_rect = ui.allocate_exact_size(
                                        egui::vec2(ui.available_width(), 1.0),
                                        egui::Sense::hover(),
                                    ).0;
                                    ui.painter().rect_filled(separator_rect, 0.0, egui::Color32::from_gray(60));
                                    ui.add_space(8.0);
                                }
                                Self::render_section_header(ui, "Custom Effects", secondary_text_color);
                                rendered_custom_header = true;
                            }
                            if asset.is_builtin {
                                _builtin_rendered += 1;
                            }
                        }

                        let (item_rect, response) = ui.allocate_exact_size(
                            egui::vec2(ui.available_width(), ITEM_HEIGHT),
                            egui::Sense::click_and_drag(),
                        );

                        let is_selected = self.selected_asset == Some(asset.id);
                        let is_being_dragged = shared
                            .dragging_asset
                            .as_ref()
                            .map(|d| d.clip_id == asset.id)
                            .unwrap_or(false);

                        // Item background
                        let item_bg = if is_being_dragged {
                            egui::Color32::from_rgb(80, 100, 120) // Highlight when dragging
                        } else if is_selected {
                            egui::Color32::from_rgb(60, 80, 100)
                        } else if response.hovered() {
                            egui::Color32::from_rgb(45, 45, 45)
                        } else {
                            egui::Color32::from_rgb(35, 35, 35)
                        };
                        ui.painter().rect_filled(item_rect, 3.0, item_bg);

                        // Category color indicator bar
                        let indicator_color = asset.category.color();
                        let indicator_rect = egui::Rect::from_min_size(
                            item_rect.min,
                            egui::vec2(4.0, ITEM_HEIGHT),
                        );
                        ui.painter().rect_filled(indicator_rect, 0.0, indicator_color);

                        // Asset name (or inline edit field)
                        let is_renaming = self.rename_state.as_ref().map(|s| s.asset_id == asset.id).unwrap_or(false);

                        if is_renaming {
                            // Inline rename text field using IME-safe widget
                            let name_rect = egui::Rect::from_min_size(
                                item_rect.min + egui::vec2(10.0, 4.0),
                                egui::vec2(item_rect.width() - 20.0, 18.0),
                            );

                            if let Some(ref mut state) = self.rename_state {
                                let mut child_ui = ui.new_child(egui::UiBuilder::new().max_rect(name_rect));
                                ImeTextField::new(&mut state.edit_text)
                                    .font_size(13.0)
                                    .desired_width(name_rect.width())
                                    .request_focus()
                                    .show(&mut child_ui);
                            }
                        } else {
                            // Normal asset name display
                            ui.painter().text(
                                item_rect.min + egui::vec2(12.0, 8.0),
                                egui::Align2::LEFT_TOP,
                                &asset.name,
                                egui::FontId::proportional(13.0),
                                text_color,
                            );
                        }

                        // Metadata line (images don't have duration)
                        let metadata = if asset.category == AssetCategory::Images {
                            // For images, just show dimensions
                            asset.extra_info.clone()
                        } else if let Some((w, h)) = asset.dimensions {
                            format!(
                                "{:.1}s | {}x{} | {}",
                                asset.duration, w as u32, h as u32, asset.extra_info
                            )
                        } else {
                            format!("{:.1}s | {}", asset.duration, asset.extra_info)
                        };

                        ui.painter().text(
                            item_rect.min + egui::vec2(12.0, 24.0),
                            egui::Align2::LEFT_TOP,
                            &metadata,
                            egui::FontId::proportional(10.0),
                            secondary_text_color,
                        );

                        // Thumbnail on the right side
                        let thumbnail_rect = egui::Rect::from_min_size(
                            egui::pos2(
                                item_rect.max.x - LIST_THUMBNAIL_SIZE - 4.0,
                                item_rect.min.y + (ITEM_HEIGHT - LIST_THUMBNAIL_SIZE) / 2.0,
                            ),
                            egui::vec2(LIST_THUMBNAIL_SIZE, LIST_THUMBNAIL_SIZE),
                        );

                        // Generate and display thumbnail based on asset type
                        let asset_id = asset.id;
                        let asset_category = asset.category;
                        let ctx = ui.ctx().clone();

                        // Get waveform data from cache if thumbnail not already cached
                        let prefetched_waveform: Option<Vec<(f32, f32)>> =
                            if asset_category == AssetCategory::Audio && !self.thumbnail_cache.has(&asset_id) {
                                if let Some(clip) = document.audio_clips.get(&asset_id) {
                                    if let AudioClipType::Sampled { audio_pool_index } = &clip.clip_type {
                                        let waveform: Option<Vec<(f32, f32)>> = shared.raw_audio_cache.get(audio_pool_index)
                                            .map(|raw| peaks_from_raw_audio(raw, THUMBNAIL_SIZE as usize));
                                        if waveform.is_some() {
                                            println!("🎵 Found waveform for pool {} (asset {})", audio_pool_index, asset_id);
                                        } else {
                                            println!("⚠️  No waveform yet for pool {} (asset {})", audio_pool_index, asset_id);
                                        }
                                        waveform
                                    } else {
                                        None
                                    }
                                } else {
                                    None
                                }
                            } else {
                                None
                            };

                        let texture = self.thumbnail_cache.get_or_create(&ctx, asset_id, || {
                            match asset_category {
                                AssetCategory::Images => {
                                    document.image_assets.get(&asset_id)
                                        .and_then(generate_image_thumbnail)
                                }
                                AssetCategory::Vector => {
                                    // Render frame 0 of vector clip using tiny-skia
                                    let bg_color = egui::Color32::from_rgba_unmultiplied(40, 40, 40, 200);
                                    document.vector_clips.get(&asset_id)
                                        .map(|clip| generate_vector_thumbnail(clip, bg_color))
                                }
                                AssetCategory::Video => {
                                    // Generate video thumbnail from first frame
                                    generate_video_thumbnail(&asset_id, &shared.video_manager)
                                        .or_else(|| Some(generate_placeholder_thumbnail(AssetCategory::Video, 200)))
                                }
                                AssetCategory::Audio => {
                                    // Check if it's sampled or MIDI
                                    if let Some(clip) = document.audio_clips.get(&asset_id) {
                                        let bg_color = egui::Color32::from_rgba_unmultiplied(40, 40, 40, 200);
                                        match &clip.clip_type {
                                            AudioClipType::Sampled { .. } => {
                                                let wave_color = egui::Color32::from_rgb(100, 200, 100);
                                                if let Some(ref peaks) = prefetched_waveform {
                                                    println!("✅ Generating waveform thumbnail with {} peaks for asset {}", peaks.len(), asset_id);
                                                    Some(generate_waveform_thumbnail(peaks, bg_color, wave_color))
                                                } else {
                                                    println!("📦 Generating placeholder thumbnail for asset {}", asset_id);
                                                    Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                                }
                                            }
                                            AudioClipType::Midi { midi_clip_id } => {
                                                let bg_color = egui::Color32::from_rgba_unmultiplied(40, 40, 40, 200);
                                                let note_color = egui::Color32::from_rgb(100, 200, 100);

                                                if let Some(events) = shared.midi_event_cache.get(midi_clip_id) {
                                                    Some(generate_midi_thumbnail(events, clip.duration, bg_color, note_color))
                                                } else {
                                                    Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                                }
                                            }
                                            AudioClipType::Recording => {
                                                Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                            }
                                        }
                                    } else {
                                        Some(generate_placeholder_thumbnail(AssetCategory::Audio, 200))
                                    }
                                }
                                AssetCategory::Effects => {
                                    // Use GPU-rendered effect thumbnail if available
                                    if let Some(rgba) = shared.effect_thumbnail_cache.get(&asset.id) {
                                        Some(rgba.clone())
                                    } else {
                                        // Request GPU thumbnail generation
                                        shared.effect_thumbnail_requests.push(asset.id);
                                        // Return None to avoid caching placeholder - will retry next frame
                                        None
                                    }
                                }
                                AssetCategory::All => None,
                            }
                        });

                        // Either use cached texture or render placeholder directly for effects
                        if let Some(texture) = texture {
                            let image = egui::Image::new(texture)
                                .fit_to_exact_size(egui::vec2(LIST_THUMBNAIL_SIZE, LIST_THUMBNAIL_SIZE));
                            ui.put(thumbnail_rect, image);
                        } else if asset.category == AssetCategory::Effects {
                            // Render effect placeholder directly (not cached) until GPU thumbnail ready
                            let placeholder_rgba = generate_effect_thumbnail();
                            let color_image = egui::ColorImage::from_rgba_unmultiplied(
                                [THUMBNAIL_SIZE as usize, THUMBNAIL_SIZE as usize],
                                &placeholder_rgba,
                            );
                            let texture = ctx.load_texture(
                                format!("effect_placeholder_{}", asset.id),
                                color_image,
                                egui::TextureOptions::LINEAR,
                            );
                            let image = egui::Image::new(&texture)
                                .fit_to_exact_size(egui::vec2(LIST_THUMBNAIL_SIZE, LIST_THUMBNAIL_SIZE));
                            ui.put(thumbnail_rect, image);
                        }

                        // Handle click (selection)
                        if response.clicked() {
                            self.selected_asset = Some(asset.id);
                        }

                        // Handle right-click (context menu)
                        if response.secondary_clicked() {
                            if let Some(pos) = ui.ctx().pointer_interact_pos() {
                                self.context_menu = Some(ContextMenuState {
                                    asset_id: asset.id,
                                    position: pos,
                                });
                            }
                        }

                        // Handle double-click
                        if response.double_clicked() {
                            // For effects, open in shader editor
                            if asset.category == AssetCategory::Effects {
                                *shared.effect_to_load = Some(asset.id);
                            } else if !asset.is_builtin {
                                // For other non-builtin assets, start rename
                                self.rename_state = Some(RenameState {
                                    asset_id: asset.id,
                                    category: asset.category,
                                    edit_text: asset.name.clone(),
                                });
                            }
                        }

                        // Handle drag start
                        if response.drag_started() {
                            // For video clips, get the linked audio clip ID
                            let linked_audio_clip_id = if asset.drag_clip_type == DragClipType::Video {
                                let result = document.video_clips.get(&asset.id)
                                    .and_then(|video| video.linked_audio_clip_id);
                                eprintln!("DEBUG DRAG: Video clip {} has linked audio: {:?}", asset.id, result);
                                result
                            } else {
                                None
                            };

                            *shared.dragging_asset = Some(DraggingAsset {
                                clip_id: asset.id,
                                clip_type: asset.drag_clip_type,
                                name: asset.name.clone(),
                                duration: asset.duration,
                                dimensions: asset.dimensions,
                                linked_audio_clip_id,
                            });
                        }

                        // Add small spacing between items
                        ui.add_space(ITEM_PADDING);
                    }
                });
        });

        // Draw drag preview at cursor when dragging
        if let Some(dragging) = shared.dragging_asset.as_ref() {
            if let Some(pos) = ui.ctx().pointer_interact_pos() {
                // Draw a semi-transparent preview
                let preview_rect = egui::Rect::from_min_size(
                    pos + egui::vec2(10.0, 10.0), // Offset from cursor
                    egui::vec2(150.0, 30.0),
                );

                // Use top layer for drag preview
                let painter = ui.ctx().layer_painter(egui::LayerId::new(
                    egui::Order::Tooltip,
                    egui::Id::new("drag_preview"),
                ));

                painter.rect_filled(
                    preview_rect,
                    4.0,
                    egui::Color32::from_rgba_unmultiplied(60, 60, 60, 220),
                );

                painter.text(
                    preview_rect.center(),
                    egui::Align2::CENTER_CENTER,
                    &dragging.name,
                    egui::FontId::proportional(12.0),
                    egui::Color32::WHITE,
                );
            }
        }

        // Clear drag state when mouse is released (if not dropped on valid target)
        // Note: Valid drop targets (Timeline, Stage) will clear this themselves
        if ui.input(|i| i.pointer.any_released()) {
            // Only clear if we're still within this pane (dropped back on library)
            if let Some(pos) = ui.ctx().pointer_interact_pos() {
                if rect.contains(pos) {
                    *shared.dragging_asset = None;
                }
            }
        }
    }

    /// Render the asset grid view
    #[allow(dead_code)]
    fn render_asset_grid_view(
        &mut self,
        ui: &mut egui::Ui,
        rect: egui::Rect,
        path: &NodePath,
        shared: &mut SharedPaneState,
        assets: &[&AssetEntry],
        document: &Document,
    ) {
        // Background
        let bg_style = shared.theme.style(".panel-content", ui.ctx());
        let bg_color = bg_style
            .background_color
            .unwrap_or(egui::Color32::from_rgb(25, 25, 25));
        ui.painter().rect_filled(rect, 0.0, bg_color);

        // Text color
        let text_style = shared.theme.style(".text-primary", ui.ctx());
        let text_color = text_style
            .text_color
            .unwrap_or(egui::Color32::from_gray(200));
        let secondary_text_color = egui::Color32::from_gray(120);

        // Show empty state message if no assets
        if assets.is_empty() {
            let message = if !self.search_filter.is_empty() {
                "No assets match your search"
            } else {
                "No assets in this category"
            };

            ui.painter().text(
                rect.center(),
                egui::Align2::CENTER_CENTER,
                message,
                egui::FontId::proportional(14.0),
                secondary_text_color,
            );
            return;
        }

        // Calculate grid layout
        let content_width = rect.width() - 16.0; // Account for scrollbar
        let columns = ((content_width + GRID_SPACING) / (GRID_ITEM_SIZE + GRID_SPACING))
            .floor()
            .max(1.0) as usize;
        let item_height = GRID_ITEM_SIZE + 20.0; // 20 for name below thumbnail

        // For Effects tab, reorder: built-in first, then custom
        let ordered_assets: Vec<&AssetEntry>;
        let show_effects_sections = self.selected_category == AssetCategory::Effects;

        let assets_to_render: &[&AssetEntry] = if show_effects_sections {
            let builtin: Vec<_> = assets.iter().filter(|a| a.is_builtin).copied().collect();
            let custom: Vec<_> = assets.iter().filter(|a| !a.is_builtin).copied().collect();
            ordered_assets = builtin.into_iter().chain(custom.into_iter()).collect();
            &ordered_assets[..]
        } else {
            assets
        };

        let builtin_count = if show_effects_sections {
            assets.iter().filter(|a| a.is_builtin).count()
        } else {
            0
        };
        let custom_count = if show_effects_sections {
            assets.iter().filter(|a| !a.is_builtin).count()
        } else {
            0
        };

        ui.scope_builder(egui::UiBuilder::new().max_rect(rect), |ui| {
            egui::ScrollArea::vertical()
                .id_salt(("asset_grid_scroll", path))
                .auto_shrink([false, false])
                .show(ui, |ui| {
                    ui.set_min_width(content_width);

                    // Render built-in section header
                    if show_effects_sections && builtin_count > 0 {
                        Self::render_section_header(ui, "Built-in Effects", secondary_text_color);
                    }

                    // First pass: render built-in items
                    let builtin_items: Vec<_> = assets_to_render.iter().filter(|a| a.is_builtin).copied().collect();
                    if !builtin_items.is_empty() {
                        self.render_grid_items(ui, &builtin_items, columns, item_height, content_width, shared, document, text_color, secondary_text_color);
                    }

                    // Separator between sections
                    if show_effects_sections && builtin_count > 0 && custom_count > 0 {
                        ui.add_space(8.0);
                        let separator_rect = ui.allocate_exact_size(
                            egui::vec2(ui.available_width(), 1.0),
                            egui::Sense::hover(),
                        ).0;
                        ui.painter().rect_filled(separator_rect, 0.0, egui::Color32::from_gray(60));
                        ui.add_space(8.0);
                    }

                    // Render custom section header
                    if show_effects_sections && custom_count > 0 {
                        Self::render_section_header(ui, "Custom Effects", secondary_text_color);
                    }

                    // Second pass: render custom items
                    let custom_items: Vec<_> = assets_to_render.iter().filter(|a| !a.is_builtin).copied().collect();
                    if !custom_items.is_empty() {
                        self.render_grid_items(ui, &custom_items, columns, item_height, content_width, shared, document, text_color, secondary_text_color);
                    }

                    // For non-Effects tabs, just render all items
                    if !show_effects_sections {
                        self.render_grid_items(ui, assets_to_render, columns, item_height, content_width, shared, document, text_color, secondary_text_color);
                    }
                });
        });

        // Draw drag preview at cursor when dragging
        if let Some(dragging) = shared.dragging_asset.as_ref() {
            if let Some(pos) = ui.ctx().pointer_interact_pos() {
                let preview_rect = egui::Rect::from_min_size(
                    pos + egui::vec2(10.0, 10.0),
                    egui::vec2(150.0, 30.0),
                );

                let painter = ui.ctx().layer_painter(egui::LayerId::new(
                    egui::Order::Tooltip,
                    egui::Id::new("drag_preview"),
                ));

                painter.rect_filled(
                    preview_rect,
                    4.0,
                    egui::Color32::from_rgba_unmultiplied(60, 60, 60, 220),
                );

                painter.text(
                    preview_rect.center(),
                    egui::Align2::CENTER_CENTER,
                    &dragging.name,
                    egui::FontId::proportional(12.0),
                    egui::Color32::WHITE,
                );
            }
        }

        // Clear drag state when mouse is released
        if ui.input(|i| i.pointer.any_released()) {
            if let Some(pos) = ui.ctx().pointer_interact_pos() {
                if rect.contains(pos) {
                    *shared.dragging_asset = None;
                }
            }
        }
    }
}

impl PaneRenderer for AssetLibraryPane {
    fn render_content(
        &mut self,
        ui: &mut egui::Ui,
        rect: egui::Rect,
        path: &NodePath,
        shared: &mut SharedPaneState,
    ) {
        // Get an Arc clone of the document for thumbnail generation
        // This allows us to pass &mut shared to render functions while still accessing document
        let document_arc = shared.action_executor.document_arc();

        // Invalidate thumbnails for audio clips that got new waveform data
        if !shared.audio_pools_with_new_waveforms.is_empty() {
            println!("🎨 [ASSET_LIB] Checking for thumbnails to invalidate (pools: {:?})", shared.audio_pools_with_new_waveforms);
            let mut invalidated_any = false;
            for (asset_id, clip) in &document_arc.audio_clips {
                if let lightningbeam_core::clip::AudioClipType::Sampled { audio_pool_index } = &clip.clip_type {
                    if shared.audio_pools_with_new_waveforms.contains(audio_pool_index) {
                        println!("❌ [ASSET_LIB] Invalidating thumbnail for asset {} (pool {})", asset_id, audio_pool_index);
                        self.thumbnail_cache.invalidate(asset_id);
                        invalidated_any = true;
                    }
                }
            }
            // Force a repaint if we invalidated any thumbnails
            if invalidated_any {
                println!("🔄 [ASSET_LIB] Requesting repaint after invalidating thumbnails");
                ui.ctx().request_repaint();
            }
        }

        // Invalidate thumbnails for effects that were edited (shader code changed)
        if !shared.effect_thumbnails_to_invalidate.is_empty() {
            for effect_id in shared.effect_thumbnails_to_invalidate.iter() {
                self.thumbnail_cache.invalidate(effect_id);
            }
            // Clear after processing - we've handled these
            shared.effect_thumbnails_to_invalidate.clear();
            ui.ctx().request_repaint();
        }

        // Collect items (folders and assets)
        let all_items = self.collect_items(&document_arc);

        // Filter items by search text
        let search_lower = self.search_filter.to_lowercase();
        let filtered_items: Vec<&LibraryItem> = all_items
            .iter()
            .filter(|item| {
                if search_lower.is_empty() {
                    true
                } else {
                    item.name().to_lowercase().contains(&search_lower)
                }
            })
            .collect();

        // Layout: Search bar -> Category tabs -> Breadcrumbs -> Asset list
        let search_rect =
            egui::Rect::from_min_size(rect.min, egui::vec2(rect.width(), SEARCH_BAR_HEIGHT));

        let tabs_rect = egui::Rect::from_min_size(
            rect.min + egui::vec2(0.0, SEARCH_BAR_HEIGHT),
            egui::vec2(rect.width(), CATEGORY_TAB_HEIGHT),
        );

        let breadcrumb_rect = egui::Rect::from_min_size(
            rect.min + egui::vec2(0.0, SEARCH_BAR_HEIGHT + CATEGORY_TAB_HEIGHT),
            egui::vec2(rect.width(), BREADCRUMB_HEIGHT),
        );

        let list_rect = egui::Rect::from_min_max(
            rect.min + egui::vec2(0.0, SEARCH_BAR_HEIGHT + CATEGORY_TAB_HEIGHT + BREADCRUMB_HEIGHT),
            rect.max,
        );

        // Render components
        self.render_search_bar(ui, search_rect, shared);
        self.render_category_tabs(ui, tabs_rect, shared);
        self.render_breadcrumbs(ui, breadcrumb_rect, &document_arc, shared);
        self.render_items(ui, list_rect, path, shared, &filtered_items, &document_arc);

        // Detect right-click on pane background (not on items)
        // Only allow folder creation in categories with folder support (not "All")
        // Don't trigger if we already opened a folder or asset context menu
        if self.selected_category != AssetCategory::All {
            if ui.input(|i| i.pointer.secondary_clicked()) {
                if self.folder_context_menu.is_none() && self.context_menu.is_none() {
                    if let Some(pos) = ui.ctx().pointer_interact_pos() {
                        if list_rect.contains(pos) {
                            self.pane_context_menu = Some(pos);
                        }
                    }
                }
            }
        }

        // Context menu handling
        if let Some(ref context_state) = self.context_menu.clone() {
            let context_asset_id = context_state.asset_id;
            let menu_pos = context_state.position;

            // Find the asset info from all_items
            let asset_opt = all_items.iter().find_map(|item| {
                match item {
                    LibraryItem::Asset(asset) if asset.id == context_asset_id => Some(asset),
                    _ => None,
                }
            });

            if let Some(asset) = asset_opt {
                let asset_name = asset.name.clone();
                let asset_category = asset.category;
                let asset_is_builtin = asset.is_builtin;
                let asset_folder_id = asset.folder_id;
                let in_use = Self::is_asset_in_use(
                    shared.action_executor.document(),
                    context_asset_id,
                    asset_category,
                );

                // Get folders for this category (for Move to Folder submenu)
                let folders: Vec<(Uuid, String)> = if let Some(core_cat) = Self::to_core_category(asset_category) {
                    let tree = document_arc.get_folder_tree(core_cat);
                    tree.folders.iter()
                        .map(|(id, f)| (*id, f.name.clone()))
                        .collect()
                } else {
                    Vec::new()
                };

                // Show context menu popup at the stored position
                let menu_id = egui::Id::new("asset_context_menu");
                let menu_response = egui::Area::new(menu_id)
                    .order(egui::Order::Foreground)
                    .fixed_pos(menu_pos)
                    .show(ui.ctx(), |ui| {
                        egui::Frame::popup(ui.style()).show(ui, |ui| {
                            ui.set_min_width(120.0);

                            // Add "Edit in Shader Editor" for effects
                            if asset_category == AssetCategory::Effects {
                                if ui.button("Edit in Shader Editor").clicked() {
                                    *shared.effect_to_load = Some(context_asset_id);
                                    self.context_menu = None;
                                }
                                ui.separator();
                            }

                            // Built-in effects cannot be renamed or deleted
                            if asset_is_builtin {
                                ui.label(egui::RichText::new("Built-in effect")
                                    .color(egui::Color32::from_gray(120))
                                    .italics());
                            } else {
                                if ui.button("Rename").clicked() {
                                    // Start inline rename
                                    self.rename_state = Some(RenameState {
                                        asset_id: context_asset_id,
                                        category: asset_category,
                                        edit_text: asset_name.clone(),
                                    });
                                    self.context_menu = None;
                                }

                                if ui.button("Delete").clicked() {
                                    // Set up pending delete confirmation
                                    self.pending_delete = Some(PendingDelete {
                                        asset_id: context_asset_id,
                                        asset_name: asset_name.clone(),
                                        category: asset_category,
                                        in_use,
                                    });
                                    self.context_menu = None;
                                }

                                // Move to Folder submenu (only show if there are folders or asset is not at root)
                                if !folders.is_empty() || asset_folder_id.is_some() {
                                    ui.separator();
                                    ui.menu_button("Move to Folder", |ui| {
                                        // Move to Root option (if not already at root)
                                        if asset_folder_id.is_some() {
                                            if ui.button("Root").clicked() {
                                                if let Some(core_cat) = Self::to_core_category(asset_category) {
                                                    let action = lightningbeam_core::actions::MoveAssetToFolderAction::new(
                                                        core_cat,
                                                        context_asset_id,
                                                        None,
                                                    );
                                                    let _ = shared.action_executor.execute(Box::new(action));
                                                }
                                                self.context_menu = None;
                                            }
                                            if !folders.is_empty() {
                                                ui.separator();
                                            }
                                        }

                                        // List all folders (except current folder)
                                        for (folder_id, folder_name) in &folders {
                                            if asset_folder_id != Some(*folder_id) {
                                                if ui.button(folder_name).clicked() {
                                                    if let Some(core_cat) = Self::to_core_category(asset_category) {
                                                        let action = lightningbeam_core::actions::MoveAssetToFolderAction::new(
                                                            core_cat,
                                                            context_asset_id,
                                                            Some(*folder_id),
                                                        );
                                                        let _ = shared.action_executor.execute(Box::new(action));
                                                    }
                                                    self.context_menu = None;
                                                }
                                            }
                                        }
                                    });
                                }
                            }
                        });
                    });

                // Close menu on click outside (using primary button release)
                let menu_rect = menu_response.response.rect;
                if ui.input(|i| i.pointer.primary_released()) {
                    if let Some(pos) = ui.ctx().pointer_interact_pos() {
                        if !menu_rect.contains(pos) {
                            self.context_menu = None;
                        }
                    }
                }

                // Also close on Escape
                if ui.input(|i| i.key_pressed(egui::Key::Escape)) {
                    self.context_menu = None;
                }
            } else {
                self.context_menu = None;
            }
        }

        // Pane context menu (for creating folders)
        if let Some(menu_pos) = self.pane_context_menu {
            let menu_id = egui::Id::new("pane_context_menu");
            let menu_response = egui::Area::new(menu_id)
                .order(egui::Order::Foreground)
                .fixed_pos(menu_pos)
                .show(ui.ctx(), |ui| {
                    egui::Frame::popup(ui.style()).show(ui, |ui| {
                        ui.set_min_width(150.0);

                        if ui.button("New Folder").clicked() {
                            // Get the current folder for this category
                            let parent_folder_id = self.get_current_folder();

                            // Get the core category
                            if let Some(core_category) = Self::to_core_category(self.selected_category) {
                                // Create folder action
                                let action = lightningbeam_core::actions::CreateFolderAction::new(
                                    core_category,
                                    "New Folder",
                                    parent_folder_id,
                                );

                                if shared.action_executor.execute(Box::new(action)).is_ok() {
                                    // Successfully created folder
                                }
                            }

                            self.pane_context_menu = None;
                        }
                    })
                });

            // Close menu on click outside (using primary button release to avoid first-frame issue)
            let menu_rect = menu_response.response.rect;
            if ui.input(|i| i.pointer.primary_released()) {
                if let Some(pos) = ui.ctx().pointer_interact_pos() {
                    if !menu_rect.contains(pos) {
                        self.pane_context_menu = None;
                    }
                }
            }

            // Also close on Escape
            if ui.input(|i| i.key_pressed(egui::Key::Escape)) {
                self.pane_context_menu = None;
            }
        }

        // Folder context menu (for rename/delete/etc)
        if let Some(ref folder_state) = self.folder_context_menu.clone() {
            let folder_id = folder_state.folder_id;
            let menu_pos = folder_state.position;

            // Get the folder from the document
            if let Some(core_category) = Self::to_core_category(self.selected_category) {
                let folder_tree = document_arc.get_folder_tree(core_category);

                if let Some(folder) = folder_tree.folders.get(&folder_id) {
                    let folder_name = folder.name.clone();

                    let menu_id = egui::Id::new("folder_context_menu");
                    let menu_response = egui::Area::new(menu_id)
                        .order(egui::Order::Foreground)
                        .fixed_pos(menu_pos)
                        .show(ui.ctx(), |ui| {
                            egui::Frame::popup(ui.style()).show(ui, |ui| {
                                ui.set_min_width(150.0);

                                if ui.button("Rename").clicked() {
                                    // Enter rename mode for folder
                                    self.folder_rename_state = Some(FolderRenameState {
                                        folder_id,
                                        category: self.selected_category,
                                        edit_text: folder_name.clone(),
                                    });
                                    self.folder_context_menu = None;
                                }

                                if ui.button("Delete").clicked() {
                                    // Execute delete folder action
                                    let action = lightningbeam_core::actions::DeleteFolderAction::new(
                                        core_category,
                                        folder_id,
                                        lightningbeam_core::actions::DeleteStrategy::MoveToParent,
                                    );

                                    let _ = shared.action_executor.execute(Box::new(action));
                                    self.folder_context_menu = None;
                                }
                            })
                        });

                    // Close menu on click outside (using primary button release to avoid first-frame issue)
                    let menu_rect = menu_response.response.rect;
                    if ui.input(|i| i.pointer.primary_released()) {
                        if let Some(pos) = ui.ctx().pointer_interact_pos() {
                            if !menu_rect.contains(pos) {
                                self.folder_context_menu = None;
                            }
                        }
                    }

                    // Also close on Escape
                    if ui.input(|i| i.key_pressed(egui::Key::Escape)) {
                        self.folder_context_menu = None;
                    }
                } else {
                    self.folder_context_menu = None;
                }
            } else {
                self.folder_context_menu = None;
            }
        }

        // Draw drag preview at cursor when dragging an asset
        if let Some(dragging) = shared.dragging_asset.as_ref() {
            if let Some(pos) = ui.ctx().pointer_interact_pos() {
                // Draw a semi-transparent preview near the cursor
                let preview_rect = egui::Rect::from_min_size(
                    pos + egui::vec2(12.0, 12.0), // Offset from cursor
                    egui::vec2(160.0, 32.0),
                );

                // Use top layer for drag preview so it appears above everything
                let painter = ui.ctx().layer_painter(egui::LayerId::new(
                    egui::Order::Tooltip,
                    egui::Id::new("asset_drag_preview"),
                ));

                // Background with rounded corners
                painter.rect_filled(
                    preview_rect,
                    4.0,
                    egui::Color32::from_rgba_unmultiplied(50, 80, 120, 230),
                );

                // Border
                painter.rect_stroke(
                    preview_rect,
                    4.0,
                    egui::Stroke::new(1.0, egui::Color32::from_rgb(100, 160, 220)),
                    egui::StrokeKind::Inside,
                );

                // Asset name
                painter.text(
                    preview_rect.center(),
                    egui::Align2::CENTER_CENTER,
                    &dragging.name,
                    egui::FontId::proportional(12.0),
                    egui::Color32::WHITE,
                );
            }
        }

        // Clear drag state when mouse is released within the asset library
        // (dropped back on library without hitting a valid folder target)
        if ui.input(|i| i.pointer.any_released()) {
            if shared.dragging_asset.is_some() {
                if let Some(pos) = ui.ctx().pointer_interact_pos() {
                    if rect.contains(pos) {
                        *shared.dragging_asset = None;
                    }
                }
            }
        }

        // Delete confirmation dialog
        if let Some(ref pending) = self.pending_delete.clone() {
            let window_id = egui::Id::new("delete_confirm_dialog");
            let mut should_close = false;
            let mut should_delete = false;

            egui::Window::new("Confirm Delete")
                .id(window_id)
                .collapsible(false)
                .resizable(false)
                .anchor(egui::Align2::CENTER_CENTER, egui::vec2(0.0, 0.0))
                .show(ui.ctx(), |ui| {
                    ui.set_min_width(300.0);

                    if pending.in_use {
                        ui.label(egui::RichText::new("Warning: This asset is currently in use!")
                            .color(egui::Color32::from_rgb(255, 180, 100)));
                        ui.add_space(4.0);
                        ui.label("Deleting it will remove all clip instances that reference it.");
                        ui.add_space(8.0);
                    }

                    ui.label(format!("Are you sure you want to delete \"{}\"?", pending.asset_name));
                    ui.add_space(12.0);

                    ui.horizontal(|ui| {
                        if ui.button("Cancel").clicked() {
                            should_close = true;
                        }

                        ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
                            let delete_text = if pending.in_use { "Delete Anyway" } else { "Delete" };
                            if ui.button(delete_text).clicked() {
                                should_delete = true;
                                should_close = true;
                            }
                        });
                    });
                });

            if should_delete {
                // Perform the delete
                Self::delete_asset(
                    shared.action_executor.document_mut(),
                    pending.asset_id,
                    pending.category,
                );
            }

            if should_close {
                self.pending_delete = None;
            }
        }

        // Handle rename state (Enter to confirm, Escape to cancel, click outside to confirm)
        if let Some(ref state) = self.rename_state.clone() {
            let mut should_confirm = false;
            let mut should_cancel = false;

            // Check for Enter or Escape
            ui.input(|i| {
                if i.key_pressed(egui::Key::Enter) {
                    should_confirm = true;
                } else if i.key_pressed(egui::Key::Escape) {
                    should_cancel = true;
                }
            });

            if should_confirm {
                let new_name = state.edit_text.trim();
                if !new_name.is_empty() {
                    Self::rename_asset(
                        shared.action_executor.document_mut(),
                        state.asset_id,
                        state.category,
                        new_name,
                    );
                }
                self.rename_state = None;
            } else if should_cancel {
                self.rename_state = None;
            }
        }

        // Handle folder rename state (Enter to confirm, Escape to cancel)
        if let Some(ref state) = self.folder_rename_state.clone() {
            let mut should_confirm = false;
            let mut should_cancel = false;

            // Check for Enter or Escape
            ui.input(|i| {
                if i.key_pressed(egui::Key::Enter) {
                    should_confirm = true;
                } else if i.key_pressed(egui::Key::Escape) {
                    should_cancel = true;
                }
            });

            if should_confirm {
                let new_name = state.edit_text.trim();
                if !new_name.is_empty() {
                    // Execute rename folder action
                    if let Some(core_category) = Self::to_core_category(state.category) {
                        let action = lightningbeam_core::actions::RenameFolderAction::new(
                            core_category,
                            state.folder_id,
                            new_name.to_string(),
                        );
                        let _ = shared.action_executor.execute(Box::new(action));
                    }
                }
                self.folder_rename_state = None;
            } else if should_cancel {
                self.folder_rename_state = None;
            }
        }
    }

    fn name(&self) -> &str {
        "Asset Library"
    }
}
