//! The base message for a server
use std::fmt::Debug;

use nanoservices_utils::errors::NanoServiceError;
use serde::{Deserialize, Serialize};

/// Defines the type of operation that is being performed on the key value store.
///
/// # Fields
/// * `Put`: inserts a value into the key value store
/// * `Putc`: inserts a value into the key value store if the value already exists and is equal to the expected value
/// * `Set`: inserts a value into the key value store event if the key already exists
/// * `Get`: retrieves a value from the key value store
/// * `Del`: deletes a value from the key value store
/// * `Delc`: deletes a value from the key value store if the value already exists and is equal to the expected value
/// * `Delr`: deletes a range of values from the key value store (not yet implemented)
/// * `Scan`: scans the key value store for values within a range of keys
/// * `Keys`: retrieves all the keys from the key value store within a range of keys
/// * `EmptyCommit`: commits a transaction without housing a key value operation in the message to be executed before the commit
/// * `Commit`: commits a transaction with a key value operation in the message to be executed before the commit
/// * `Rollback`: rolls back a transaction
///
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub enum KeyValueOperationType {
    Put,
    Putc,
    Set,
    Get,
    Del,
    Delc,
    Delr,
    Scan,
    Keys,
    EmptyCommit,
    Commit,
    Rollback,
}

// /// The message that is to be serialized and deserialized when being sent between the server and the
// /// client for a key value operation.
// ///
// /// # Notes
// ///
// ///
// /// # Fields
// /// * `key`: the key for the transaction
// /// * `value`: the value to insert into the key value store
// /// * `expected_value`: the expected value to compare with the existing value in the key value store
// /// * `begin`: the beginning key for a range of keys for a key value operation
// /// * `finish`: the ending key for a range of keys for a key value operation
// /// * `values`: a vector of key value pairs that have been retrieved from the key value store
// /// * `kv_operation_type`: the type of transaction to be operated on the key value store
// /// * `limit`: the limit of values to be retrieved from the key value store
// #[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
// pub struct Transaction {
//     pub key: Vec<u8>,
//     pub value: Option<Vec<u8>>,
//     pub expected_value: Option<Vec<u8>>,
//     pub begin: Option<Vec<u8>>,
//     pub finish: Option<Vec<u8>>,
//     pub values: Option<Vec<(Vec<u8>, Vec<u8>)>>,
//     pub kv_operation_type: KeyValueOperationType,
//     pub limit: Option<u32>,
//     pub keys: Option<Vec<Vec<u8>>>,
// }

// impl Transaction {
//     /// Creates a new transaction message with the key and transaction type.
//     ///
//     /// # Arguments
//     /// * `key`: the key for the transaction
//     ///
//     /// # Returns
//     /// * `Transaction`: the transaction message
//     pub fn new(key: Vec<u8>, kv_operation_type: KeyValueOperationType) -> Self {
//         Transaction {
//             key,
//             value: None,
//             expected_value: None,
//             kv_operation_type,
//             begin: None,
//             finish: None,
//             values: None,
//             limit: None,
//             keys: None,
//         }
//     }

//     /// Adds a value to the transaction message.
//     ///
//     /// # Notes
//     /// This should be used if you want to insert a value into the key value store
//     ///
//     /// # Arguments
//     /// * `value`: the value to insert into the key value store
//     ///
//     /// # Returns
//     /// * `Transaction`: the transaction message with the value field populated
//     pub fn with_value(mut self, value: Vec<u8>) -> Self {
//         self.value = Some(value);
//         self
//     }

//     /// Adds an expected value to the transaction message.
//     ///
//     /// # Notes
//     /// This should be used if you want to compare the existing value in the key value store with the expected value
//     ///
//     /// # Arguments
//     /// * `expected_value`: the expected value to compare with the existing value in the key value store
//     ///
//     /// # Returns
//     /// * `Transaction`: the transaction message with the expected value field populated
//     pub fn with_expected_value(mut self, expected_value: Option<Vec<u8>>) -> Self {
//         self.expected_value = expected_value;
//         self
//     }

//     pub fn empty(kv_operation_type: KeyValueOperationType) -> Self {
//         Transaction {
//             key: vec![],
//             value: None,
//             expected_value: None,
//             kv_operation_type,
//             begin: None,
//             finish: None,
//             values: None,
//             limit: None,
//             keys: None,
//         }
//     }
// }

/// The message that is to be serialized and deserialized when being sent between the server and the client.
///
/// # Notes
/// This is needed because internal messages may house things like channel senders and recievers that cannot be
/// sent over to another computer.
///
/// # Fields
/// * `BeginTransaction`: begins a transaction
/// * `SendOperation`: sends a transaction to the server for an existing transaction
/// * `OneShotOperation`: begins a transaction, performs a single key value operation, and then commits the transaction in one message
/// * `ChainedOperations`: begins a transaction, performs multiple key value operations, and then commits the transaction in one message
/// * `CommitTransaction`: performs a key value operation and then commits the transaction
/// * `EmptyCommit`: commits a transaction without housing a key value operation in the message to be executed before the commit
/// * `RollbackTransaction`: rolls back a transaction
/// * `Ping`: pings the server
/// * `Cleanup`: cleans up the transaction by killing all the actors associated with the transaction
/// * `Error`: an error message (usually returned by the server due to a key value operation)
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub enum ServerMessage {
    BeginTransaction(Transaction),
    SendOperation(Transaction),
    OneShotOperation(Transaction),
    ChainedOperations(Vec<Transaction>),
    CommitTransaction(Transaction),
    Ping(usize),
    Error(NanoServiceError),
    // ones below have their own logging format with transaction_id
    EmptyCommit,
    RollbackTransaction,
    Cleanup,
}
