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

/// Reasons [`crate::try_run`] (and therefore [`crate::run`]) can fail
/// to bring up the event loop.
///
/// Every variant maps to a fatal failure during init: the Wayland
/// connection, the calloop event loop, or one of the protocol bindings
/// the runtime cannot operate without (`wl_compositor`, `wl_shm`,
/// `xdg_wm_base`). Once init succeeds, the compositor disconnecting
/// (`BrokenPipe` / `ConnectionReset`) is treated as a clean exit; any
/// other runtime error during the dispatch loop still panics, since the
/// surface is already on screen and the state machine cannot be unwound
/// from this entry point.
///
/// Embedders that want a software-rendered fallback or that need to
/// degrade gracefully should call [`crate::try_run`] and match on the
/// variants instead of letting [`crate::run`] panic.
#[ derive( Debug ) ]
pub enum RunError
{
	/// `WAYLAND_DISPLAY` is unset, the socket is missing, or the
	/// compositor refused the handshake. Includes the detailed reason
	/// from the underlying `wayland-client` error.
	NoWaylandConnection( String ),
	/// The Wayland registry could not be enumerated. Almost always a
	/// compositor / driver bug — the registry is the first thing every
	/// Wayland client touches.
	RegistryInit( String ),
	/// `calloop`'s `EventLoop::try_new` or its Wayland source insertion
	/// failed (typically an `io` error talking to the kernel).
	EventLoop( String ),
	/// A required Wayland protocol is missing from the compositor.
	/// `name` is the wire-format protocol name; `detail` is the
	/// underlying bind error.
	MissingProtocol
	{
		name:   &'static str,
		detail: String,
	},
}

impl std::fmt::Display for RunError
{
	fn fmt( &self, f: &mut std::fmt::Formatter<'_> ) -> std::fmt::Result
	{
		match self
		{
			Self::NoWaylandConnection( d ) =>
				write!( f, "Wayland connection failed: {d}" ),
			Self::RegistryInit( d )        =>
				write!( f, "Wayland registry init failed: {d}" ),
			Self::EventLoop( d )           =>
				write!( f, "event-loop setup failed: {d}" ),
			Self::MissingProtocol { name, detail } =>
				write!( f, "Wayland protocol `{name}` unavailable: {detail}" ),
		}
	}
}

impl std::error::Error for RunError {}
