use std::collections::BTreeMap;

use arrayvec::ArrayVec;
use crossbeam_skiplist::SkipMap;
use derive_more::Debug;
use serde::{Deserialize, Serialize};

// Re-export from armour-core
#[cfg(feature = "std")]
pub use armour_core::persist;
#[cfg(feature = "std")]
pub use armour_core::persist::Persist;

use crate::Record;

#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct DbInfo {
    pub version: u64,
    pub collections: BTreeMap<String, CollectionInfo>,
}

#[derive(Debug, Clone, Copy, Deserialize, Serialize, Default)]
pub struct CollectionInfo {
    #[debug("{:#X}", typ_hash)]
    pub typ_hash: u64,
    pub version: u16,
}

pub type FnArray<T> = ArrayVec<T, 8>;

/// item, old_id, new_id
pub type IdChangeEventFn<Item> =
    Box<dyn Fn(&Item, &<Item as Record>::SelfId, &<Item as Record>::SelfId) + Send + Sync>;

pub type UpsertEventFn<Item> = Box<dyn Fn(&<Item as Record>::SelfId, Change<Item>) + Send + Sync>;

pub type RemoveEventFn<Item> = Box<dyn Fn(&<Item as Record>::SelfId, &Item) + Send + Sync>;

#[derive(Debug)]
pub(crate) struct EventHandlers<Item: Record> {
    /// item, old_id, new_id
    #[debug("{}", self.on_id_change.is_some())]
    pub(crate) on_id_change: Option<IdChangeEventFn<Item>>,
    #[debug("{}", self.on_upsert.is_some())]
    pub(crate) on_upsert: Option<UpsertEventFn<Item>>,
    #[debug("{}", self.on_remove.is_some())]
    pub(crate) on_remove: Option<RemoveEventFn<Item>>,
}

impl<Item: Record> Default for EventHandlers<Item> {
    fn default() -> Self {
        Self {
            on_id_change: None,
            on_upsert: None,
            on_remove: None,
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Change<'o, 'n, Item> {
    pub old: Option<&'o Item>,
    pub new: &'n Item,
}

#[derive(Debug, Clone, Copy)]
pub struct GroupVal {
    pub hash: u64,
    // pub updated: Datetime,
    pub changed: bool,
}

pub type CheckSumVec = Vec<(u32, u64)>;
pub type HashPoints = SkipMap<u32, GroupVal>;
