//! Per-tile viewport shading controls (mode + overlays toggle).
//!
//! Each viewport tile gets a small docked button strip in its top-left
//! corner with three shading-mode buttons (Wireframe / Solid / Rendered)
//! and a toggle for editor overlays (grid, gizmos, debug lines). The
//! buttons drive `ViewportShading` on the tile's camera entity, which the
//! engine reads on every per-camera render. Only the editor knows about
//! these tiles and which entity each one renders, so this module lives in
//! the editor app, not the engine.
//!
//! `build` creates the strip parented to a content entity. `update`
//! repositions it each frame against the tile's pixel rect (so it tracks
//! window/tile resizes). `sync` reflects the current `ViewportShading`
//! values back into the buttons (active highlight, overlays icon swap).
//! `poll` consumes interaction events and pushes `Action::SetShadingMode`
//! / `Action::ToggleViewportOverlays` for the interaction drain.

use crate::ecs::EditorWorld;
use crate::systems::retained_ui::Action;
use nightshade::ecs::camera::components::{ShadingMode, ViewportShading, ViewportUpdateMode};
use nightshade::ecs::gizmos::GizmoMode;
use nightshade::prelude::*;

const STRIP_INSET_PX: f32 = 8.0;
const STRIP_HEIGHT_PX: f32 = 28.0;
const BUTTON_WIDTH_PX: f32 = 30.0;
const BUTTON_GAP_PX: f32 = 3.0;
const STRIP_PADDING_PX: f32 = 4.0;
const SEPARATOR_WIDTH_PX: f32 = 1.0;
const NUM_BUTTONS: f32 = 12.0;
const NUM_SEPARATORS: f32 = 4.0;
const NUM_CHILDREN: f32 = NUM_BUTTONS + NUM_SEPARATORS;
const STRIP_WIDTH_PX: f32 = STRIP_PADDING_PX * 2.0
    + BUTTON_WIDTH_PX * NUM_BUTTONS
    + SEPARATOR_WIDTH_PX * NUM_SEPARATORS
    + BUTTON_GAP_PX * (NUM_CHILDREN - 1.0);

const STRIP_BG: Vec4 = Vec4::new(0.06, 0.06, 0.08, 0.85);
const BUTTON_INACTIVE: Vec4 = Vec4::new(0.0, 0.0, 0.0, 0.0);
const BUTTON_ACTIVE: Vec4 = Vec4::new(0.20, 0.42, 0.78, 0.95);
const BUTTON_HOVER: Vec4 = Vec4::new(0.25, 0.25, 0.30, 0.85);
const ICON_COLOR: Vec4 = Vec4::new(0.92, 0.92, 0.92, 1.0);
const SEPARATOR_COLOR: Vec4 = Vec4::new(0.25, 0.25, 0.30, 0.85);

#[derive(Clone, Copy)]
pub struct ViewportControlsHandles {
    pub camera_entity: Entity,
    pub container: Entity,
    pub wireframe_button: Entity,
    pub solid_button: Entity,
    pub flat_button: Entity,
    pub rendered_button: Entity,
    pub overlays_button: Entity,
    pub overlays_icon: Entity,
    pub grid_button: Entity,
    pub sky_button: Entity,
    pub translate_button: Entity,
    pub rotate_button: Entity,
    pub scale_button: Entity,
    pub snap_button: Entity,
    pub realtime_button: Entity,
}

pub fn build(tree: &mut UiTreeBuilder, camera_entity: Entity) -> ViewportControlsHandles {
    let icon_set = tree.world_mut().resources.retained_ui.icon_set;
    let lookup = IconLookup::for_set(icon_set);

    let container = tree
        .add_node()
        .window(
            Ab(vec2(STRIP_INSET_PX, STRIP_INSET_PX)),
            Ab(vec2(STRIP_WIDTH_PX, STRIP_HEIGHT_PX)),
            Anchor::TopLeft,
        )
        .rect(6.0)
        .color_raw::<UiBase>(STRIP_BG)
        .with_layer(UiLayer::DockedPanels)
        .with_depth(UiDepthMode::Set(14.0))
        .flow(FlowDirection::Horizontal, STRIP_PADDING_PX, BUTTON_GAP_PX)
        .entity();
    let mut wireframe_button = Entity::default();
    let mut solid_button = Entity::default();
    let mut flat_button = Entity::default();
    let mut rendered_button = Entity::default();
    let mut overlays_button = Entity::default();
    let mut overlays_icon = Entity::default();
    let mut grid_button = Entity::default();
    let mut sky_button = Entity::default();
    let mut translate_button = Entity::default();
    let mut rotate_button = Entity::default();
    let mut scale_button = Entity::default();
    let mut snap_button = Entity::default();
    let mut realtime_button = Entity::default();

    tree.in_parent(container, |tree| {
        wireframe_button = make_icon_button(
            tree,
            lookup.mesh,
            "Viewport Shading: Wireframe\nShow mesh edges (bounding volumes + normal lines).",
        );
        solid_button = make_icon_button(
            tree,
            lookup.palette,
            "Viewport Shading: Solid\nUnlit shading with post-processing disabled.",
        );
        flat_button = make_icon_button(
            tree,
            lookup.crop_free,
            "Viewport Shading: Flat\nCAD-style gray with lighting; suppresses material colors and textures.",
        );
        rendered_button = make_icon_button(
            tree,
            lookup.auto_awesome,
            "Viewport Shading: Rendered\nFull lighting and post-processing pipeline.",
        );

        add_separator(tree);

        let pair = make_overlays_button(
            tree,
            lookup.visibility,
            "Show Overlays\nDisplay overlays like gizmos and grid for this viewport.",
        );
        overlays_button = pair.0;
        overlays_icon = pair.1;
        grid_button = make_icon_button(
            tree,
            lookup.grid,
            "Show Ground Grid\nToggle the world floor grid (global).",
        );
        sky_button = make_icon_button(
            tree,
            lookup.public,
            "Show Sky\nToggle the atmosphere skybox (global). IBL contributions are unaffected.",
        );

        add_separator(tree);

        translate_button = make_icon_button(
            tree,
            lookup.open_with,
            "Translate gizmo\nMove the selected entity along local axes.",
        );
        rotate_button = make_icon_button(
            tree,
            lookup.rotate_left,
            "Rotate gizmo\nRotate the selected entity around local axes.",
        );
        scale_button = make_icon_button(
            tree,
            lookup.zoom_out_map,
            "Scale gizmo\nScale the selected entity.",
        );

        add_separator(tree);

        snap_button = make_icon_button(
            tree,
            lookup.tune,
            "Snap\nQuantize gizmo translate, rotate, and scale to step values.\nConfigure in the World inspector.",
        );

        add_separator(tree);

        realtime_button = make_icon_button(
            tree,
            lookup.refresh,
            "Realtime\nRe-render this viewport every frame. When off, the tile only re-renders on scene mutations or shading changes.",
        );
    });

    ViewportControlsHandles {
        camera_entity,
        container,
        wireframe_button,
        solid_button,
        flat_button,
        rendered_button,
        overlays_button,
        overlays_icon,
        grid_button,
        sky_button,
        translate_button,
        rotate_button,
        scale_button,
        snap_button,
        realtime_button,
    }
}

fn make_icon_button(tree: &mut UiTreeBuilder, icon: IconGlyph, tooltip: &str) -> Entity {
    let button = tree
        .add_node()
        .size(
            BUTTON_WIDTH_PX.px(),
            (STRIP_HEIGHT_PX - STRIP_PADDING_PX * 2.0).px(),
        )
        .rect(4.0)
        .color_raw::<UiBase>(BUTTON_INACTIVE)
        .color_raw::<UiHover>(BUTTON_HOVER)
        .with_interaction()
        .with_tooltip(tooltip)
        .with_transition::<UiHover>(8.0, 6.0)
        .with_cursor_icon(winit::window::CursorIcon::Pointer)
        .flow(FlowDirection::Horizontal, 0.0, 0.0)
        .entity();
    tree.in_parent(button, |tree| {
        tree.add_node()
            .fill()
            .with_icon(icon, 14.0)
            .color_raw::<UiBase>(ICON_COLOR)
            .entity();
    });
    button
}

fn add_separator(tree: &mut UiTreeBuilder) {
    tree.add_node()
        .size(
            SEPARATOR_WIDTH_PX.px(),
            (STRIP_HEIGHT_PX - STRIP_PADDING_PX * 2.0).px(),
        )
        .with_rect(0.0, 0.0, SEPARATOR_COLOR)
        .color_raw::<UiBase>(SEPARATOR_COLOR)
        .entity();
}

fn make_overlays_button(
    tree: &mut UiTreeBuilder,
    icon: IconGlyph,
    tooltip: &str,
) -> (Entity, Entity) {
    let button = tree
        .add_node()
        .size(
            BUTTON_WIDTH_PX.px(),
            (STRIP_HEIGHT_PX - STRIP_PADDING_PX * 2.0).px(),
        )
        .rect(4.0)
        .color_raw::<UiBase>(BUTTON_INACTIVE)
        .color_raw::<UiHover>(BUTTON_HOVER)
        .with_interaction()
        .with_tooltip(tooltip)
        .with_transition::<UiHover>(8.0, 6.0)
        .with_cursor_icon(winit::window::CursorIcon::Pointer)
        .flow(FlowDirection::Horizontal, 0.0, 0.0)
        .entity();
    let icon_entity = tree.in_parent(button, |tree| {
        tree.add_node()
            .fill()
            .with_icon(icon, 14.0)
            .color_raw::<UiBase>(ICON_COLOR)
            .entity()
    });
    (button, icon_entity)
}

pub fn update(world: &mut World, handles: &ViewportControlsHandles, tile_rect: Option<Rect>) {
    let dpi_scale = world.resources.window.cached_scale_factor.max(0.0001);
    let min_width_physical = (STRIP_WIDTH_PX + STRIP_INSET_PX) * dpi_scale;
    let visible = matches!(tile_rect, Some(rect) if rect.width() > min_width_physical);
    ui_set_visible(world, handles.container, visible);
    if !visible {
        return;
    }
    if let Some(rect) = tile_rect
        && let Some(node) = world.ui.get_ui_layout_node_mut(handles.container)
        && let Some(nightshade::ecs::ui::layout_types::UiLayoutType::Window(window)) =
            node.base_layout.as_mut()
    {
        let position = vec2(rect.min.x + STRIP_INSET_PX, rect.min.y + STRIP_INSET_PX) / dpi_scale;
        window.position = nightshade::ecs::ui::units::Ab(position).into();
    }
}

pub fn sync(world: &mut World, handles: &ViewportControlsHandles) {
    let snap_enabled = world
        .resources
        .user_interface
        .gizmos
        .translation_snap
        .is_some();
    let shading = world
        .core
        .get_viewport_shading(handles.camera_entity)
        .copied()
        .unwrap_or_default();
    set_button_active(
        world,
        handles.wireframe_button,
        shading.mode == ShadingMode::Wireframe,
    );
    set_button_active(
        world,
        handles.solid_button,
        shading.mode == ShadingMode::Solid,
    );
    set_button_active(
        world,
        handles.flat_button,
        shading.mode == ShadingMode::Flat,
    );
    set_button_active(
        world,
        handles.rendered_button,
        shading.mode == ShadingMode::Rendered,
    );
    set_button_active(world, handles.overlays_button, shading.show_overlays);
    set_button_active(
        world,
        handles.grid_button,
        world.resources.debug_draw.show_grid,
    );
    set_button_active(
        world,
        handles.sky_button,
        world.resources.render_settings.show_sky,
    );
    let gizmo_mode = world.resources.user_interface.gizmos.mode;
    set_button_active(
        world,
        handles.translate_button,
        matches!(
            gizmo_mode,
            GizmoMode::LocalTranslation | GizmoMode::GlobalTranslation
        ),
    );
    set_button_active(
        world,
        handles.rotate_button,
        matches!(gizmo_mode, GizmoMode::Rotation),
    );
    set_button_active(
        world,
        handles.scale_button,
        matches!(gizmo_mode, GizmoMode::Scale),
    );
    set_button_active(world, handles.snap_button, snap_enabled);
    let realtime_active = world
        .core
        .get_viewport_update_mode(handles.camera_entity)
        .copied()
        .map(|mode| matches!(mode, ViewportUpdateMode::Always))
        .unwrap_or(true);
    set_button_active(world, handles.realtime_button, realtime_active);

    let icon_set = world.resources.retained_ui.icon_set;
    let lookup = IconLookup::for_set(icon_set);
    let icon = if shading.show_overlays {
        lookup.visibility
    } else {
        lookup.visibility_off
    };
    ui_set_icon(world, handles.overlays_icon, icon);
}

fn set_button_active(world: &mut World, button: Entity, active: bool) {
    if let Some(color) = world.ui.get_ui_node_color_mut(button) {
        color.colors[0] = Some(if active {
            BUTTON_ACTIVE
        } else {
            BUTTON_INACTIVE
        });
    }
}

pub fn poll(editor_world: &mut EditorWorld, world: &mut World, handles: &ViewportControlsHandles) {
    for event in ui_events(world) {
        if let UiEvent::ButtonClicked(entity) = event {
            let mode = if *entity == handles.wireframe_button {
                Some(ShadingMode::Wireframe)
            } else if *entity == handles.solid_button {
                Some(ShadingMode::Solid)
            } else if *entity == handles.flat_button {
                Some(ShadingMode::Flat)
            } else if *entity == handles.rendered_button {
                Some(ShadingMode::Rendered)
            } else {
                None
            };
            if let Some(mode) = mode {
                editor_world
                    .resources
                    .ui_interaction
                    .actions
                    .push(Action::SetShadingMode(handles.camera_entity, mode));
            } else if *entity == handles.overlays_button {
                editor_world
                    .resources
                    .ui_interaction
                    .actions
                    .push(Action::ToggleViewportOverlays(handles.camera_entity));
            } else if *entity == handles.grid_button {
                editor_world
                    .resources
                    .ui_interaction
                    .actions
                    .push(Action::ToggleGroundGrid);
            } else if *entity == handles.sky_button {
                editor_world
                    .resources
                    .ui_interaction
                    .actions
                    .push(Action::ToggleSky);
            } else if *entity == handles.translate_button {
                editor_world
                    .resources
                    .ui_interaction
                    .actions
                    .push(Action::SetGizmoMode(GizmoMode::LocalTranslation));
            } else if *entity == handles.rotate_button {
                editor_world
                    .resources
                    .ui_interaction
                    .actions
                    .push(Action::SetGizmoMode(GizmoMode::Rotation));
            } else if *entity == handles.scale_button {
                editor_world
                    .resources
                    .ui_interaction
                    .actions
                    .push(Action::SetGizmoMode(GizmoMode::Scale));
            } else if *entity == handles.snap_button {
                editor_world
                    .resources
                    .ui_interaction
                    .actions
                    .push(Action::ToggleSnap);
            } else if *entity == handles.realtime_button {
                editor_world
                    .resources
                    .ui_interaction
                    .actions
                    .push(Action::ToggleViewportRealtime(handles.camera_entity));
            }
        }
    }
}

pub fn ensure_shading_with_mode(world: &mut World, camera_entity: Entity, mode: ShadingMode) {
    if world.core.get_viewport_shading(camera_entity).is_none() {
        world
            .core
            .add_components(camera_entity, nightshade::ecs::world::VIEWPORT_SHADING);
    }
    world.core.set_viewport_shading(
        camera_entity,
        ViewportShading {
            mode,
            show_overlays: true,
        },
    );
}

pub fn ensure_shading(world: &mut World, camera_entity: Entity) {
    if world.core.get_viewport_shading(camera_entity).is_none() {
        world
            .core
            .add_components(camera_entity, nightshade::ecs::world::VIEWPORT_SHADING);
        world
            .core
            .set_viewport_shading(camera_entity, ViewportShading::default());
    }
}
