use std::collections::BTreeSet;
use std::iter::once;
use std::sync::Arc;

use hashbrown::HashSet;

use crate::event::{CreateEvent, ModifyEvent};
use crate::modify::Modify;
use crate::plugins::Plugin;
use crate::prelude::*;

// This module has some special properties around it's operation, namely that it
// has to make a certain number of assertions *early* in the entry lifecycle around
// names and uuids since these have such significance to every other part of the
// servers operation. As a result, this is the ONLY PLUGIN that does validation in the
// pre_create_transform step, where every other SHOULD use the post_* hooks for all
// validation operations.
//
// Additionally, this plugin WILL block and deny certain modifications to uuids and
// more to prevent intentional DB damage.

pub struct Base {}

impl Plugin for Base {
    fn id() -> &'static str {
        "plugin_base"
    }

    #[instrument(level = "debug", name = "base_pre_create_transform", skip_all)]
    #[allow(clippy::cognitive_complexity)]
    fn pre_create_transform(
        qs: &mut QueryServerWriteTransaction,
        cand: &mut Vec<EntryInvalidNew>,
        ce: &CreateEvent,
    ) -> Result<(), OperationError> {
        // debug!("Entering base pre_create_transform");
        // For each candidate
        for entry in cand.iter_mut() {
            // First, ensure we have the 'object', class in the class set.
            entry.add_ava(Attribute::Class, EntryClass::Object.to_value());

            // if they don't have uuid, create it.
            match entry.get_ava_set(Attribute::Uuid).map(|s| s.len()) {
                None => {
                    // Generate
                    let ava_uuid = Value::Uuid(Uuid::new_v4());
                    trace!("Setting temporary UUID {:?} to entry", ava_uuid);
                    entry.set_ava(&Attribute::Uuid, once(ava_uuid));
                }
                Some(1) => {
                    // Do nothing
                }
                Some(x) => {
                    // If we get some it MUST be 2 +
                    admin_error!(
                        "Entry defines {} attr, but has multiple ({}) values.",
                        Attribute::Uuid,
                        x
                    );
                    return Err(OperationError::Plugin(PluginError::Base(
                        "Uuid has multiple values".to_string(),
                    )));
                }
            };
        }

        // Now, every cand has a UUID - create a cand uuid set from it.
        let mut cand_uuid: BTreeSet<Uuid> = BTreeSet::new();

        let mut system_range_invalid = false;

        // As we insert into the set, if a duplicate is found, return an error
        // that a duplicate exists.
        //
        // Remember, we have to use the ava here, not the get_uuid types because
        // we may not have filled in the uuid field yet.
        for entry in cand.iter_mut() {
            let uuid_ref: Uuid = entry
                .get_ava_single_uuid(Attribute::Uuid)
                .ok_or_else(|| OperationError::InvalidAttribute(Attribute::Uuid.to_string()))?;

            // Check that the system-protected range is not in the cand_uuid, unless we are
            // an internal operation.
            if uuid_ref < DYNAMIC_RANGE_MINIMUM_UUID {
                if ce.ident.is_internal() {
                    // it's a builtin entry, lets add the class.
                    entry.add_ava(Attribute::Class, EntryClass::Builtin.to_value());
                } else {
                    // Don't do that!
                    error!(
                        "uuid from protected system UUID range found in create set! {:?}",
                        uuid_ref
                    );
                    system_range_invalid = true;
                }
            };

            if !cand_uuid.insert(uuid_ref) {
                trace!("uuid duplicate found in create set! {:?}", uuid_ref);
                return Err(OperationError::Plugin(PluginError::Base(
                    "Uuid duplicate detected in request".to_string(),
                )));
            }
        }

        if system_range_invalid {
            return Err(OperationError::Plugin(PluginError::Base(
                "Uuid must not be in protected range".to_string(),
            )));
        }

        if cand_uuid.contains(&UUID_DOES_NOT_EXIST) {
            error!(
                "uuid \"does not exist\" found in create set! THIS IS A BUG. PLEASE REPORT IT IMMEDIATELY."
            );
            return Err(OperationError::Plugin(PluginError::Base(
                "Attempt to create UUID_DOES_NOT_EXIST".to_string(),
            )));
        }

        // Now from each element, generate a filter to search for all of them
        //
        // IMPORTANT: We don't exclude recycled or tombstones here!
        let filt_in = filter_all!(FC::Or(
            cand_uuid
                .into_iter()
                .map(|u| FC::Eq(Attribute::Uuid, PartialValue::Uuid(u)))
                .collect(),
        ));

        // If any results exist, fail as a duplicate UUID is present.
        // TODO #69: Can we report which UUID exists? Probably yes, we do
        // internal search and report the UUID *OR* we alter internal_exists
        // to return UUID sets. This can be done as an extension to #69 where the
        // internal exists is actually a wrapper around a search for uuid internally
        //
        // But does it add value? How many people will try to custom define/add uuid?
        let r = qs.internal_exists(&filt_in);

        match r {
            Ok(b) => {
                if b {
                    admin_error!("A UUID already exists, rejecting.");
                    return Err(OperationError::Plugin(PluginError::Base(
                        "Uuid duplicate found in database".to_string(),
                    )));
                }
            }
            Err(e) => {
                admin_error!("Error occurred checking UUID existence. {:?}", e);
                return Err(e);
            }
        }

        Ok(())
    }

    #[instrument(level = "debug", name = "base_pre_modify", skip_all)]
    fn pre_modify(
        _qs: &mut QueryServerWriteTransaction,
        _pre_cand: &[Arc<EntrySealedCommitted>],
        cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
        me: &ModifyEvent,
    ) -> Result<(), OperationError> {
        for entry in cand.iter_mut() {
            // Ensure we have the 'object', class in the class set.
            entry.add_ava_if_not_exist(Attribute::Class, EntryClass::Object.to_value());
        }

        me.modlist.iter().try_for_each(|modify| {
            let attr = match &modify {
                Modify::Present(a, _)
                | Modify::Removed(a, _)
                | Modify::Purged(a)
                | Modify::Set(a, _) => Some(a),
                Modify::Assert(_, _) => None,
            };
            if attr == Some(&Attribute::Uuid) {
                debug!(?modify, "Modify in violation");
                request_error!("Modifications to UUID's are NOT ALLOWED");
                Err(OperationError::SystemProtectedAttribute)
            } else {
                Ok(())
            }
        })
    }

    #[instrument(level = "debug", name = "base_pre_modify", skip_all)]
    fn pre_batch_modify(
        _qs: &mut QueryServerWriteTransaction,
        _pre_cand: &[Arc<EntrySealedCommitted>],
        cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
        me: &BatchModifyEvent,
    ) -> Result<(), OperationError> {
        for entry in cand.iter_mut() {
            // Ensure we have the 'object', class in the class set.
            entry.add_ava_if_not_exist(Attribute::Class, EntryClass::Object.to_value());
        }

        me.modset
            .values()
            .flat_map(|ml| ml.iter())
            .try_for_each(|modify| {
                let attr = match &modify {
                    Modify::Present(a, _)
                    | Modify::Removed(a, _)
                    | Modify::Set(a, _)
                    | Modify::Purged(a) => Some(a),
                    Modify::Assert(_, _) => None,
                };
                if attr == Some(&Attribute::Uuid) {
                    debug!(?modify, "Modify in violation");
                    request_error!("Modifications to UUID's are NOT ALLOWED");
                    Err(OperationError::SystemProtectedAttribute)
                } else {
                    Ok(())
                }
            })
    }

    #[instrument(level = "debug", name = "base::verify", skip_all)]
    fn verify(qs: &mut QueryServerReadTransaction) -> Vec<Result<(), ConsistencyError>> {
        // Search for class = *
        let entries = match qs.internal_search(filter!(f_pres(Attribute::Class))) {
            Ok(v) => v,
            Err(e) => {
                admin_error!("Internal Search Failure: {:?}", e);
                return vec![Err(ConsistencyError::QueryServerSearchFailure)];
            }
        };

        let mut uuid_seen: HashSet<Uuid> = HashSet::with_capacity(entries.len());

        entries
            .iter()
            // do an exists checks on the uuid
            .map(|e| {
                // To get the entry deserialised, a UUID MUST EXIST, else an expect
                // will be thrown in the deserialise (possibly it will be better
                // handled later). But it means this check only needs to validate
                // uniqueness!
                let uuid = e.get_uuid();

                if uuid_seen.insert(uuid) {
                    // Insert returns true if the item was unique.
                    Ok(())
                } else {
                    Err(ConsistencyError::UuidNotUnique(uuid.to_string()))
                }
            })
            .filter(|v| v.is_err())
            .collect()
    }
}

#[cfg(test)]
mod tests {
    use crate::prelude::*;
    use std::sync::Arc;

    const UUID_TEST_ACCOUNT: Uuid = uuid::uuid!("cc8e95b4-c24f-4d68-ba54-8bed76f63930");
    const UUID_TEST_GROUP: Uuid = uuid::uuid!("81ec1640-3637-4a2f-8a52-874fa3c3c92f");
    const UUID_TEST_ACP: Uuid = uuid::uuid!("acae81d6-5ea7-4bd8-8f7f-fcec4c0dd647");

    pub static TEST_ACCOUNT: LazyLock<EntryInitNew> = LazyLock::new(|| {
        entry_init_fn([
            (Attribute::Class, EntryClass::Account.to_value()),
            (Attribute::Class, EntryClass::ServiceAccount.to_value()),
            (Attribute::Class, EntryClass::MemberOf.to_value()),
            (Attribute::Name, Value::new_iname("test_account_1")),
            (Attribute::DisplayName, Value::new_utf8s("test_account_1")),
            (Attribute::Uuid, Value::Uuid(UUID_TEST_ACCOUNT)),
            (Attribute::MemberOf, Value::Refer(UUID_TEST_GROUP)),
        ])
    });
    pub static TEST_GROUP: LazyLock<EntryInitNew> = LazyLock::new(|| {
        entry_init_fn([
            (Attribute::Class, EntryClass::Group.to_value()),
            (Attribute::Name, Value::new_iname("test_group_a")),
            (Attribute::Uuid, Value::Uuid(UUID_TEST_GROUP)),
            (Attribute::Member, Value::Refer(UUID_TEST_ACCOUNT)),
        ])
    });
    pub static ALLOW_ALL: LazyLock<EntryInitNew> = LazyLock::new(|| {
        entry_init_fn([
            (Attribute::Class, EntryClass::Object.to_value()),
            (
                Attribute::Class,
                EntryClass::AccessControlProfile.to_value(),
            ),
            (
                Attribute::Class,
                EntryClass::AccessControlTargetScope.to_value(),
            ),
            (
                Attribute::Class,
                EntryClass::AccessControlReceiverGroup.to_value(),
            ),
            (Attribute::Class, EntryClass::AccessControlModify.to_value()),
            (Attribute::Class, EntryClass::AccessControlCreate.to_value()),
            (Attribute::Class, EntryClass::AccessControlDelete.to_value()),
            (Attribute::Class, EntryClass::AccessControlSearch.to_value()),
            (
                Attribute::Name,
                Value::new_iname("idm_admins_acp_allow_all_test"),
            ),
            (Attribute::Uuid, Value::Uuid(UUID_TEST_ACP)),
            (Attribute::AcpReceiverGroup, Value::Refer(UUID_TEST_GROUP)),
            (
                Attribute::AcpTargetScope,
                Value::new_json_filter_s("{\"pres\":\"class\"}").expect("filter"),
            ),
            (Attribute::AcpSearchAttr, Value::from(Attribute::Name)),
            (Attribute::AcpSearchAttr, Value::from(Attribute::Class)),
            (Attribute::AcpSearchAttr, Value::from(Attribute::Uuid)),
            (Attribute::AcpModifyClass, EntryClass::System.to_value()),
            (
                Attribute::AcpModifyRemovedAttr,
                Value::from(Attribute::Class),
            ),
            (
                Attribute::AcpModifyRemovedAttr,
                Value::from(Attribute::DisplayName),
            ),
            (Attribute::AcpModifyRemovedAttr, Value::from(Attribute::May)),
            (
                Attribute::AcpModifyRemovedAttr,
                Value::from(Attribute::Must),
            ),
            (
                Attribute::AcpModifyPresentAttr,
                Value::from(Attribute::Class),
            ),
            (
                Attribute::AcpModifyPresentAttr,
                Value::from(Attribute::DisplayName),
            ),
            (Attribute::AcpModifyPresentAttr, Value::from(Attribute::May)),
            (
                Attribute::AcpModifyPresentAttr,
                Value::from(Attribute::Must),
            ),
            (Attribute::AcpCreateClass, EntryClass::Object.to_value()),
            (Attribute::AcpCreateClass, EntryClass::Person.to_value()),
            (Attribute::AcpCreateClass, EntryClass::System.to_value()),
            (Attribute::AcpCreateAttr, Value::from(Attribute::Name)),
            (Attribute::AcpCreateAttr, Value::from(Attribute::Class)),
            (
                Attribute::AcpCreateAttr,
                Value::from(Attribute::Description),
            ),
            (
                Attribute::AcpCreateAttr,
                Value::from(Attribute::DisplayName),
            ),
            (Attribute::AcpCreateAttr, Value::from(Attribute::Uuid)),
        ])
    });

    pub static PRELOAD: LazyLock<Vec<EntryInitNew>> =
        LazyLock::new(|| vec![TEST_ACCOUNT.clone(), TEST_GROUP.clone(), ALLOW_ALL.clone()]);
    pub static E_TEST_ACCOUNT: LazyLock<Arc<EntrySealedCommitted>> =
        LazyLock::new(|| Arc::new(TEST_ACCOUNT.clone().into_sealed_committed()));

    // check create where no uuid
    #[test]
    fn test_pre_create_no_uuid() {
        let preload: Vec<Entry<EntryInit, EntryNew>> = Vec::with_capacity(0);

        let e = entry_init!(
            (Attribute::Class, EntryClass::Person.to_value()),
            (Attribute::Class, EntryClass::Account.to_value()),
            (Attribute::Name, Value::new_iname("testperson")),
            (
                Attribute::DisplayName,
                Value::Utf8("Test Person".to_string())
            )
        );

        let create = vec![e];

        run_create_test!(
            Ok(None),
            preload,
            create,
            None,
            |qs: &mut QueryServerWriteTransaction| {
                let cands = qs
                    .internal_search(filter!(f_eq(
                        Attribute::Name,
                        PartialValue::new_iname("testperson")
                    )))
                    .expect("Internal search failure");
                let ue = cands.first().expect("No cand");
                assert!(ue.attribute_pres(Attribute::Uuid));
            }
        );
    }

    // check unparsable uuid
    #[test]
    fn test_pre_create_uuid_invalid() {
        let preload: Vec<Entry<EntryInit, EntryNew>> = Vec::with_capacity(0);

        let e = entry_init!(
            (Attribute::Class, EntryClass::Person.to_value()),
            (Attribute::Class, EntryClass::Account.to_value()),
            (Attribute::Name, Value::new_iname("testperson")),
            (
                Attribute::DisplayName,
                Value::Utf8("Test Person".to_string())
            ),
            (Attribute::Uuid, Value::Utf8("xxxxxx".to_string()))
        );

        let create = vec![e];

        run_create_test!(
            Err(OperationError::InvalidAttribute(
                Attribute::Uuid.to_string()
            )),
            preload,
            create,
            None,
            |_| {}
        );
    }

    // check entry where uuid is empty list
    #[test]
    fn test_pre_create_uuid_empty() {
        let preload: Vec<Entry<EntryInit, EntryNew>> = Vec::with_capacity(0);

        let mut e = entry_init!(
            (Attribute::Class, EntryClass::Person.to_value()),
            (Attribute::Class, EntryClass::Account.to_value()),
            (Attribute::Name, Value::new_iname("testperson")),
            (
                Attribute::DisplayName,
                Value::Utf8("Test Person".to_string())
            ),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("79724141-3603-4060-b6bb-35c72772611d"))
            )
        );

        let vs = e.get_ava_mut(Attribute::Uuid).unwrap();
        vs.clear();

        let create = vec![e.clone()];

        run_create_test!(
            Err(OperationError::Plugin(PluginError::Base(
                "Uuid format invalid".to_string()
            ))),
            preload,
            create,
            None,
            |_| {}
        );
    }

    // check create where provided uuid is valid. It should be unchanged.
    #[test]
    fn test_pre_create_uuid_valid() {
        let preload: Vec<Entry<EntryInit, EntryNew>> = Vec::with_capacity(0);

        let e = entry_init!(
            (Attribute::Class, EntryClass::Person.to_value()),
            (Attribute::Class, EntryClass::Account.to_value()),
            (Attribute::Name, Value::new_iname("testperson")),
            (
                Attribute::DisplayName,
                Value::Utf8("Test Person".to_string())
            ),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("79724141-3603-4060-b6bb-35c72772611d"))
            )
        );

        let create = vec![e];

        run_create_test!(
            Ok(None),
            preload,
            create,
            None,
            |qs: &mut QueryServerWriteTransaction| {
                let cands = qs
                    .internal_search(filter!(f_eq(
                        Attribute::Name,
                        PartialValue::new_iname("testperson")
                    )))
                    .expect("Internal search failure");
                let ue = cands.first().expect("No cand");
                assert!(ue.attribute_equality(
                    Attribute::Uuid,
                    &PartialValue::Uuid(uuid!("79724141-3603-4060-b6bb-35c72772611d"))
                ));
            }
        );
    }

    #[test]
    fn test_pre_create_uuid_valid_multi() {
        let preload: Vec<Entry<EntryInit, EntryNew>> = Vec::with_capacity(0);

        let e = entry_init!(
            (Attribute::Class, EntryClass::Person.to_value()),
            (Attribute::Class, EntryClass::Account.to_value()),
            (Attribute::Name, Value::new_iname("testperson")),
            (
                Attribute::DisplayName,
                Value::Utf8("Test Person".to_string())
            ),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("79724141-3603-4060-b6bb-35c72772611e"))
            ),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("79724141-3603-4060-b6bb-35c72772611d"))
            )
        );

        let create = vec![e];

        run_create_test!(
            Err(OperationError::Plugin(PluginError::Base(
                "Uuid has multiple values".to_string()
            ))),
            preload,
            create,
            None,
            |_| {}
        );
    }

    // check create where uuid already exists.
    // -- check create where uuid is a well-known
    // This second case is technically handled as well-known
    // types are created "at startup" so it's not possible
    // to create one.
    //
    // To solidify this, we could make a range of min-max well knowns
    // to ensure we always have a name space to draw from?
    #[test]
    fn test_pre_create_uuid_exist() {
        let e = entry_init!(
            (Attribute::Class, EntryClass::Person.to_value()),
            (Attribute::Class, EntryClass::Account.to_value()),
            (Attribute::Name, Value::new_iname("testperson")),
            (
                Attribute::DisplayName,
                Value::Utf8("Test Person".to_string())
            ),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("79724141-3603-4060-b6bb-35c72772611d"))
            )
        );

        let create = vec![e.clone()];
        let preload = vec![e];

        run_create_test!(
            Err(OperationError::Plugin(PluginError::Base(
                "Uuid duplicate found in database".to_string()
            ))),
            preload,
            create,
            None,
            |_| {}
        );
    }

    #[test]
    fn test_pre_create_double_uuid() {
        // Test adding two entries with the same uuid
        let preload: Vec<Entry<EntryInit, EntryNew>> = Vec::with_capacity(0);

        let ea = entry_init!(
            (Attribute::Class, EntryClass::Person.to_value()),
            (Attribute::Class, EntryClass::Account.to_value()),
            (Attribute::Name, Value::new_iname("testperson")),
            (
                Attribute::DisplayName,
                Value::Utf8("Test Person".to_string())
            ),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("79724141-3603-4060-b6bb-35c72772611d"))
            )
        );

        let eb = ea.clone();

        let create = vec![ea, eb];

        run_create_test!(
            Err(OperationError::Plugin(PluginError::Base(
                "Uuid duplicate detected in request".to_string()
            ))),
            preload,
            create,
            None,
            |_| {}
        );
    }

    // All of these *SHOULD* be blocked?
    #[test]
    fn test_modify_uuid_present() {
        // Add another uuid to a type
        let ea = entry_init!(
            (Attribute::Class, EntryClass::Group.to_value()),
            (Attribute::Name, Value::new_iname("testgroup_a")),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("79724141-3603-4060-b6bb-35c72772611d"))
            )
        );

        let preload = vec![ea];

        run_modify_test!(
            Err(OperationError::SystemProtectedAttribute),
            preload,
            filter!(f_eq(
                Attribute::Name,
                PartialValue::new_iname("testgroup_a")
            )),
            ModifyList::new_list(vec![Modify::Present(
                Attribute::Uuid,
                Value::from("f15a7219-1d15-44e3-a7b4-bec899c07788")
            )]),
            None,
            |_| {},
            |_| {}
        );
    }

    #[test]
    fn test_modify_uuid_removed() {
        // Test attempting to remove a uuid
        let ea = entry_init!(
            (Attribute::Class, EntryClass::Group.to_value()),
            (Attribute::Name, Value::new_iname("testgroup_a")),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("79724141-3603-4060-b6bb-35c72772611d"))
            )
        );

        let preload = vec![ea];

        run_modify_test!(
            Err(OperationError::SystemProtectedAttribute),
            preload,
            filter!(f_eq(
                Attribute::Name,
                PartialValue::new_iname("testgroup_a")
            )),
            ModifyList::new_list(vec![Modify::Removed(
                Attribute::Uuid,
                PartialValue::Uuid(uuid!("f15a7219-1d15-44e3-a7b4-bec899c07788"))
            )]),
            None,
            |_| {},
            |_| {}
        );
    }

    #[test]
    fn test_modify_uuid_purged() {
        // Test attempting to purge uuid
        let ea = entry_init!(
            (Attribute::Class, EntryClass::Group.to_value()),
            (Attribute::Name, Value::new_iname("testgroup_a")),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("79724141-3603-4060-b6bb-35c72772611d"))
            )
        );

        let preload = vec![ea];

        run_modify_test!(
            Err(OperationError::SystemProtectedAttribute),
            preload,
            filter!(f_eq(
                Attribute::Name,
                PartialValue::new_iname("testgroup_a")
            )),
            ModifyList::new_list(vec![Modify::Purged(Attribute::Uuid)]),
            None,
            |_| {},
            |_| {}
        );
    }

    #[test]
    fn test_protected_uuid_range() {
        // Test an external create, it should fail.
        // Testing internal create is not super needed, due to migrations at start
        // up testing this every time we run :P
        let preload = PRELOAD.clone();

        let e = entry_init!(
            (Attribute::Class, EntryClass::Person.to_value()),
            (Attribute::Name, Value::new_iname("testperson")),
            (Attribute::DisplayName, Value::new_iname("testperson")),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("00000000-0000-0000-0000-f0f0f0f0f0f0"))
            )
        );

        let create = vec![e];

        run_create_test!(
            Err(OperationError::AccessDenied),
            preload,
            create,
            Some(E_TEST_ACCOUNT.clone()),
            |_| {}
        );
    }

    #[test]
    fn test_protected_uuid_range_2() {
        // Test an external create, it should fail.
        // Testing internal create is not super needed, due to migrations at start
        // up testing this every time we run :P
        let preload = PRELOAD.clone();

        let e = entry_init!(
            (Attribute::Class, EntryClass::Person.to_value()),
            (Attribute::Name, Value::new_iname("testperson")),
            (Attribute::DisplayName, Value::new_iname("testperson")),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("00000000-0000-0000-0000-f0f0f0f0f0f0"))
            )
        );

        let create = vec![e];

        run_create_test!(
            Err(OperationError::AccessDenied),
            preload,
            create,
            Some(E_TEST_ACCOUNT.clone()),
            |_| {}
        );
    }

    #[test]
    fn test_protected_uuid_does_not_exist() {
        // Test that internal create of "does not exist" will fail.
        let preload = Vec::with_capacity(0);

        let e = entry_init!(
            (Attribute::Class, EntryClass::Person.to_value()),
            (Attribute::Class, EntryClass::System.to_value()),
            (Attribute::Name, Value::new_iname("testperson")),
            (Attribute::DisplayName, Value::new_iname("testperson")),
            (
                Attribute::Uuid,
                Value::Uuid(uuid::uuid!("00000000-0000-0000-0000-fffffffffffe"))
            )
        );

        let create = vec![e];

        run_create_test!(
            Err(OperationError::Plugin(PluginError::Base(
                "UUID_DOES_NOT_EXIST may not exist!".to_string()
            ))),
            preload,
            create,
            None,
            |_| {}
        );
    }
}
