//! Host-supplied configuration for [`PackedArea`](crate::render::packed::PackedArea).
//! Today just keybinds; passed once as a prop. Binds match the **produced character**
//! (`KeyboardEvent.key()`), so they follow the user's keyboard layout instead of a hardcoded
//! QWERTY physical position.

/// A single chord: the character the key produces, plus the non-shift modifiers held. Shift is
/// already baked into `key` (`"u"` vs `"U"`), so it isn't a separate flag.
#[derive(Clone, Copy, PartialEq)]
pub struct Keybind {
	/// Matched verbatim against `KeyboardEvent.key()` — e.g. `"u"`, `"U"`, `"Delete"`, `"f"`.
	pub key: &'static str,
	pub alt: bool,
	pub ctrl: bool,
}

impl Keybind {
	#[cfg(target_arch = "wasm32")]
	pub(crate) fn matches(&self, key: &str, alt: bool, ctrl: bool) -> bool {
		self.key == key && self.alt == alt && self.ctrl == ctrl
	}
}

/// Chords acting on the layout / the focused pane. Defaults: `u` / `U` for the undo tree,
/// `Backspace` to close the focused pane, `f` to toggle maximize on it, `?` for the keybind hint.
/// They never fire while an editable field is focused (see the listener), so bare letters don't
/// hijack typing.
#[derive(Clone, Copy, PartialEq)]
pub struct Keybinds {
	pub undo: Keybind = Keybind { key: "u", alt: false, ctrl: false },
	pub redo: Keybind = Keybind { key: "U", alt: false, ctrl: false },
	pub close: Keybind = Keybind { key: "Backspace", alt: false, ctrl: false },
	pub maximize: Keybind = Keybind { key: "f", alt: false, ctrl: false },
	pub help: Keybind = Keybind { key: "?", alt: false, ctrl: false },
}

impl Default for Keybinds {
	fn default() -> Self {
		Self { .. }
	}
}

#[derive(Clone, Default, PartialEq)]
pub struct Config {
	pub keybinds: Keybinds,
	/// Host-registered chords, each running arbitrary code over the live layout. Built-ins win on
	/// collision (the listener tries them first); the closure gets the same [`PackedApi`] `on_ready`
	/// hands out, so it can `save()` the current layout. A bare `Vec` is the whole API.
	pub actions: Vec<(Keybind, dioxus::prelude::Callback<crate::render::packed::PackedApi>)>,
	/// How many grid steps span the container's width. Fixed (not derived from font size): the
	/// rendered horizontal step is `container_width / steps`, so the layout always stretches to fill —
	/// wider container ⇒ bigger steps, narrower ⇒ smaller, the same tiles either way. A finer grid
	/// (more steps) gives smaller resize/placement increments.
	pub steps: u32 = 64,
	/// How many grid steps span the container's height — the vertical twin of [`steps`](Self::steps).
	/// The rendered vertical step is `container_height / rows`, so a tile's height tracks the
	/// container's height just as its width tracks the container's width (shorter container ⇒ shorter
	/// tiles). Dividing by a *fixed* row count (not the layout's used rows) keeps the whitespace-below
	/// look: a layout shorter than `rows` leaves the slack empty. The default ≈ a square step on a
	/// 16∶9 container (`64 × 9/16`).
	pub rows: u32 = 36,
}
