// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// Copyright by contributors to this project.
// SPDX-License-Identifier: (Apache-2.0 OR MIT)

use crate::{
    client::MlsError,
    group::{framing::MlsMessage, message_processor::validate_key_package, ExportedTree},
    KeyPackage,
};

pub mod builder;
mod config;
mod group;

pub(crate) use config::ExternalClientConfig;
use mls_rs_core::{
    crypto::{CryptoProvider, SignatureSecretKey},
    identity::SigningIdentity,
};

use builder::{ExternalBaseConfig, ExternalClientBuilder};

pub use group::{ExternalGroup, ExternalReceivedMessage, ExternalSnapshot};

/// A client capable of observing a group's state without having
/// private keys required to read content.
///
/// This structure is useful when an application is sending
/// plaintext control messages in order to allow a central server
/// to facilitate communication between users.
///
/// # Warning
///
/// This structure will only be able to observe groups that were
/// created by clients that have the `encrypt_control_messages`
/// option returned by [`MlsRules::encryption_options`](`crate::MlsRules::encryption_options`)
/// set to `false`. Any control messages that are sent encrypted
/// over the wire will break the ability of this client to track
/// the resulting group state.
pub struct ExternalClient<C> {
    config: C,
    signing_data: Option<(SignatureSecretKey, SigningIdentity)>,
}

impl ExternalClient<()> {
    pub fn builder() -> ExternalClientBuilder<ExternalBaseConfig> {
        ExternalClientBuilder::new()
    }
}

impl<C> ExternalClient<C>
where
    C: ExternalClientConfig + Clone,
{
    pub(crate) fn new(
        config: C,
        signing_data: Option<(SignatureSecretKey, SigningIdentity)>,
    ) -> Self {
        Self {
            config,
            signing_data,
        }
    }

    /// Begin observing a group based on a GroupInfo message created by
    /// [Group::group_info_message](crate::group::Group::group_info_message)
    ///
    ///`tree_data` is required to be provided out of band if the client that
    /// created GroupInfo message did not did not use the `ratchet_tree_extension`
    /// according to [`MlsRules::commit_options`](crate::MlsRules::commit_options)
    /// at the time the welcome message
    /// was created. `tree_data` can be exported from a group using the
    /// [export tree function](crate::group::Group::export_tree).
    #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
    pub async fn observe_group(
        &self,
        group_info: MlsMessage,
        tree_data: Option<ExportedTree<'_>>,
    ) -> Result<ExternalGroup<C>, MlsError> {
        ExternalGroup::join(
            self.config.clone(),
            self.signing_data.clone(),
            group_info,
            tree_data,
        )
        .await
    }

    /// Load an existing observed group by loading a snapshot that was
    /// generated by
    /// [ExternalGroup::snapshot](self::ExternalGroup::snapshot).
    #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
    pub async fn load_group(
        &self,
        snapshot: ExternalSnapshot,
    ) -> Result<ExternalGroup<C>, MlsError> {
        ExternalGroup::from_snapshot(self.config.clone(), snapshot).await
    }

    #[cfg_attr(not(mls_build_async), maybe_async::must_be_sync)]
    pub async fn validate_key_package(
        &self,
        key_package: MlsMessage,
    ) -> Result<KeyPackage, MlsError> {
        let version = key_package.version;

        let key_package = key_package
            .into_key_package()
            .ok_or(MlsError::UnexpectedMessageType)?;

        let cs = self
            .config
            .crypto_provider()
            .cipher_suite_provider(key_package.cipher_suite)
            .ok_or(MlsError::UnsupportedCipherSuite(key_package.cipher_suite))?;

        let id = self.config.identity_provider();

        validate_key_package(&key_package, version, &cs, &id).await?;

        Ok(key_package)
    }
}

#[cfg(test)]
pub(crate) mod tests_utils {
    use crate::{
        client::test_utils::{TEST_CIPHER_SUITE, TEST_PROTOCOL_VERSION},
        key_package::test_utils::test_key_package_message,
    };

    pub use super::builder::test_utils::*;

    #[maybe_async::test(not(mls_build_async), async(mls_build_async, crate::futures_test))]
    async fn external_client_can_validate_key_package() {
        let kp = test_key_package_message(TEST_PROTOCOL_VERSION, TEST_CIPHER_SUITE, "john").await;
        let server = TestExternalClientBuilder::new_for_test().build();
        let validated_kp = server.validate_key_package(kp.clone()).await.unwrap();

        assert_eq!(kp.into_key_package().unwrap(), validated_kp);
    }
}
