//! Reusable Content Browser and Material Library asset cards.

use bevy_egui::egui;
use egui_phosphor_icons::icons;

use crate::assets::{kind_icon, EditorAsset};

#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct AssetCardStatus {
    pub dirty: bool,
    pub processing: bool,
    pub error: bool,
}

impl AssetCardStatus {
    pub fn for_document(
        snapshot: Option<&crate::asset_documents::AuthoredDocumentSnapshot>,
        dirty: bool,
        failed: bool,
    ) -> Self {
        use crate::asset_documents::{AuthoredDocumentState, DerivedProcessingState};

        Self {
            dirty,
            processing: snapshot.is_some_and(|status| {
                matches!(
                    status.processing,
                    DerivedProcessingState::Queued | DerivedProcessingState::Processing
                )
            }),
            error: failed
                || snapshot.is_some_and(|status| {
                    matches!(
                        status.state,
                        AuthoredDocumentState::ExternalConflict | AuthoredDocumentState::SaveFailed
                    ) || status.processing == DerivedProcessingState::Failed
                }),
        }
    }
}

#[allow(clippy::too_many_arguments)]
pub fn draw_asset_card(
    ui: &mut egui::Ui,
    asset: &EditorAsset,
    texture_id: Option<egui::TextureId>,
    pending: bool,
    failure: Option<&str>,
    selected: bool,
    thumbnail_size: f32,
    status: AssetCardStatus,
) -> egui::Response {
    let response = draw_asset_cell(
        ui,
        asset,
        texture_id,
        pending,
        failure,
        selected,
        thumbnail_size,
    );
    draw_asset_status_rail(ui, response.rect, status);
    response
}

pub fn draw_asset_status_rail(ui: &egui::Ui, rect: egui::Rect, status: AssetCardStatus) {
    let mut y = rect.top() + 11.0;
    let x = rect.right() - 11.0;
    if status.error {
        ui.painter().text(
            egui::pos2(x, y),
            egui::Align2::CENTER_CENTER,
            icons::WARNING_CIRCLE.as_str(),
            egui::FontId::new(12.0, egui::FontFamily::Name("phosphor-regular".into())),
            super::theme::ERROR,
        );
        y += 12.0;
    }
    if status.processing {
        ui.painter().text(
            egui::pos2(x, y),
            egui::Align2::CENTER_CENTER,
            icons::CIRCLE_NOTCH.as_str(),
            egui::FontId::new(12.0, egui::FontFamily::Name("phosphor-regular".into())),
            super::theme::ACCENT,
        );
        y += 12.0;
    }
    if status.dirty {
        ui.painter()
            .circle_filled(egui::pos2(x, y), 4.0, super::theme::WARNING);
    }
}

/// Draws the same authored-document status model in a fixed-width list cell.
pub fn draw_asset_status_marker(ui: &mut egui::Ui, status: AssetCardStatus) {
    let (rect, response) = ui.allocate_exact_size(egui::vec2(20.0, 20.0), egui::Sense::hover());
    let (glyph, color) = if status.error {
        (Some(icons::WARNING_CIRCLE), super::theme::ERROR)
    } else if status.processing {
        (Some(icons::CIRCLE_NOTCH), super::theme::ACCENT)
    } else if status.dirty {
        (None, super::theme::WARNING)
    } else {
        return;
    };
    if let Some(glyph) = glyph {
        ui.painter().text(
            rect.center(),
            egui::Align2::CENTER_CENTER,
            glyph.as_str(),
            egui::FontId::new(12.0, egui::FontFamily::Name("phosphor-regular".into())),
            color,
        );
    } else {
        ui.painter().circle_filled(rect.center(), 4.0, color);
    }
    response.on_hover_text(if status.error {
        "Asset has a save, conflict, or processing error"
    } else if status.processing {
        "Derived asset processing is running"
    } else {
        "Asset has unsaved changes"
    });
}

#[allow(clippy::too_many_arguments)]
fn draw_asset_cell(
    ui: &mut egui::Ui,
    asset: &EditorAsset,
    texture_id: Option<egui::TextureId>,
    pending: bool,
    failed: Option<&str>,
    selected: bool,
    thumbnail_size: f32,
) -> egui::Response {
    let thumb_size = thumbnail_size.clamp(48.0, 112.0);
    let cell_size = egui::vec2(thumb_size + 20.0, thumb_size + 42.0);
    let (rect, response) = ui.allocate_exact_size(cell_size, egui::Sense::click_and_drag());
    let fill = if selected {
        super::theme::SELECTION_BG_MUTED
    } else if response.hovered() {
        super::theme::ELEVATED_BG
    } else {
        super::theme::WIDGET_BG
    };
    ui.painter().rect(
        rect,
        4.0,
        fill,
        egui::Stroke::new(
            1.0_f32,
            if selected {
                super::theme::ACCENT_HOVER
            } else {
                super::theme::BORDER
            },
        ),
        egui::StrokeKind::Inside,
    );

    let thumbnail_rect = egui::Rect::from_min_size(
        rect.min + egui::vec2(10.0, 8.0),
        egui::vec2(thumb_size, thumb_size),
    );
    let painter = ui.painter().with_clip_rect(thumbnail_rect);
    if let Some(texture_id) = texture_id {
        painter.image(
            texture_id,
            thumbnail_rect,
            egui::Rect::from_min_max(egui::Pos2::ZERO, egui::pos2(1.0, 1.0)),
            egui::Color32::WHITE,
        );
    } else {
        let (icon, color) = if pending {
            (icons::CIRCLE_NOTCH, super::theme::TEXT_DIM)
        } else if failed.is_some() {
            (icons::WARNING_CIRCLE, super::theme::TEXT_DIM)
        } else {
            (kind_icon(&asset.kind), super::theme::TEXT)
        };
        painter.text(
            thumbnail_rect.center(),
            egui::Align2::CENTER_CENTER,
            icon.as_str(),
            egui::FontId::new(26.0, egui::FontFamily::Name("phosphor-regular".into())),
            color,
        );
    }

    let label_rect = egui::Rect::from_min_max(
        egui::pos2(rect.min.x + 6.0, thumbnail_rect.max.y + 4.0),
        egui::pos2(rect.max.x - 6.0, rect.max.y - 4.0),
    );
    let label_color = if selected {
        super::theme::TEXT_SELECTED
    } else {
        super::theme::TEXT
    };
    let font = egui::FontId::proportional(11.0);
    let mut job =
        egui::text::LayoutJob::simple(asset.label.clone(), font, label_color, label_rect.width());
    job.halign = egui::Align::Center;
    job.wrap.max_rows = 2;
    job.wrap.break_anywhere = true;
    job.wrap.overflow_character = Some('…');
    let galley = ui.painter().layout_job(job);
    let label_painter = ui.painter().with_clip_rect(label_rect);
    label_painter.galley(
        egui::pos2(
            label_rect.center().x - galley.rect.width() * 0.5,
            label_rect.center().y - galley.rect.height() * 0.5,
        ),
        galley.clone(),
        label_color,
    );

    if let Some(reason) = failed {
        response.on_hover_text(reason)
    } else if galley.elided {
        response.on_hover_text(&asset.label)
    } else {
        response
    }
}
