//! JSON read with every object's members distinct. `serde_json` keeps the last of a
//! repeated member, and another reader may keep the first, so a document that is a
//! definition — the authoring form of a score (score §2.3), an instruction object of
//! `wai.generate.spectral` (SPEC §5) — would mean one thing to one reader and another
//! to the next. These readers refuse a repeated member instead.

use std::fmt;

use serde::de::{DeserializeSeed, Deserializer, Error as _, MapAccess, SeqAccess, Visitor};
use serde_json::{Map, Number, Value};

/// A JSON value whose objects name each member once.
struct Distinct;

impl<'de> DeserializeSeed<'de> for Distinct {
    type Value = Value;
    fn deserialize<D: Deserializer<'de>>(self, d: D) -> Result<Value, D::Error> {
        d.deserialize_any(self)
    }
}

impl<'de> Visitor<'de> for Distinct {
    type Value = Value;
    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str("a JSON value")
    }
    fn visit_bool<E>(self, v: bool) -> Result<Value, E> {
        Ok(Value::Bool(v))
    }
    fn visit_i64<E>(self, v: i64) -> Result<Value, E> {
        Ok(Value::Number(v.into()))
    }
    fn visit_u64<E>(self, v: u64) -> Result<Value, E> {
        Ok(Value::Number(v.into()))
    }
    fn visit_f64<E>(self, v: f64) -> Result<Value, E> {
        Ok(Number::from_f64(v).map_or(Value::Null, Value::Number))
    }
    fn visit_str<E>(self, v: &str) -> Result<Value, E> {
        Ok(Value::String(v.to_owned()))
    }
    fn visit_string<E>(self, v: String) -> Result<Value, E> {
        Ok(Value::String(v))
    }
    fn visit_unit<E>(self) -> Result<Value, E> {
        Ok(Value::Null)
    }
    fn visit_none<E>(self) -> Result<Value, E> {
        Ok(Value::Null)
    }
    fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Value, A::Error> {
        let mut v = Vec::new();
        while let Some(x) = seq.next_element_seed(Distinct)? {
            v.push(x);
        }
        Ok(Value::Array(v))
    }
    fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Value, A::Error> {
        let mut m = Map::new();
        while let Some(k) = map.next_key::<String>()? {
            if m.contains_key(&k) {
                return Err(A::Error::custom(format!("member `{k}` is given twice")));
            }
            let v = map.next_value_seed(Distinct)?;
            m.insert(k, v);
        }
        Ok(Value::Object(m))
    }
}

/// Why `bytes` is not read.
pub enum Refused {
    /// An object names a member twice.
    Repeated(String),
    /// The bytes are not one JSON value.
    NotJson(String),
}

/// One JSON value from `bytes`, with every object's members distinct; nothing but
/// whitespace may follow it, as `serde_json::from_slice` allows.
pub fn from_slice(bytes: &[u8]) -> Result<Value, Refused> {
    let mut de = serde_json::Deserializer::from_slice(bytes);
    let v = Distinct.deserialize(&mut de).and_then(|v| de.end().map(|()| v));
    // Every value is accepted by the visitor, so the only data error is the repeated
    // member it raises; every other error is the syntax's.
    v.map_err(|e| if e.is_data() { Refused::Repeated(e.to_string()) } else { Refused::NotJson(e.to_string()) })
}
