// Copyright (c) 2026, Salesforce, Inc.,
// All rights reserved.
// For full license text, see the LICENSE.txt file

use crate::DataStorageError;
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;

/// This enum is used to wrap the errors returned by the format implementations. In case no format
/// is configured, the legacy Serialization(bincode) error will be returned or
/// the new Format(Box<dyn Error>) will be used.
#[derive(Debug)]
pub(crate) enum FormatWrapper<F: Format> {
    Default(DefaultFormat, PhantomData<F>),
    #[cfg(feature = "experimental_datastorage_formats")]
    Custom(F),
}

impl<F: Format + Clone> Clone for FormatWrapper<F> {
    fn clone(&self) -> Self {
        match self {
            FormatWrapper::Default(format, _) => {
                FormatWrapper::Default(format.clone(), PhantomData)
            }
            #[cfg(feature = "experimental_datastorage_formats")]
            FormatWrapper::Custom(format) => FormatWrapper::Custom(format.clone()),
        }
    }
}

impl<F: Format> FormatWrapper<F> {
    pub fn serialize<T: Serialize>(&self, item: &T) -> Result<Vec<u8>, DataStorageError> {
        match self {
            FormatWrapper::Default(format, _) => Ok(format.serialize(item)?),
            #[cfg(feature = "experimental_datastorage_formats")]
            FormatWrapper::Custom(format) => format
                .serialize(item)
                .map_err(|e| DataStorageError::Format(e.into())),
        }
    }

    pub fn deserialize<'a, T>(&self, bytes: &'a [u8]) -> Result<T, DataStorageError>
    where
        T: Deserialize<'a>,
    {
        match self {
            FormatWrapper::Default(format, _) => Ok(format.deserialize(bytes)?),
            #[cfg(feature = "experimental_datastorage_formats")]
            FormatWrapper::Custom(format) => format
                .deserialize(bytes)
                .map_err(|e| DataStorageError::Format(e.into())),
        }
    }
}

pub trait Format {
    type SerializeError: Into<Box<dyn std::error::Error>>;
    type DeserializeError: Into<Box<dyn std::error::Error>>;

    fn serialize<T: Serialize>(&self, item: &T) -> Result<Vec<u8>, Self::SerializeError>;

    fn deserialize<'a, T>(&self, bytes: &'a [u8]) -> Result<T, Self::DeserializeError>
    where
        T: Deserialize<'a>;
}

pub(super) type DefaultFormat = Bincode;

#[derive(Debug, Default, Clone)]
pub struct Bincode {
    // Reserved for internal status
    _priv: (),
}

impl Format for Bincode {
    type SerializeError = bincode::Error;
    type DeserializeError = bincode::Error;

    fn serialize<T: serde::Serialize>(&self, item: &T) -> Result<Vec<u8>, Self::SerializeError> {
        bincode::serialize(item)
    }

    fn deserialize<'a, T>(&self, bytes: &'a [u8]) -> Result<T, Self::SerializeError>
    where
        T: Deserialize<'a>,
    {
        bincode::deserialize(bytes)
    }
}

#[cfg(feature = "experimental_datastorage_formats")]
#[derive(Debug, Default, Clone)]
pub struct MessagePack {
    // Reserved for internal status
    _priv: (),
}

#[cfg(feature = "experimental_datastorage_formats")]
impl Format for MessagePack {
    type SerializeError = rmp_serde::encode::Error;
    type DeserializeError = rmp_serde::decode::Error;

    fn serialize<T: serde::Serialize>(&self, item: &T) -> Result<Vec<u8>, Self::SerializeError> {
        rmp_serde::to_vec(item)
    }

    fn deserialize<'a, T>(&self, bytes: &'a [u8]) -> Result<T, Self::DeserializeError>
    where
        T: Deserialize<'a>,
    {
        rmp_serde::from_slice(bytes)
    }
}
