//! Defines the struct for mapping out the journey for a transaction message. Here we can construct log messages for
//! particular points in the journey of a transaction message.
use crate::messages::server::interface::{
	ServerMessage, ServerTransactionMessage as TransactionData,
};
use crate::messages::server::wrapper::WrappedServerMessage;

/// Represents the journey of a transaction message.
///
/// This enum represents the journey of a transaction message. It is used to log the journey of a transaction message
///
/// # Variants
/// * `SentByTransactionClient`: The transaction message was sent by the transaction client
/// * `RecievedByClientTransactionActor`: The transaction message was recieved by the client transaction actor
/// * `RecievedByClientWriter`: The transaction message was recieved by the client writer
/// * `RecievedByServerReader`: The transaction message was recieved by the server reader
/// * `RecievedByServerRouter`: The transaction message was recieved by the server router
/// * `RecievedByServerTransactionActor`: The transaction message was recieved by the server transaction actor
/// * `RecievedByServerWriter`: The transaction message was recieved by the server writer
/// * `RecievedByClientReader`: The transaction message was recieved by the client reader
/// * `RecievedByClientRouter`: The transaction message was recieved by the client router
/// * `RecievedByClientTransactionActorAgain`: The transaction message was recieved by the client transaction actor again
/// * `RecievedByTransactionClient`: The transaction message was recieved by the transaction client
pub enum TransactionJourney {
	SentByTransactionClient,
	RecievedByClientTransactionActor,
	RecievedByClientWriter,
	RecievedByServerReader,
	RecievedByServerRouter,
	RecievedByServerTransactionActor,
	RecievedByServerWriter,
	RecievedByClientReader,
	RecievedByClientRouter,
	RecievedByClientTransactionActorAgain,
	RecievedByTransactionClient,
}

impl TransactionJourney {
	/// Returns the string representation of the transaction journey.
	///
	/// # Returns
	/// The string representation of the transaction journey
	pub fn as_str(&self) -> &'static str {
		match self {
			TransactionJourney::SentByTransactionClient => "Sent by transaction client",
			TransactionJourney::RecievedByClientTransactionActor => {
				"Recieved by client transaction actor"
			}
			TransactionJourney::RecievedByClientWriter => "Recieved by client writer",
			TransactionJourney::RecievedByServerReader => "Recieved by server reader",
			TransactionJourney::RecievedByServerRouter => "Recieved by server router",
			TransactionJourney::RecievedByServerTransactionActor => {
				"Recieved by server transaction actor"
			}
			TransactionJourney::RecievedByServerWriter => "Recieved by server writer",
			TransactionJourney::RecievedByClientReader => "Recieved by client reader",
			TransactionJourney::RecievedByClientRouter => "Recieved by client router",
			TransactionJourney::RecievedByClientTransactionActorAgain => {
				"Recieved by client transaction actor again"
			}
			TransactionJourney::RecievedByTransactionClient => "Recieved by transaction client",
		}
	}

	/// Returns the log message for the transaction journey.
	///
	/// # Arguments
	/// * `connection_id`: the id of the connection that the transaction message is associated with
	/// * `transaction_id`: the id of the transaction that the transaction message is associated with
	/// * `data`: the data of the transaction message such as the operation type and key value pairs
	/// * `transaction_type`: the type of transaction message which is the key value operation message type
	///
	/// # Returns
	/// The log message for the transaction journey
	fn to_log(
		&self,
		connection_id: &String,
		transaction_id: &Option<String>,
		data: &TransactionData,
		transaction_type: &str,
	) -> String {
		let transaction_id = match transaction_id {
			Some(id) => id,
			None => &"None".to_string(),
		};
		format!(
			"{} transaction: {} => {:?} -> [{}, {}]",
			transaction_type,
			self.as_str(),
			data,
			connection_id,
			transaction_id
		)
	}

	/// Returns the log message for the transaction journey when the transaction message is a begin transaction message.
	///
	/// # Arguments
	/// * `connection_id`: the id of the connection that the transaction message is associated with
	/// * `transaction_id`: the id of the transaction that the transaction message is associated with
	/// * `data`: the data of the transaction message such as the operation type and key value pairs
	///
	/// # Returns
	/// The log message for the transaction journey when the transaction message is a begin transaction message
	pub fn to_begin_log(
		&self,
		connection_id: &String,
		transaction_id: &Option<String>,
		data: &TransactionData,
	) -> String {
		self.to_log(connection_id, transaction_id, data, "begin")
	}

	/// Returns the log message for the transaction journey when the transaction message is a send operation message.
	///
	/// # Arguments
	/// * `connection_id`: the id of the connection that the transaction message is associated with
	/// * `transaction_id`: the id of the transaction that the transaction message is associated with
	/// * `data`: the data of the transaction message such as the operation type and key value pairs
	///
	/// # Returns
	/// The log message for the transaction journey when the transaction message is a send operation message
	pub fn to_send_log(
		&self,
		connection_id: &String,
		transaction_id: &Option<String>,
		data: &TransactionData,
	) -> String {
		self.to_log(connection_id, transaction_id, data, "send")
	}

	/// Returns the log message for the transaction journey when the transaction message is a one-shot operation message.
	///
	/// # Arguments
	/// * `connection_id`: the id of the connection that the transaction message is associated with
	/// * `transaction_id`: the id of the transaction that the transaction message is associated with
	/// * `data`: the data of the transaction message such as the operation type and key value pairs
	///
	/// # Returns
	/// The log message for the transaction journey when the transaction message is a one-shot operation message
	pub fn to_one_shot_log(
		&self,
		connection_id: &String,
		transaction_id: &Option<String>,
		data: &TransactionData,
	) -> String {
		self.to_log(connection_id, transaction_id, data, "one-shot")
	}

	/// Returns the log message for the transaction journey when the transaction message is a commit transaction message.
	///
	/// # Arguments
	/// * `connection_id`: the id of the connection that the transaction message is associated with
	/// * `transaction_id`: the id of the transaction that the transaction message is associated with
	/// * `data`: the data of the transaction message such as the operation type and key value pairs
	///
	/// # Returns
	/// The log message for the transaction journey when the transaction message is a commit transaction message
	pub fn to_commit_log(
		&self,
		connection_id: &String,
		transaction_id: &Option<String>,
		data: &TransactionData,
	) -> String {
		self.to_log(connection_id, transaction_id, data, "commit")
	}

	/// Returns the log message for the transaction journey when the transaction message is a commit transaction message.
	///
	/// # Arguments
	/// * `connection_id`: the id of the connection that the transaction message is associated with
	/// * `transaction_id`: the id of the transaction that the transaction message is associated with
	/// * `data`: the data of the transaction message such as the operation type and key value pairs
	///
	/// # Returns
	/// The log message for the transaction journey when the transaction message is a commit transaction message
	pub fn to_ping_log(
		&self,
		connection_id: &String,
		transaction_id: &Option<String>,
		data: &TransactionData,
	) -> String {
		self.to_log(connection_id, transaction_id, data, "ping")
	}

	/// Returns the log message for the transaction journey when the transaction message is an error message.
	///
	/// # Arguments
	/// * `connection_id`: the id of the connection that the transaction message is associated with
	/// * `transaction_id`: the id of the transaction that the transaction message is associated with
	/// * `data`: the data of the transaction message such as the operation type and key value pairs
	///
	/// # Returns
	/// The log message for the transaction journey when the transaction message is an error message
	pub fn to_error_log(
		&self,
		connection_id: &String,
		transaction_id: &Option<String>,
		data: &TransactionData,
	) -> String {
		self.to_log(connection_id, transaction_id, data, "error")
	}

	/// Returns the log message for the transaction journey when the transaction message is an empty commit message.
	///
	/// # Arguments
	/// * `connection_id`: the id of the connection that the transaction message is associated with
	/// * `transaction_id`: the id of the transaction that the transaction message is associated with
	///
	/// # Returns
	/// The log message for the transaction journey when the transaction message is an empty commit message
	pub fn to_empty_commit_log(
		&self,
		connection_id: &String,
		transaction_id: &Option<String>,
	) -> String {
		let placeholder = TransactionData::EmptyCommit;
		self.to_log(connection_id, transaction_id, &placeholder, "empty-commit")
	}

	/// Returns the log message for the transaction journey when the transaction message is a rollback message.
	///
	/// # Arguments
	/// * `connection_id`: the id of the connection that the transaction message is associated with
	/// * `transaction_id`: the id of the transaction that the transaction message is associated with
	///
	/// # Returns
	/// The log message for the transaction journey when the transaction message is a rollback message
	pub fn to_rollback_log(
		&self,
		connection_id: &String,
		transaction_id: &Option<String>,
	) -> String {
		let placeholder = TransactionData::Rollback;
		self.to_log(connection_id, transaction_id, &placeholder, "rollback")
	}

	/// Returns the log message for the transaction journey when the transaction message is a rollback message.
	///
	/// # Arguments
	/// * `message`: the transaction message to be processed and unwrapped
	///
	/// # Returns
	/// The log message for the transaction journey if the message is a transaction message
	pub fn from_wrapped_server_message(&self, message: &WrappedServerMessage) -> Option<String> {
		match &message.message {
			ServerMessage::BeginTransaction(trans) => {
				Some(self.to_begin_log(&message.connection_id, &message.transaction_id, trans))
			}
			ServerMessage::SendOperation(trans) => {
				Some(self.to_send_log(&message.connection_id, &message.transaction_id, trans))
			}
			ServerMessage::OneShotOperation(trans) => {
				Some(self.to_one_shot_log(&message.connection_id, &message.transaction_id, trans))
			}
			ServerMessage::CommitTransaction(trans) => {
				Some(self.to_commit_log(&message.connection_id, &message.transaction_id, trans))
			}
			ServerMessage::EmptyCommit => {
				Some(self.to_empty_commit_log(&message.connection_id, &message.transaction_id))
			}
			ServerMessage::RollbackTransaction => {
				Some(self.to_rollback_log(&message.connection_id, &message.transaction_id))
			}
			_ => None,
		}
	}
}
