use super::prelude::*;
use serde::de::Error as DeError;
use serde::de::MapAccess;
use serde::ser::{Serialize, SerializeSeq, Serializer};
use std::{collections::HashMap, hash::Hash, sync::Arc};

#[cfg(feature = "cache")]
use crate::internal::prelude::*;

#[cfg(all(feature = "cache", feature = "model"))]
use super::permissions::Permissions;
#[cfg(all(feature = "cache", feature = "model"))]
use crate::cache::CacheRwLock;
use crate::internal::{AsyncRwLock, SyncRwLock};

pub fn default_true() -> bool {
    true
}

pub fn deserialize_emojis<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<HashMap<EmojiId, Emoji>, D::Error> {
    let vec: Vec<Emoji> = Deserialize::deserialize(deserializer)?;
    let mut emojis = HashMap::new();

    for emoji in vec {
        emojis.insert(emoji.id, emoji);
    }

    Ok(emojis)
}

pub fn serialize_emojis<S: Serializer>(
    emojis: &HashMap<EmojiId, Emoji>,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    let mut seq = serializer.serialize_seq(Some(emojis.len()))?;

    for emoji in emojis.values() {
        seq.serialize_element(emoji)?;
    }

    seq.end()
}

pub fn deserialize_guild_channels<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<HashMap<ChannelId, Arc<AsyncRwLock<GuildChannel>>>, D::Error> {
    let vec: Vec<GuildChannel> = Deserialize::deserialize(deserializer)?;
    let mut map = HashMap::new();

    for channel in vec {
        map.insert(channel.id, Arc::new(AsyncRwLock::new(channel)));
    }

    Ok(map)
}

pub fn deserialize_members<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<HashMap<UserId, Member>, D::Error> {
    let vec: Vec<Member> = Deserialize::deserialize(deserializer)?;

    let mut members = HashMap::new();

    for member in vec {
        let user_id = member.user.read().id;

        members.insert(user_id, member);
    }

    Ok(members)
}

pub fn deserialize_presences<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<HashMap<UserId, Presence>, D::Error> {
    let vec: Vec<Presence> = Deserialize::deserialize(deserializer)?;
    let mut presences = HashMap::new();

    for presence in vec {
        presences.insert(presence.user_id, presence);
    }

    Ok(presences)
}

pub fn serialize_presences<S: Serializer>(
    presences: &HashMap<UserId, Presence>,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    let mut seq = serializer.serialize_seq(Some(presences.len()))?;

    for presence in presences.values() {
        seq.serialize_element(presence)?;
    }

    seq.end()
}

pub fn deserialize_private_channels<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<HashMap<ChannelId, Channel>, D::Error> {
    let vec: Vec<Channel> = Deserialize::deserialize(deserializer)?;
    let mut private_channels = HashMap::new();

    for private_channel in vec {
        let id = match private_channel {
            Channel::Group(ref group) => futures::executor::block_on(group.read()).channel_id,
            Channel::Private(ref channel) => futures::executor::block_on(channel.read()).id,
            Channel::Guild(_) => unreachable!("Guild private channel decode"),
            Channel::Category(_) => unreachable!("Channel category private channel decode"),
        };

        private_channels.insert(id, private_channel);
    }

    Ok(private_channels)
}

pub fn serialize_private_channels<S: Serializer>(
    private_channels: &HashMap<ChannelId, Channel>,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    let mut seq = serializer.serialize_seq(Some(private_channels.len()))?;

    for private_channel in private_channels.values() {
        seq.serialize_element(private_channel)?;
    }

    seq.end()
}

pub fn deserialize_roles<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<HashMap<RoleId, Role>, D::Error> {
    let vec: Vec<Role> = Deserialize::deserialize(deserializer)?;
    let mut roles = HashMap::new();

    for role in vec {
        roles.insert(role.id, role);
    }

    Ok(roles)
}

pub fn serialize_roles<S: Serializer>(
    roles: &HashMap<RoleId, Role>,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    let mut seq = serializer.serialize_seq(Some(roles.len()))?;

    for role in roles.values() {
        seq.serialize_element(role)?;
    }

    seq.end()
}

pub fn deserialize_single_recipient<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<Arc<SyncRwLock<User>>, D::Error> {
    let mut users: Vec<User> = Deserialize::deserialize(deserializer)?;
    let user = if users.is_empty() {
        return Err(DeError::custom("Expected a single recipient"));
    } else {
        users.remove(0)
    };

    Ok(Arc::new(SyncRwLock::new(user)))
}

pub fn serialize_single_recipient<S: Serializer>(
    user: &Arc<SyncRwLock<User>>,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    let mut seq = serializer.serialize_seq(Some(1))?;

    seq.serialize_element(&*user.read())?;

    seq.end()
}

pub fn deserialize_sync_user<'de, D>(deserializer: D) -> StdResult<Arc<SyncRwLock<User>>, D::Error>
where
    D: Deserializer<'de>,
{
    Ok(Arc::new(SyncRwLock::new(User::deserialize(deserializer)?)))
}

pub fn serialize_sync_user<S: Serializer>(
    user: &Arc<SyncRwLock<User>>,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    User::serialize(&*user.read(), serializer)
}

pub fn deserialize_users<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<HashMap<UserId, Arc<SyncRwLock<User>>>, D::Error> {
    let vec: Vec<User> = Deserialize::deserialize(deserializer)?;
    let mut users = HashMap::new();

    for user in vec {
        users.insert(user.id, Arc::new(SyncRwLock::new(user)));
    }

    Ok(users)
}

pub fn serialize_users<S: Serializer>(
    users: &HashMap<UserId, Arc<SyncRwLock<User>>>,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    let mut seq = serializer.serialize_seq(Some(users.len()))?;

    for user in users.values() {
        seq.serialize_element(&*user.read())?;
    }

    seq.end()
}

pub fn deserialize_u16<'de, D: Deserializer<'de>>(deserializer: D) -> StdResult<u16, D::Error> {
    deserializer.deserialize_any(U16Visitor)
}

pub fn deserialize_u64<'de, D: Deserializer<'de>>(deserializer: D) -> StdResult<u64, D::Error> {
    deserializer.deserialize_any(U64Visitor)
}

/// Deserializes an u64, returning 0 if the deserialization failed.
pub fn deserialize_u64_or_zero<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<u64, D::Error> {
    deserialize_u64(deserializer).or(Ok(0))
}

#[allow(clippy::trivially_copy_pass_by_ref)]
pub fn serialize_u64<S: Serializer>(data: &u64, ser: S) -> StdResult<S::Ok, S::Error> {
    ser.serialize_str(&data.to_string())
}

pub fn deserialize_voice_states<'de, D: Deserializer<'de>>(
    deserializer: D,
) -> StdResult<HashMap<UserId, VoiceState>, D::Error> {
    let vec: Vec<VoiceState> = Deserialize::deserialize(deserializer)?;
    let mut voice_states = HashMap::new();

    for voice_state in vec {
        voice_states.insert(voice_state.user_id, voice_state);
    }

    Ok(voice_states)
}

pub fn serialize_gen_map<K: Eq + Hash, S: Serializer, V: Serialize>(
    map: &HashMap<K, V>,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    let mut seq = serializer.serialize_seq(Some(map.len()))?;

    for value in map.values() {
        seq.serialize_element(&value)?;
    }

    seq.end()
}

pub fn serialize_gen_locked_map<K: Eq + Hash, S: Serializer, V: Serialize>(
    map: &HashMap<K, Arc<AsyncRwLock<V>>>,
    serializer: S,
) -> StdResult<S::Ok, S::Error> {
    let mut seq = serializer.serialize_seq(Some(map.len()))?;

    for value in map.values() {
        seq.serialize_element(&*futures::executor::block_on(value.read()))?;
    }

    seq.end()
}

#[cfg(all(feature = "cache", feature = "model"))]
pub async fn user_has_perms(
    cache: impl AsRef<CacheRwLock>,
    channel_id: ChannelId,
    guild_id: Option<GuildId>,
    mut permissions: Permissions,
) -> Result<bool> {
    let cache = cache.as_ref().read().await;
    let current_user = &cache.user;

    let guild_id = match guild_id {
        Some(id) => id,
        None => {
            let channel = match cache.channel(channel_id) {
                Some(channel) => channel,
                None => return Err(Error::Model(ModelError::ItemMissing)),
            };

            match channel {
                Channel::Guild(channel) => channel.read().await.guild_id,
                Channel::Group(_) | Channel::Private(_) | Channel::Category(_) => {
                    // Both users in DMs, all users in groups, and maybe all channels in categories
                    // will have the same permissions.
                    //
                    // The only exception to this is when the current user is blocked by
                    // the recipient in a DM channel, preventing the current user
                    // from sending messages.
                    //
                    // Since serenity can't _reasonably_ check and keep track of these,
                    // just assume that all permissions are granted and return `true`.
                    return Ok(true);
                }
            }
        }
    };

    let guild = match cache.guild(guild_id) {
        Some(guild) => guild,
        None => return Err(Error::Model(ModelError::ItemMissing)),
    };

    let perms = {
        let tmp = guild.read().await;
        tmp.user_permissions_in(channel_id, current_user.id).await
    };

    permissions.remove(perms);

    Ok(permissions.is_empty())
}

macro_rules! num_visitors {
    ($($visitor:ident: $type:ty),*) => {
        $(
            #[derive(Debug)]
            pub struct $visitor;

            impl<'de> Visitor<'de> for $visitor {
                type Value = $type;

                fn expecting(&self, formatter: &mut Formatter<'_>) -> FmtResult {
                    formatter.write_str("identifier")
                }

                fn visit_str<E: DeError>(self, v: &str) -> StdResult<Self::Value, E> {
                    v.parse::<$type>().map_err(|_| {
                        let mut s = String::with_capacity(32);
                        s.push_str("Unknown ");
                        s.push_str(stringify!($type));
                        s.push_str(" value: ");
                        s.push_str(v);

                        DeError::custom(s)
                    })
                }

                fn visit_i64<E: DeError>(self, v: i64) -> StdResult<Self::Value, E> { Ok(v as $type) }

                fn visit_u64<E: DeError>(self, v: u64) -> StdResult<Self::Value, E> { Ok(v as $type) }

                // This is called when serde_json's `arbitrary_precision` feature is enabled.
                fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> StdResult<Self::Value, A::Error> {
                    struct Id {
                        num: $type,
                    }

                    struct StrVisitor;

                    impl<'de> Visitor<'de> for StrVisitor {
                        type Value = $type;

                        fn expecting(&self, formatter: &mut Formatter<'_>) -> FmtResult {
                            formatter.write_str("string")
                        }

                        fn visit_str<E: DeError>(self, s: &str) -> StdResult<Self::Value, E> { s.parse().map_err(E::custom) }
                        fn visit_string<E: DeError>(self, s: String) -> StdResult<Self::Value, E> { s.parse().map_err(E::custom) }
                    }

                    impl<'de> Deserialize<'de> for Id {
                        fn deserialize<D: Deserializer<'de>>(des: D) -> StdResult<Self, D::Error> {
                            Ok(Id { num: des.deserialize_str(StrVisitor)? })
                        }
                    }

                    map.next_value::<Id>().map(|id| id.num)
                }
            }
        )*
    }
}

num_visitors!(U16Visitor: u16, U64Visitor: u64);
