//! Asset browser UI state and view enums.

use std::collections::HashSet;
use std::path::PathBuf;

use crate::assets::{AssetSelection, ASSETS_ROOT, BUILTINS_FOLDER};
use bevy::prelude::*;
use shared::MaterialAsset;

pub(crate) const ASSET_DETAILS_DEFAULT_WIDTH: f32 = 290.0;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum AssetBrowserView {
    Grid,
    List,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum AssetSort {
    Name,
    Kind,
    Modified,
    Size,
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum AssetKindFilter {
    All,
    Model,
    Texture,
    Material,
    Audio,
    Level,
    Prefab,
    Builtin,
}

#[derive(Resource, Debug)]
pub struct AssetBrowserUiState {
    pub(crate) search: String,
    pub(crate) view: AssetBrowserView,
    pub(crate) sort: AssetSort,
    pub(crate) kind_filter: AssetKindFilter,
    pub(crate) thumbnail_size: f32,
    pub(crate) recursive: bool,
    pub(crate) show_details: bool,
    /// File-manager navigation history. Content topology operations do not rewrite these stacks.
    pub(crate) navigation_back: Vec<String>,
    pub(crate) navigation_forward: Vec<String>,
    /// Width of the details pane for the current editor session.
    pub(crate) details_width: f32,
    pub(crate) expanded_folders: HashSet<String>,
    pub(crate) expanded_assets: HashSet<String>,
    pub(crate) pending_delete: Option<AssetDeleteRequest>,
    pub(crate) clipboard: Option<ContentClipboard>,
    pub(crate) pending_path_edit: Option<ContentPathEdit>,
    pub(crate) pending_content_transaction: Option<PendingContentTransaction>,
    /// Selected project folder while the explicit Import To review is open.
    pub(crate) pending_import_destination: Option<String>,
    pub(crate) content_undo: Vec<ContentUndoEntry>,
    pub(crate) pending_gltf_extraction: Option<GltfMaterialExtractionDraft>,
    pub(crate) pending_pbr_grouping: Option<PbrGroupingDraft>,
    pub(crate) show_trash: bool,
}

#[derive(Debug, Clone)]
pub(crate) struct ContentClipboard {
    pub(crate) sources: Vec<String>,
    pub(crate) cut: bool,
}

#[derive(Debug, Clone)]
pub(crate) struct ContentUndoEntry {
    pub(crate) label: String,
    pub(crate) action: ContentUndoAction,
    pub(crate) guarded_sources: Vec<(PathBuf, String)>,
}

#[derive(Debug, Clone)]
pub(crate) enum ContentUndoAction {
    Apply(Vec<content_pipeline::ContentOperation>),
    TrashCreated(Vec<PathBuf>),
    RestoreTrash(PathBuf),
}

#[derive(Debug, Clone)]
pub(crate) struct PendingContentTransaction {
    pub(crate) preview: content_pipeline::ContentTransactionPreview,
    pub(crate) guarded_paths: Vec<(PathBuf, String)>,
    pub(crate) clear_cut_clipboard: bool,
    pub(crate) clear_drag: bool,
    pub(crate) browser_snapshot: ContentBrowserSnapshot,
}

/// Browser-local state captured before a reviewed content operation begins.
/// Cancel restores this verbatim; commit deliberately replaces it with the result selection.
#[derive(Debug, Clone)]
pub(crate) struct ContentBrowserSnapshot {
    pub(crate) current_folder: String,
    pub(crate) selected: Option<AssetSelection>,
    pub(crate) selections: Vec<AssetSelection>,
    pub(crate) selection_anchor: Option<AssetSelection>,
    pub(crate) dragging: Option<AssetSelection>,
    pub(crate) asset_status: String,
    pub(crate) scene_status: String,
}

#[derive(Debug, Clone)]
pub(crate) enum ContentPathEditKind {
    Rename { source: String },
    NewFolder { parent: String },
}

#[derive(Debug, Clone)]
pub(crate) struct ContentPathEdit {
    pub(crate) kind: ContentPathEditKind,
    pub(crate) name: String,
}

#[derive(Debug, Clone)]
pub(crate) struct AssetDeleteRequest {
    pub(crate) label: String,
    pub(crate) files: Vec<String>,
    pub(crate) warnings: Vec<String>,
}

#[derive(Debug, Clone)]
pub(crate) struct GltfMaterialExtractionDraft {
    pub(crate) source: String,
    pub(crate) destination: String,
    pub(crate) materials: Vec<GltfMaterialExtractionEntry>,
    /// When present, extraction publishes only this imported source and assigns only this actor slot.
    pub(crate) actor_target: Option<GltfMaterialExtractionTarget>,
}

#[derive(Debug, Clone)]
pub(crate) struct GltfMaterialExtractionTarget {
    pub(crate) entity: Entity,
    pub(crate) slot_id: shared::ComponentInstanceId,
    pub(crate) source_sub_asset_id: String,
}

#[derive(Debug, Clone)]
pub(crate) struct GltfMaterialExtractionEntry {
    pub(crate) included: bool,
    pub(crate) source_index: usize,
    pub(crate) source_name: String,
    pub(crate) path: String,
    pub(crate) asset: MaterialAsset,
    pub(crate) write_mode: MaterialExtractionWriteMode,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum MaterialExtractionWriteMode {
    /// An existing provenance match must be explicitly reviewed before publishing.
    Undecided,
    CreateNew,
    ApplyExisting {
        expected_fingerprint: String,
        previous_bytes: Vec<u8>,
    },
}

#[derive(Debug, Clone)]
pub(crate) struct PbrGroupingDraft {
    pub(crate) folder: String,
    pub(crate) textures: Vec<PbrTextureDraft>,
}

#[derive(Debug, Clone)]
pub(crate) struct PbrTextureDraft {
    pub(crate) path: String,
    pub(crate) target: String,
    pub(crate) role: content_pipeline::PbrTextureRole,
    pub(crate) confidence: content_pipeline::PbrMatchConfidence,
    pub(crate) included: bool,
}

impl Default for AssetBrowserUiState {
    fn default() -> Self {
        let mut expanded_folders = HashSet::new();
        expanded_folders.insert(ASSETS_ROOT.to_string());
        expanded_folders.insert(BUILTINS_FOLDER.to_string());
        Self {
            search: String::new(),
            view: AssetBrowserView::Grid,
            sort: AssetSort::Name,
            kind_filter: AssetKindFilter::All,
            thumbnail_size: 96.0,
            recursive: false,
            show_details: true,
            navigation_back: Vec::new(),
            navigation_forward: Vec::new(),
            details_width: ASSET_DETAILS_DEFAULT_WIDTH,
            expanded_folders,
            expanded_assets: HashSet::new(),
            pending_delete: None,
            clipboard: None,
            pending_path_edit: None,
            pending_content_transaction: None,
            pending_import_destination: None,
            content_undo: Vec::new(),
            pending_gltf_extraction: None,
            pending_pbr_grouping: None,
            show_trash: false,
        }
    }
}
