use super::*;

pub(super) fn content_header(
    world: &mut World,
    ui: &mut egui::Ui,
    current_folder: &str,
    folders: &[FolderSnapshot],
    assets: &[AssetRow],
) {
    let folder_label = if current_folder == BUILTINS_FOLDER {
        "Built-ins"
    } else {
        Path::new(current_folder)
            .file_name()
            .and_then(|name| name.to_str())
            .unwrap_or(current_folder)
    };
    ui.label(panel_heading(folder_label));
    let direct_assets = assets
        .iter()
        .filter(|row| row.asset.folder_path == current_folder)
        .count();
    let direct_folders = folders
        .iter()
        .filter(|folder| folder.parent.as_deref() == Some(current_folder))
        .count();
    let sort = world.resource::<AssetBrowserUiState>().sort;
    ui.small(
        egui::RichText::new(format!(
            "{} items · sorted by {}",
            direct_folders + direct_assets,
            sort_label(sort)
        ))
        .color(TEXT_DIM),
    );
}

pub(super) fn prefetch_asset_row_thumbnails(world: &mut World, rows: &[AssetRow]) {
    let requests: Vec<(String, String, EditorAssetKind)> = rows
        .iter()
        .filter(|row| {
            matches!(
                row.asset.kind,
                EditorAssetKind::Texture | EditorAssetKind::Model | EditorAssetKind::Material
            )
        })
        .filter_map(|row| {
            Some((
                asset_cache_key(&row.asset),
                row.asset.path.clone()?,
                row.asset.kind.clone(),
            ))
        })
        .collect();
    if requests.is_empty() {
        return;
    }
    let asset_server = world.resource::<AssetServer>().clone();
    world.resource_scope(|world, mut cache: Mut<AssetThumbnailCache>| {
        world.resource_scope(|_world, mut studio: Mut<ThumbnailStudio>| {
            for (key, path, kind) in &requests {
                match kind {
                    EditorAssetKind::Texture => {
                        cache.request_texture(key.clone(), path.clone(), &asset_server);
                    }
                    EditorAssetKind::Model => {
                        cache.request_model(key.clone(), path.clone(), &mut studio);
                    }
                    EditorAssetKind::Material => {
                        cache.request_material_asset(key.clone(), path.clone(), &mut studio);
                    }
                    _ => {}
                }
            }
        });
    });
}

pub(super) fn folder_tree_branch(
    world: &mut World,
    ui: &mut egui::Ui,
    folders: &[FolderSnapshot],
    node_path: &str,
    depth: usize,
    current_folder: &str,
) {
    let Some(folder) = folders.iter().find(|folder| folder.path == node_path) else {
        return;
    };
    let path = &folder.path;
    let name = &folder.name;
    let children: Vec<&FolderSnapshot> = folders
        .iter()
        .filter(|child| child.parent.as_deref() == Some(path.as_str()))
        .collect();
    let expanded = children.is_empty()
        || world
            .resource::<AssetBrowserUiState>()
            .expanded_folders
            .contains(path);

    let selected = current_folder == *path;
    ui.horizontal(|ui| {
        ui.add_space(depth as f32 * 12.0);
        if children.is_empty() {
            ui.add_sized(
                [18.0, 20.0],
                egui::Label::new(icon_text(icons::DOT_OUTLINE, 12.0).color(TEXT_DIM)),
            );
        } else {
            let icon = if expanded {
                icons::CARET_DOWN
            } else {
                icons::CARET_RIGHT
            };
            if ui
                .add_sized(
                    [18.0, 18.0],
                    egui::Button::new(icon_text(icon, 12.0)).frame(false),
                )
                .clicked()
            {
                let mut state = world.resource_mut::<AssetBrowserUiState>();
                if expanded {
                    state.expanded_folders.remove(path);
                } else {
                    state.expanded_folders.insert(path.clone());
                }
            }
        }
        ui.label(icon_text(icons::FOLDER, 14.0).color(TEXT_DIM));
        let folder_response = ui.add_sized(
            [fit_width(ui, 72.0, f32::INFINITY), 20.0],
            egui::Button::selectable(selected, name.as_str()),
        );
        if folder_response.clicked() {
            navigate_content_folder(world, path.clone());
        }
        if folder_response.secondary_clicked() {
            prepare_context_menu_selection(world, AssetSelection::Folder(path.clone()));
        }
        folder_response.context_menu(|ui| folder_context_menu(world, ui, folder));
        handle_asset_drop_to_folder(world, ui, &folder_response, path);
    });

    if expanded {
        for child in children {
            folder_tree_branch(world, ui, folders, &child.path, depth + 1, current_folder);
        }
    }
}

pub(super) fn child_folders_for_content(
    folders: &[FolderSnapshot],
    current_folder: &str,
    search: &str,
) -> Vec<FolderSnapshot> {
    if !search.trim().is_empty() {
        return Vec::new();
    }
    let mut children: Vec<FolderSnapshot> = folders
        .iter()
        .filter(|folder| folder.parent.as_deref() == Some(current_folder))
        .cloned()
        .collect();
    children.sort_by(|a, b| natural_cmp(&a.name, &b.name));
    children
}

pub(super) fn visible_assets(
    assets: &[AssetRow],
    current_folder: &str,
    state: &AssetBrowserStateSnapshot,
) -> Vec<AssetRow> {
    let search = state.search.trim().to_ascii_lowercase();
    let mut rows: Vec<AssetRow> = assets
        .iter()
        .filter(|row| {
            if state.recursive {
                row.asset.folder_path == current_folder
                    || row
                        .asset
                        .folder_path
                        .strip_prefix(current_folder)
                        .is_some_and(|rest| rest.starts_with('/'))
            } else {
                row.asset.folder_path == current_folder
            }
        })
        .filter(|row| asset_matches_kind_filter(&row.asset, state.kind_filter))
        .filter(|row| {
            search.is_empty()
                || row.asset.label.to_ascii_lowercase().contains(&search)
                || row
                    .asset
                    .path
                    .as_deref()
                    .unwrap_or_default()
                    .to_ascii_lowercase()
                    .contains(&search)
        })
        .cloned()
        .collect();

    rows.sort_by(|a, b| match state.sort {
        AssetSort::Name => natural_cmp(&a.asset.label, &b.asset.label),
        AssetSort::Kind => kind_label(&a.asset.kind).cmp(kind_label(&b.asset.kind)),
        AssetSort::Modified => b.modified.cmp(&a.modified),
        AssetSort::Size => b.file_size.cmp(&a.file_size),
    });
    rows
}

pub(super) fn visible_selection_order(
    folders: &[FolderSnapshot],
    assets: &[AssetRow],
) -> Vec<AssetSelection> {
    folders
        .iter()
        .map(|folder| AssetSelection::Folder(folder.path.clone()))
        .chain(assets.iter().map(|row| row.selection.clone()))
        .collect()
}

pub(super) fn apply_content_click_selection(
    world: &mut World,
    ui: &egui::Ui,
    selection: AssetSelection,
    visible_order: &[AssetSelection],
) {
    let modifiers = ui.input(|input| input.modifiers);
    let mut assets = world.resource_mut::<EditorAssets>();
    if modifiers.shift {
        assets.select_range(selection, visible_order, modifiers.command);
    } else if modifiers.command {
        assets.toggle_selection(selection);
    } else {
        assets.select(selection);
    }
}

pub(super) fn handle_content_shortcuts(
    world: &mut World,
    ctx: &egui::Context,
    visible_order: &[AssetSelection],
    content_contains_pointer: bool,
) {
    if !content_contains_pointer
        || ctx.egui_wants_keyboard_input()
        || ctx.any_popup_open()
        || content_browser_modal_active(world)
    {
        return;
    }
    let (select_all, copy, cut, paste, duplicate, new_folder, undo, rename, delete) =
        ctx.input(|input| {
            let modifiers = input.modifiers;
            let command_only = modifiers.command && !modifiers.shift && !modifiers.alt;
            let command_shift = modifiers.command && modifiers.shift && !modifiers.alt;
            let no_modifiers =
                !modifiers.command && !modifiers.ctrl && !modifiers.shift && !modifiers.alt;
            (
                command_only && input.key_pressed(egui::Key::A),
                command_only && input.key_pressed(egui::Key::C),
                command_only && input.key_pressed(egui::Key::X),
                command_only && input.key_pressed(egui::Key::V),
                command_only && input.key_pressed(egui::Key::D),
                command_shift && input.key_pressed(egui::Key::N),
                command_only && input.key_pressed(egui::Key::Z),
                no_modifiers && input.key_pressed(egui::Key::F2),
                no_modifiers && input.key_pressed(egui::Key::Delete),
            )
        });
    let consumed = if select_all {
        Some((egui::Modifiers::COMMAND, egui::Key::A))
    } else if copy {
        Some((egui::Modifiers::COMMAND, egui::Key::C))
    } else if cut {
        Some((egui::Modifiers::COMMAND, egui::Key::X))
    } else if paste {
        Some((egui::Modifiers::COMMAND, egui::Key::V))
    } else if duplicate {
        Some((egui::Modifiers::COMMAND, egui::Key::D))
    } else if new_folder {
        Some((
            egui::Modifiers::COMMAND | egui::Modifiers::SHIFT,
            egui::Key::N,
        ))
    } else if undo {
        Some((egui::Modifiers::COMMAND, egui::Key::Z))
    } else if rename {
        Some((egui::Modifiers::NONE, egui::Key::F2))
    } else if delete {
        Some((egui::Modifiers::NONE, egui::Key::Delete))
    } else {
        None
    };
    if let Some((modifiers, key)) = consumed {
        ctx.input_mut(|input| {
            input.consume_key(modifiers, key);
        });
    }
    if select_all {
        world
            .resource_mut::<EditorAssets>()
            .select_all(visible_order);
    } else if copy {
        set_content_clipboard(world, false);
    } else if cut {
        set_content_clipboard(world, true);
    } else if paste {
        paste_content_clipboard(world);
    } else if duplicate {
        duplicate_selection(world);
    } else if new_folder {
        let current_folder = world.resource::<EditorAssets>().current_folder.clone();
        if current_folder != BUILTINS_FOLDER {
            begin_new_folder(world, current_folder);
        }
    } else if undo {
        undo_last_content_operation(world);
    } else if rename {
        begin_rename(world);
    } else if delete {
        request_delete_for_selection(world);
    }
}

pub(super) fn content_browser_modal_active(world: &World) -> bool {
    let state = world.resource::<AssetBrowserUiState>();
    state.pending_delete.is_some()
        || state.pending_path_edit.is_some()
        || state.pending_content_transaction.is_some()
        || state.pending_import_destination.is_some()
        || state.pending_gltf_extraction.is_some()
        || state.pending_pbr_grouping.is_some()
        || state.show_trash
        || world
            .get_resource::<crate::scene_io::PendingAssetImportReview>()
            .is_some_and(|pending| pending.0.is_some())
        || world
            .get_resource::<PendingExternalMoveRepair>()
            .and_then(|pending| pending.review.as_ref())
            .is_some_and(|review| review.open)
}
