use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
pub enum FinePermission {
    Administrator,
    ManagePosts,
    ManageUsers,
    ManageBans,
    ManageWarnings,
    ManageNotifications,
    ViewReports,
    ViewAuditLog,
    ManageReactions,
    ManageFollows,
    ManageVerified,
    ManageAuditLog,
    ManageReports,
    Banned,
    Supporter,
    ManageRequests,
    ManageQuestions,
    ManageUploads,
    StaffBadge,
    ManageApps,
    ManageGroups,
}

impl FinePermission {
    /// Check if the given `input` contains the given permission.
    pub fn check(permissions: &[Self], permission: Self) -> bool {
        if permissions.contains(&Self::Administrator) && permission != Self::Banned {
            // has administrator permission, meaning everything else is automatically true
            return true;
        } else if permissions.contains(&Self::Banned) && permission != Self::Banned {
            // has banned permission, meaning everything else is automatically false
            return false;
        }

        permissions.contains(&permission)
    }
}

#[derive(Serialize, Deserialize, Clone, Debug, Default)]
pub struct PermissionsContainer(Vec<FinePermission>);

impl PermissionsContainer {
    pub fn new() -> Self {
        Self(Vec::new())
    }

    pub fn check(&self, permission: FinePermission) -> bool {
        FinePermission::check(&self.0, permission)
    }

    pub fn join(&mut self, permission: FinePermission) {
        self.0.push(permission);
    }

    pub fn joinc(&self, permission: FinePermission) -> Self {
        let mut clone = self.to_owned();
        clone.0.push(permission);
        clone
    }

    pub fn remove(&mut self, permission: FinePermission) {
        self.0
            .remove(self.0.iter().position(|x| x == &permission).unwrap());
    }

    pub fn removec(&self, permission: FinePermission) -> Self {
        let mut clone = self.to_owned();
        clone
            .0
            .remove(self.0.iter().position(|x| x == &permission).unwrap());
        clone
    }

    pub fn len(&self) -> usize {
        self.0.len()
    }

    pub fn is_empty(&self) -> bool {
        self.0.is_empty()
    }
}
