//! Telephony backend abstraction.
//!
//! The trait below is intentionally synchronous and poll-based rather
//! than async. The UI layer (LTK + calloop) is single-threaded and does
//! not host an async runtime; the real ModemManager backend (Fase 2)
//! will run its zbus loop on a dedicated thread and forward events
//! through a channel that the trait's `poll_events` drains.

use crate::types::{ CallId, CallState, PhoneNumber };

pub mod modemmanager;

#[ derive( Clone, Debug ) ]
pub enum CallEvent
{
	/// A new incoming call appeared. The id is allocated by the backend.
	Incoming
	{
		id:     CallId,
		number: PhoneNumber,
	},
	/// State of an existing call changed.
	StateChanged
	{
		id:    CallId,
		state: CallState,
	},
	/// Backend lost connection to the modem (e.g. ModemManager
	/// restarted, modem unplugged). UI should surface this.
	BackendUnavailable,
	/// Backend recovered after a previous BackendUnavailable.
	BackendAvailable,
}

#[ derive( Clone, Debug ) ]
pub enum CallError
{
	/// No modem registered or modem busy.
	NoModem,
	/// The supplied number is malformed.
	InvalidNumber,
	/// The call id was unknown to the backend.
	UnknownCall,
	/// Generic backend failure with a human-readable message.
	Backend( String ),
}

/// Operations the UI can request on the telephony stack.
///
/// All methods return immediately. Side effects materialise as
/// `CallEvent`s on a subsequent `poll_events` call.
pub trait CallBackend
{
	fn dial( &mut self, number: &PhoneNumber ) -> Result<CallId, CallError>;
	fn accept( &mut self, id: CallId ) -> Result<(), CallError>;
	fn hangup( &mut self, id: CallId ) -> Result<(), CallError>;
	fn reject( &mut self, id: CallId ) -> Result<(), CallError>;
	fn send_dtmf( &mut self, id: CallId, tone: char ) -> Result<(), CallError>;
	fn set_mute( &mut self, id: CallId, muted: bool ) -> Result<(), CallError>;

	/// Drain queued events. Called from the UI poll tick.
	fn poll_events( &mut self ) -> Vec<CallEvent>;
}
