use super::*;

pub fn project_sun_ui(world: &mut World, ui: &mut egui::Ui, entity: Entity) {
    if world.get::<ProjectSun>(entity).is_none() {
        return;
    }

    let rendering = world
        .resource::<settings::ProjectSettings>()
        .rendering
        .clone();
    let scene_override_active = has_scene_sun_override(world);
    let mut create_override = false;
    let mut options = ComponentCardOptions::fixed(COMPONENT_PROJECT_SUN, "Project Sun", icons::SUN);
    options.resettable = false;
    let card = component_card_context(world, entity, options);
    let card_response = component_card(ui, &card, |ui| {
        ui.label("Runtime default world lighting from assets/project.ron.");
        property_row(ui, "Illuminance", |ui| {
            ui.small(format!("{:.0} lux", rendering.sun_illuminance));
        });
        property_row(ui, "Ambient", |ui| {
            ui.small(format!(
                "{:.2}, {:.2}, {:.2} @ {:.1}",
                rendering.ambient_color[0],
                rendering.ambient_color[1],
                rendering.ambient_color[2],
                rendering.ambient_brightness
            ));
        });
        property_row(ui, "Shadows", |ui| {
            ui.small(format!(
                "{} cascades, max {:.0}m",
                rendering.shadow_cascades, rendering.shadow_max_distance
            ));
        });
        if scene_override_active {
            ui.label(egui::RichText::new("Scene sun override is active.").weak());
        } else if ui.button("Create Scene Sun Override").clicked() {
            create_override = true;
        }
    });
    apply_component_card_response(world, entity, card_response);

    if create_override {
        let sun = create_scene_sun_override_from_project_settings(world);
        crate::ui::request_ui_selection(world, &[sun]);
    }
}

pub(super) fn has_scene_sun_override(world: &mut World) -> bool {
    world
        .query_filtered::<(
            &shared::LightDesc,
            Option<&AuthoringComponentStates>,
            Option<&InspectorOrder>,
        ), With<LevelObject>>()
        .iter(world)
        .any(|(light, states, legacy_order)| {
            authoring_component_active(states, legacy_order, COMPONENT_LIGHT_DESC)
                && matches!(light.kind, shared::AuthoringLightKind::Directional)
        })
}

pub(super) fn texture_asset_picker_ui(
    world: &mut World,
    ui: &mut egui::Ui,
    label: &str,
    value: &mut Option<String>,
    candidates: &[TextureAssetCandidate],
) -> bool {
    let current_path = value.clone();
    let dragging_selection = world
        .get_resource::<EditorAssets>()
        .and_then(|assets| assets.dragging_selection().cloned());
    let drop_candidate = dragging_selection
        .as_ref()
        .and_then(|selection| texture_path_from_selection(world, selection));
    let mut selected_path: Option<String> = None;
    let mut clear = false;
    let mut locate = false;
    let mut accepted_drop = false;
    let current_candidate = current_path.as_ref().and_then(|path| {
        candidates
            .iter()
            .find(|candidate| candidate.path == *path)
            .cloned()
    });

    property_row(ui, label, |ui| {
        let control_width = ui
            .available_width()
            .max(MIN_INLINE_CONTROL_WIDTH.min(ui.available_width().max(1.0)));
        let row_height = 30.0;
        let (rect, _response) =
            ui.allocate_exact_size(egui::vec2(control_width, row_height), egui::Sense::hover());
        let valid_drag = drop_candidate.is_some();
        let row_hovered = ui.rect_contains_pointer(rect);
        let drop_hovered = valid_drag && row_hovered;
        let stroke = if drop_hovered {
            egui::Stroke::new(2.0_f32, egui::Color32::from_rgb(125, 198, 255))
        } else if valid_drag {
            egui::Stroke::new(1.0_f32, egui::Color32::from_rgb(58, 88, 122))
        } else if row_hovered {
            egui::Stroke::new(1.0_f32, egui::Color32::from_rgb(92, 102, 118))
        } else {
            egui::Stroke::new(1.0_f32, BORDER)
        };
        let fill = if drop_hovered {
            egui::Color32::from_rgb(29, 57, 86)
        } else if valid_drag {
            WIDGET_BG.linear_multiply(0.88)
        } else if row_hovered {
            WIDGET_BG.linear_multiply(1.05)
        } else {
            WIDGET_BG.linear_multiply(0.75)
        };
        ui.painter()
            .rect(rect, 4.0, fill, stroke, egui::StrokeKind::Inside);
        if drop_hovered {
            let badge_rect = egui::Rect::from_min_size(
                rect.right_top() + egui::vec2(-82.0, 4.0),
                egui::vec2(74.0, 16.0),
            );
            ui.painter().rect(
                badge_rect,
                3.0,
                egui::Color32::from_rgb(35, 95, 155),
                egui::Stroke::NONE,
                egui::StrokeKind::Inside,
            );
            ui.painter().text(
                badge_rect.center(),
                egui::Align2::CENTER_CENTER,
                "Drop texture",
                egui::FontId::new(10.0, egui::FontFamily::Proportional),
                egui::Color32::from_rgb(225, 241, 255),
            );
        }

        let mut child = ui.new_child(
            egui::UiBuilder::new()
                .max_rect(rect.shrink2(egui::vec2(6.0, 4.0)))
                .layout(egui::Layout::left_to_right(egui::Align::Center)),
        );
        child.set_clip_rect(rect.intersect(ui.clip_rect()));
        let preview_size = 22.0;
        let (preview_rect, _preview_response) =
            child.allocate_exact_size(egui::vec2(preview_size, preview_size), egui::Sense::hover());
        child.painter().rect(
            preview_rect,
            3.0,
            PANEL_BG_DARK,
            egui::Stroke::new(1.0_f32, BORDER),
            egui::StrokeKind::Inside,
        );
        if let Some(texture_id) = current_candidate
            .as_ref()
            .and_then(|candidate| candidate.texture_id)
        {
            let uv = egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0));
            child.painter().image(
                texture_id,
                preview_rect.shrink(1.0),
                uv,
                egui::Color32::WHITE,
            );
        } else {
            child.painter().text(
                preview_rect.center(),
                egui::Align2::CENTER_CENTER,
                icons::IMAGE.as_str(),
                egui::FontId::new(12.0, egui::FontFamily::Name("phosphor-regular".into())),
                TEXT_DIM,
            );
        }

        let action_width = 92.0;
        let text_width = (child.available_width() - action_width).max(1.0);
        child.allocate_ui_with_layout(
            egui::vec2(text_width, 22.0),
            egui::Layout::left_to_right(egui::Align::Center),
            |ui| {
                let display_label = current_candidate
                    .as_ref()
                    .map(|candidate| candidate.label.as_str())
                    .or(current_path.as_deref())
                    .unwrap_or("(none)");
                ui.add_sized(
                    [text_width, 20.0],
                    egui::Label::new(egui::RichText::new(display_label).color(
                        if current_path.is_some() {
                            TEXT_DIM.linear_multiply(1.45)
                        } else {
                            TEXT_DIM
                        },
                    ))
                    .truncate(),
                );
            },
        );

        child.allocate_ui_with_layout(
            egui::vec2(action_width, 28.0),
            egui::Layout::right_to_left(egui::Align::Center),
            |ui| {
                let clear_response = ui.add_enabled(
                    current_path.is_some(),
                    egui::Button::new(phosphor_icon(icons::X, 16.0))
                        .frame(false)
                        .min_size(egui::vec2(22.0, 22.0)),
                );
                if clear_response.on_hover_text("Clear texture").clicked() {
                    clear = true;
                }
                let locate_response = ui.add_enabled(
                    current_path.is_some(),
                    egui::Button::new(phosphor_icon(icons::CROSSHAIR, 16.0))
                        .frame(false)
                        .min_size(egui::vec2(22.0, 22.0)),
                );
                if locate_response
                    .on_hover_text("Locate in content browser")
                    .clicked()
                {
                    locate = true;
                }
                if candidates.is_empty() {
                    ui.add_enabled(
                        false,
                        egui::Button::new(phosphor_icon(icons::FOLDER_OPEN, 16.0))
                            .frame(false)
                            .min_size(egui::vec2(22.0, 22.0)),
                    )
                    .on_hover_text("No texture assets available");
                } else {
                    let menu = ui.menu_button(phosphor_icon(icons::FOLDER_OPEN, 16.0), |ui| {
                        ui.set_min_width(240.0);
                        for candidate in candidates {
                            let selected = current_path.as_deref() == Some(candidate.path.as_str());
                            if ui
                                .selectable_label(selected, candidate.label.as_str())
                                .on_hover_text(candidate.path.as_str())
                                .clicked()
                            {
                                selected_path = Some(candidate.path.clone());
                                ui.close();
                            }
                        }
                    });
                    menu.response.on_hover_text("Browse textures");
                }
            },
        );

        if drop_hovered && ui.input(|input| input.pointer.any_released()) {
            if let Some(candidate) = drop_candidate.as_ref() {
                selected_path = Some(candidate.path.clone());
                accepted_drop = true;
            }
        }
    });

    if locate {
        locate_texture_asset(world, current_path.as_deref(), candidates);
    }
    if accepted_drop {
        if let Some(mut assets) = world.get_resource_mut::<EditorAssets>() {
            assets.clear_drag();
        }
    }
    if clear {
        *value = None;
        return current_path.is_some();
    }
    if let Some(path) = selected_path {
        let changed = current_path.as_deref() != Some(path.as_str());
        *value = Some(path);
        return changed;
    }

    false
}

pub(super) fn locate_texture_asset(
    world: &mut World,
    path: Option<&str>,
    candidates: &[TextureAssetCandidate],
) {
    let Some(path) = path else {
        return;
    };
    let Some(candidate) = candidates.iter().find(|candidate| candidate.path == path) else {
        if let Some(mut scene_io) = world.get_resource_mut::<crate::scene_io::SceneIo>() {
            scene_io.status = format!("Could not locate texture {path}");
        }
        return;
    };

    reveal_asset_in_browser(world, &candidate.folder_path, &candidate.selection);
}

pub(super) fn option_string_ui(ui: &mut egui::Ui, label: &str, value: &mut Option<String>) -> bool {
    let mut text = value.clone().unwrap_or_default();
    let before = text.clone();
    property_row(ui, label, |ui| {
        ui.horizontal_wrapped(|ui| {
            let clear_width = 52.0;
            let field_width = (ui.available_width() - clear_width - ui.spacing().item_spacing.x)
                .max(MIN_INLINE_CONTROL_WIDTH.min(ui.available_width().max(1.0)))
                .min(TEXT_FIELD_MAX_WIDTH)
                .min(ui.available_width().max(1.0));
            ui.add_sized([field_width, 20.0], egui::TextEdit::singleline(&mut text));
            if ui.button("Clear").clicked() {
                text.clear();
            }
        });
    });
    let changed = before != text;
    *value = if text.trim().is_empty() {
        None
    } else {
        Some(text)
    };
    changed
}
