use crate::editor::UNDOMANAGER;
use crate::prelude::*;

pub struct TilePickerTool {
    id: TheId,
}

impl EditorTool for TilePickerTool {
    fn new() -> Self
    where
        Self: Sized,
    {
        Self {
            id: TheId::named_with_id("Tile Picker Tool", Uuid::new_v4()),
        }
    }

    fn id(&self) -> TheId {
        self.id.clone()
    }

    fn info(&self) -> String {
        "Picker Tool (P). Click to sample a pixel color, then select it in the palette or add it if missing.".to_string()
    }

    fn icon_name(&self) -> String {
        "eyedropper-sample".to_string()
    }

    fn rgba_view_mode(&self) -> Option<TheRGBAViewMode> {
        Some(TheRGBAViewMode::TileEditor)
    }

    fn accel(&self) -> Option<char> {
        Some('P')
    }

    fn handle_event(
        &mut self,
        event: &TheEvent,
        ui: &mut TheUI,
        ctx: &mut TheContext,
        project: &mut Project,
        server_ctx: &mut ServerContext,
    ) -> bool {
        if let TheEvent::TileEditorClicked(id, coord) = event
            && id.name == "Tile Editor Dock RGBA Layout View"
        {
            return self.pick_from(*coord, ui, ctx, project, server_ctx);
        }
        false
    }
}

impl TilePickerTool {
    fn pick_from(
        &mut self,
        pos: Vec2<i32>,
        ui: &mut TheUI,
        ctx: &mut TheContext,
        project: &mut Project,
        server_ctx: &mut ServerContext,
    ) -> bool {
        if let Some(editor) = ui.get_rgba_layout("Tile Editor Dock RGBA Layout")
            && let Some(rgba_view) = editor.rgba_view_mut().as_rgba_view()
            && rgba_view.has_paste_preview()
        {
            return false;
        }

        let editing_ctx = server_ctx.editing_ctx;
        let Some(texture) = project.get_editing_texture(&editing_ctx) else {
            return false;
        };

        let width = texture.width as i32;
        let height = texture.height as i32;
        if pos.x < 0 || pos.y < 0 || pos.x >= width || pos.y >= height {
            return false;
        }

        let sampled = texture.get_pixel(pos.x as u32, pos.y as u32);
        let sampled_color = TheColor::from(sampled);

        let prev_palette = project.palette.clone();
        let prev_palette_materials = project.palette_materials.clone();

        let mut selected_index = project
            .palette
            .colors
            .iter()
            .position(|entry| entry.as_ref() == Some(&sampled_color));

        if selected_index.is_none() {
            project.palette.add_unique_color(sampled_color.clone());
            selected_index = project
                .palette
                .colors
                .iter()
                .position(|entry| entry.as_ref() == Some(&sampled_color));
        }

        if let Some(index) = selected_index {
            project.palette.current_index = index as u16;
        }

        if project.palette != prev_palette {
            let undo = ProjectUndoAtom::PaletteEdit(
                prev_palette,
                prev_palette_materials,
                project.palette.clone(),
                project.palette_materials.clone(),
            );
            UNDOMANAGER.write().unwrap().add_undo(undo, ctx);
        }

        apply_palette(ui, ctx, server_ctx, project);

        if let Some(palette_picker) = ui.get_palette_picker("Palette Picker") {
            palette_picker.set_palette(project.palette.clone());
            palette_picker.set_index(project.palette.current_index as usize);
        }
        if let Some(widget) = ui.get_widget("Palette Color Picker") {
            widget.set_value(TheValue::ColorObject(sampled_color.clone()));
        }
        if let Some(widget) = ui.get_widget("Palette Hex Edit") {
            widget.set_value(TheValue::Text(sampled_color.to_hex()));
        }

        crate::undo::project_helper::refresh_palette_runtime(project);

        true
    }
}
