// SPDX-License-Identifier: LGPL-2.1-only
// Copyright (C) 2026 Liberux Labs, S. L. <info@liberux.net>

use smithay_client_toolkit::seat::keyboard::{ KeyEvent, Keysym };

use crate::app::App;
use crate::event_loop::{ AppData, SurfaceFocus };
use crate::tree::find_handlers;

impl<A: App> AppData<A>
{
	pub( super ) fn handle_key_backspace( &mut self, focus: SurfaceFocus, event: &KeyEvent )
	{
		let focused = self.surface( focus ).focused_idx;
		if focused.is_some() { self.handle_backspace( focus ); }
		else if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed )
		{
			self.pending_msgs.push( msg );
		}
	}

	pub( super ) fn handle_key_delete( &mut self, focus: SurfaceFocus, event: &KeyEvent )
	{
		let focused = self.surface( focus ).focused_idx;
		// Supr / Forward-Delete: same shape as Backspace but
		// removes the char *after* the cursor. When no widget
		// is focused, the keysym bubbles to the app.
		if focused.is_some() { self.handle_delete_forward( focus ); }
		else if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed )
		{
			self.pending_msgs.push( msg );
		}
	}

	pub( super ) fn handle_key_return( &mut self, focus: SurfaceFocus, event: &KeyEvent )
	{
		let focused = self.surface( focus ).focused_idx;
		// Enter targets, in order: (a) the focused widget's submit
		// message (TextEdit), (b) its press message (Button etc),
		// (c) the press message of the keyboard-hovered list item
		// in the topmost scroll. The hovered fallback lets users
		// confirm a combo / list choice with the keyboard after
		// arrow-navigating to it without ever taking widget focus.
		//
		// Multiline text-input override: when the focused widget
		// is a `text_edit().multiline( true )`, Enter inserts a
		// literal `\n` into the buffer instead of submitting, so
		// the user can compose paragraphs.
		let is_multi = focused.and_then( |idx|
			find_handlers( &self.surface( focus ).frame.widget_rects, idx )
				.map( |h| h.is_multiline_text_input() ) ).unwrap_or( false );
		if is_multi
		{
			self.handle_text_insert( focus, "\n" );
		} else {
			let target = focused.or( self.surface( focus ).hovered_idx );
			let mut handled = false;
			if let Some( idx ) = target
			{
				let msg = find_handlers( &self.surface( focus ).frame.widget_rects, idx )
					.and_then( |h| h.submit_msg().or_else( || h.press_msg() ) );
				if let Some( m ) = msg
				{
					self.pending_msgs.push( m );
					handled = true;
				}
			}
			if !handled
			{
				if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed )
				{
					self.pending_msgs.push( msg );
				}
			}
		}
	}

	pub( super ) fn handle_key_arrow_vertical( &mut self, focus: SurfaceFocus, event: &KeyEvent )
	{
		let focused = self.surface( focus ).focused_idx;
		let is_text = focused.and_then( |idx|
			find_handlers( &self.surface( focus ).frame.widget_rects, idx )
				.map( |h| h.is_text_input() ) ).unwrap_or( false );
		let reverse  = event.keysym == Keysym::Up;
		let extend   = self.shift_pressed;
		let intercepted = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed );
		if let Some( msg ) = intercepted
		{
			self.pending_msgs.push( msg );
		}
		else
		{
			let consumed = if is_text
			{
				if reverse { self.handle_cursor_up( focus, extend ) }
				else       { self.handle_cursor_down( focus, extend ) }
			} else { false };
			if !consumed && !self.move_keyboard_hover( focus, reverse )
			{
				// already None, no extra fire
			}
		}
	}

	pub( super ) fn handle_key_arrow_horizontal( &mut self, focus: SurfaceFocus, event: &KeyEvent )
	{
		let focused = self.surface( focus ).focused_idx;
		let is_text = focused.and_then( |idx|
			find_handlers( &self.surface( focus ).frame.widget_rects, idx )
				.map( |h| h.is_text_input() ) ).unwrap_or( false );
		let extend = self.shift_pressed;
		let intercepted = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed );
		if let Some( msg ) = intercepted
		{
			self.pending_msgs.push( msg );
		}
		else if is_text
		{
			if event.keysym == Keysym::Left
			{
				self.handle_cursor_left( focus, extend );
			} else {
				self.handle_cursor_right( focus, extend );
			}
		}
	}

	pub( super ) fn handle_key_home( &mut self, focus: SurfaceFocus )
	{
		let focused = self.surface( focus ).focused_idx;
		let is_text = focused.and_then( |idx|
			find_handlers( &self.surface( focus ).frame.widget_rects, idx )
				.map( |h| h.is_text_input() ) ).unwrap_or( false );
		if is_text { self.handle_cursor_home( focus, self.shift_pressed ); }
	}

	pub( super ) fn handle_key_end( &mut self, focus: SurfaceFocus )
	{
		let focused = self.surface( focus ).focused_idx;
		let is_text = focused.and_then( |idx|
			find_handlers( &self.surface( focus ).frame.widget_rects, idx )
				.map( |h| h.is_text_input() ) ).unwrap_or( false );
		if is_text { self.handle_cursor_end( focus, self.shift_pressed ); }
	}

	pub( super ) fn handle_key_space( &mut self, focus: SurfaceFocus, event: &KeyEvent )
	{
		let focused = self.surface( focus ).focused_idx;
		if let Some( idx ) = focused
		{
			let press = find_handlers( &self.surface( focus ).frame.widget_rects, idx )
				.and_then( |h| h.press_msg() );
			if let Some( msg ) = press
			{
				self.pending_msgs.push( msg );
			} else {
				// Focused widget is a TextEdit (or has no on_press) — insert space as text
				self.handle_text_insert( focus, " " );
			}
		} else if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, self.ctrl_pressed, self.shift_pressed )
		{
			self.pending_msgs.push( msg );
		}
	}

	pub( super ) fn handle_key_default( &mut self, focus: SurfaceFocus, event: &KeyEvent )
	{
		let focused = self.surface( focus ).focused_idx;
		if self.ctrl_pressed
		{
			if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, true, self.shift_pressed )
			{
				self.pending_msgs.push( msg );
			}
		} else if focused.is_some()
		{
			if let Some( txt ) = event.utf8.clone()
			{
				if !txt.is_empty() && txt.chars().all( |c| !c.is_control() )
				{
					self.handle_text_insert( focus, &txt );
				}
			}
		} else if let Some( msg ) = self.app.on_key_with_modifiers( event.keysym, false, self.shift_pressed )
		{
			self.pending_msgs.push( msg );
		}
	}
}
