//! Edit-mode context menu.
//!
//! Shown when the user opens an icon's context menu — touch hold or
//! mouse right-click — on the dock or homescreen grid. The menu is
//! anchored near the icon it belongs to, clamped inside the visible
//! surface, and offers the per-item actions the shell supports:
//!
//! - Información — opens a small overlay describing the app.
//! - Eliminar del homescreen — unpins the item from the dock / grid.
//! - Desinstalar — stub for now; filtered per-app-type later.
//! - Cancelar edición — dismisses the menu and exits edit mode.
//!
//! Tapping anywhere outside the panel also exits edit mode, routed through
//! the overlay's `on_dismiss` in [`crate::app`].

use std::sync::Arc;

use crate::message::Message;
use crate::homescreen::DragOrigin;

use rust_i18n::t;

/// State carried by an open edit menu: which icon it is anchored on and
/// the approximate centre of that icon (in logical pixels) so the panel
/// lands adjacent to the cell that opened the menu.
pub struct EditMenu
{
	pub origin:   DragOrigin,
	pub app_id:   String,
	pub app_name: String,
	pub anchor:   ( f32, f32 ),
	pub running:  bool,
}

/// Menu card metrics in design px, multiplied by the density at use.
/// The card width is exact (the column's max_width); the height is
/// estimated as chrome + visible rows so the card can be clamped inside
/// the surface and land just above its anchor.
const MENU_W: f32 = 260.0;
/// Card height minus the item rows: container and column paddings, the
/// title stripe, both separators and the inter-child spacing.
const MENU_CHROME_H: f32 = 84.0;
/// Minimum breathing room between the menu and the surface edges.
const EDGE_PAD: f32 = 12.0;
/// Nudge above the anchor so the panel centre doesn't sit on the finger.
const ANCHOR_NUDGE_UP: f32 = 32.0;

/// Dense-menu metrics in design px — a context menu doesn't need the
/// touch-target generosity of the stock 56 px list row. Geometry goes
/// through `Length::dp`; fonts stay design px since the raster path
/// multiplies them by the surface scale.
const ROW_H_PX:      f32 = 29.4;
const ITEM_FONT_PX:  f32 = 15.0;
/// Title stripe: app name with the app icon drawn small beside it.
const TITLE_FONT_PX: f32 = 13.5;
pub( crate ) const TITLE_ICON_PX: f32 = 27.0;

impl EditMenu
{
	/// Compute the top-left corner of the panel, clamped inside the
	/// visible surface. The anchor is the centre of the icon the menu
	/// belongs to; we place the menu above and slightly offset so the
	/// user can see the icon the menu refers to.
	fn panel_origin( &self, screen_w: u32, screen_h: u32, rows: usize ) -> ( f32, f32 )
	{
		let d      = ltk::density().max( 1.0 );
		let menu_w = MENU_W * d;
		let menu_h = ( MENU_CHROME_H + rows as f32 * ROW_H_PX ) * d;
		let pad    = EDGE_PAD * d;
		let nudge  = ANCHOR_NUDGE_UP * d;
		let ( ax, ay ) = self.anchor;
		let sw = screen_w as f32;
		let sh = screen_h as f32;
		let min_x = pad;
		let max_x = ( sw - menu_w - pad ).max( min_x );
		let min_y = pad;
		let max_y = ( sh - menu_h - pad ).max( min_y );
		let x = ( ax - menu_w * 0.5 ).clamp( min_x, max_x );
		let y = ( ay - menu_h - nudge ).clamp( min_y, max_y );
		( x, y )
	}

	pub fn view( &self, icon: ( Arc<Vec<u8>>, u32, u32 ), screen_w: u32, screen_h: u32 ) -> ltk::Element<Message>
	{
		let palette = ltk::theme_palette();

		let item = | label: String, msg: Message |
		{
			ltk::list_item::<Message>( label )
				.height( ltk::Length::dp( ROW_H_PX ) )
				.font_size( ITEM_FONT_PX )
				.on_press( msg )
		};

		// Title stripe: small app icon + name, left-aligned. The trailing
		// flex spacer makes the row claim the full column width so the
		// column's default horizontal centering cannot recentre it.
		let ( rgba, iw, ih ) = icon;
		let icon_sz = ltk::Length::dp( TITLE_ICON_PX );
		let title = ltk::row::<Message>()
			.padding( 0.0 )
			.spacing( ltk::Length::dp( 6.0 ) )
			.push( ltk::img_widget( rgba, iw, ih ).size( icon_sz, icon_sz ) )
			.push(
				ltk::text( &self.app_name )
					.size( TITLE_FONT_PX )
					.color( palette.text_primary ),
			)
			.push( ltk::flex( ltk::spacer() ) );

		let temp_only = matches!( self.origin, DragOrigin::Running { .. } );
		let rows      = 1 + if temp_only { 0 } else { 3 } + if self.running { 1 } else { 0 };
		let mut col = ltk::column::<Message>()
			.fit_content()
			.max_width( ltk::Length::dp( MENU_W ) )
			.padding( ltk::Length::dp( 8.0 ) )
			.spacing( ltk::Length::dp( 2.0 ) )
			.push( title )
			.push( ltk::separator() );

		if !temp_only
		{
			col = col.push( item( t!( "editmenu_info" ).to_string(), Message::EditMenuInfo ) );
		}
		if self.running
		{
			col = col.push( item( t!( "editmenu_close" ).to_string(), Message::EditMenuClose ) );
		}
		if !temp_only
		{
			col = col
				.push( item( t!( "editmenu_remove" ).to_string(), Message::EditMenuRemove ) )
				.push( item( t!( "editmenu_uninstall" ).to_string(), Message::EditMenuUninstall ) );
		}
		col = col
			.push( ltk::separator() )
			.push( item( t!( "editmenu_cancel" ).to_string(), Message::EditMenuCancel ) );

		let panel = ltk::container( col )
			.background( palette.surface )
			.padding( ltk::Length::dp( 4.0 ) )
			.radius( 12.0 * ltk::density().max( 1.0 ) );

		// Place the panel at the computed anchor inside a full-surface
		// stack. The stack itself is transparent — the overlay's own
		// `on_dismiss` handles taps on the bare areas.
		let ( x, y ) = self.panel_origin( screen_w, screen_h, rows );
		ltk::stack::<Message>()
			.push_translated( panel, ltk::HAlign::Start, ltk::VAlign::Top, x, y )
			.into()
	}
}
