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

use crate::types::Point;

/// Result of [`GestureState::on_press`]. Handler uses `hit_idx` to set
/// keyboard focus; pushes `initial_slider_msg` to the pending queue
/// when present.
pub struct PressOutcome<Msg>
{
	pub hit_idx:            Option<usize>,
	pub initial_slider_msg: Option<Msg>,
}

/// Result of [`GestureState::on_move`]. Handler turns this into app
/// callbacks + redraw flags.
pub enum MoveOutcome<Msg>
{
	/// Nothing gesture-level fired. Hovered index may still have
	/// changed — pointer handler updates it separately before calling
	/// on_move.
	Idle,
	/// Long-press drag in flight — fire `app.on_drag_move(pos)`.
	Drag   { pos: Point },
	/// Slider value changed. `None` when the slider has no change
	/// handler for this value (typically unreachable — sliders always
	/// carry a change msg — but the gesture machine stays general).
	Slider { msg: Option<Msg> },
	/// Scroll viewport offset updated. Handler just requests a redraw.
	Scroll,
	/// Vertical scroll pinned at the top while the finger keeps pulling
	/// down: `progress` is the accumulated overscroll as a fraction of
	/// surface height. Handler fires `app.on_overscroll_down_progress`.
	OverscrollDown { progress: f32 },
	/// Swipe progress. Each axis is `Some(value)` when it has a valid
	/// progress reading for this move (not every motion updates all
	/// axes). Handler fires the matching app callback.
	Swipe  { up: Option<f32>, down: Option<f32>, horizontal: Option<f32> },
}

/// Events emitted by [`GestureState::on_release`], in the order the
/// handler should dispatch them. Multiple events per release are
/// possible (see the horizontal fall-through case).
pub enum ReleaseEvent<Msg>
{
	/// Long-press drop — `app.on_drop(pos)`, kick main redraw, clear
	/// long-press drag.
	Drop { pos: Point },
	/// Horizontal swipe committed left.
	SwipeLeft,
	/// Horizontal swipe committed right.
	SwipeRight,
	/// Vertical swipe committed up.
	SwipeUp,
	/// Vertical swipe committed down.
	SwipeDown,
	/// Released after a top overscroll pull-down — fire
	/// `app.on_overscroll_down(committed)`. `committed` is set when the
	/// pull passed `overscroll_thresh` of surface height.
	OverscrollDown { committed: bool },
	/// Horizontal swipe did not commit — fire
	/// `app.on_swipe_horizontal_progress(0.0)` + main redraw.
	HorizontalFellThrough,
	/// Vertical swipe did not commit — fire
	/// `app.on_swipe_progress(0.0)` + `app.on_swipe_down_progress(0.0)`.
	VerticalFellThrough,
	/// Push a widget-level message (button press or final slider
	/// value on release).
	PushMsg( Msg ),
	/// Release on empty area — handler calls `app.on_tap()` on Main
	/// focus or `overlay_dismiss_msg(id)` on Overlay focus.
	EmptyRelease,
}

/// Swipe thresholds + surface dimensions snapshotted from the app +
/// current surface, passed into gesture methods so the machine stays
/// decoupled from `App` and `SurfaceState`.
pub struct SwipeConfig
{
	/// Up-swipe commit fraction of surface height (e.g. 0.3 = 30 %).
	pub up_thresh:         f32,
	/// Down-swipe commit fraction of surface height.
	pub down_thresh:       f32,
	/// Down-swipe start zone fraction — the press must land within
	/// `surface_height * down_edge` of the top for a down-swipe to
	/// arm.
	pub down_edge:         f32,
	/// Horizontal commit fraction of surface width.
	pub horizontal_thresh: f32,
	/// Top-overscroll dismiss commit fraction of surface height — the
	/// pull-down past a scroll's top must exceed this to commit.
	pub overscroll_thresh: f32,
	pub surface_width:     u32,
	pub surface_height:    u32,
}
