use std::hash::{Hash, Hasher};

use serde::{Serialize, Serializer, ser::SerializeMap};
use xxhash_rust::xxh3::Xxh3;

pub type NamedField = (&'static str, Typ);

pub type Arr<T> = &'static [T];
pub type Str = &'static str;
pub type Map<T> = Arr<(u8, T)>;

#[derive(PartialEq, Clone, Serialize, Debug, Copy, Hash)]
#[serde(tag = "type", content = "data")]
pub enum Fields {
    Named(Arr<NamedField>),
    Unnamed(Arr<Typ>),
}

/**
named structs, unnamed structs and tuples
если нет названий полей в структуре, то это неименованная структура или кортеж.
*/
#[derive(PartialEq, Clone, Serialize, Debug, Copy, Hash)]
pub struct StructType {
    pub name: &'static str,
    pub fields: Fields,
}

fn variants<S, T>(variants: Map<T>, serializer: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
    T: Serialize,
{
    let mut map = serializer.serialize_map(Some(variants.len()))?;
    for (key, value) in variants {
        map.serialize_entry(key, value)?;
    }
    map.end()
}

#[derive(PartialEq, Clone, Serialize, Debug, Copy, Hash)]
pub struct EnumType {
    pub name: Str,
    #[serde(serialize_with = "variants")]
    pub variants: Map<NamedField>,
}

#[derive(PartialEq, Eq, Clone, Serialize, Debug, Copy, Hash)]
pub struct SimpleEnumType {
    pub name: Str,
    #[serde(serialize_with = "variants")]
    pub variants: Map<Str>,
}

#[derive(PartialEq, Clone, Serialize, Debug, Copy, Hash)]
#[serde(tag = "type", content = "data")]
pub enum Typ {
    Bool,
    U8,
    U16,
    U32,
    U64,
    I32,
    I64,
    F32,
    F64,
    Str,
    /// i64 unix timestamp milliseconds
    Datetime,
    /// u64 unix timestamp milliseconds
    Timestamp,
    Decimal,
    /// u32 big endian id type
    Id32,
    /// u64 big endian id type
    Id64,
    /// Fuid
    Fuid,
    /// LowId
    LowId,
    // массив байт
    Bytes,
    // массив байт фиксированного размера
    /// array bytes with bytes count in scheme
    ArrayBytes(u32),
    Array(u32, &'static Typ),
    // Вектор или массив значений одного типа
    Vec(&'static Typ),
    Optional(&'static Typ),
    SimpleEnum(SimpleEnumType),
    Struct(StructType),
    Enum(EnumType),
    Void,
    /// Rust binary JSON representation
    #[serde(rename = "Json")]
    RustJson,
    /// vector of bytes, representing json string
    JsonBytes,
    Custom(&'static str, &'static [Typ]),
}

impl Typ {
    pub(crate) fn h(&self) -> u64 {
        let mut hasher = Xxh3::new();
        self.hash(&mut hasher);
        hasher.finish()
    }
}
