use std::cmp::Ordering;
use std::fmt;
use crate::model::KStringCow;
use super::DisplayCow;
use super::State;
use super::Value;
use crate::model::ArrayView;
use crate::model::ObjectView;
use crate::model::ScalarCow;
pub trait ValueView: fmt::Debug {
    fn as_debug(&self) -> &dyn fmt::Debug;
    fn render(&self) -> DisplayCow<'_>;
    fn source(&self) -> DisplayCow<'_>;
    fn type_name(&self) -> &'static str;
    fn query_state(&self, state: State) -> bool;
    fn to_kstr(&self) -> KStringCow<'_>;
    fn to_value(&self) -> Value;
    fn as_scalar(&self) -> Option<ScalarCow<'_>> {
        None
    }
    fn is_scalar(&self) -> bool {
        self.as_scalar().is_some()
    }
    fn as_array(&self) -> Option<&dyn ArrayView> {
        None
    }
    fn is_array(&self) -> bool {
        self.as_array().is_some()
    }
    fn as_object(&self) -> Option<&dyn ObjectView> {
        None
    }
    fn is_object(&self) -> bool {
        self.as_object().is_some()
    }
    fn as_state(&self) -> Option<State> {
        None
    }
    fn is_state(&self) -> bool {
        self.as_state().is_some()
    }
    fn is_nil(&self) -> bool {
        false
    }
}
impl<'v, V: ValueView + ?Sized> ValueView for &'v V {
    fn as_debug(&self) -> &dyn fmt::Debug {
        <V as ValueView>::as_debug(self)
    }
    fn render(&self) -> DisplayCow<'_> {
        <V as ValueView>::render(self)
    }
    fn source(&self) -> DisplayCow<'_> {
        <V as ValueView>::source(self)
    }
    fn type_name(&self) -> &'static str {
        <V as ValueView>::type_name(self)
    }
    fn query_state(&self, state: State) -> bool {
        <V as ValueView>::query_state(self, state)
    }
    fn to_kstr(&self) -> KStringCow<'_> {
        <V as ValueView>::to_kstr(self)
    }
    fn to_value(&self) -> Value {
        <V as ValueView>::to_value(self)
    }
    fn as_scalar(&self) -> Option<ScalarCow<'_>> {
        <V as ValueView>::as_scalar(self)
    }
    fn as_array(&self) -> Option<&dyn ArrayView> {
        <V as ValueView>::as_array(self)
    }
    fn as_object(&self) -> Option<&dyn ObjectView> {
        <V as ValueView>::as_object(self)
    }
    fn as_state(&self) -> Option<State> {
        <V as ValueView>::as_state(self)
    }
    fn is_nil(&self) -> bool {
        <V as ValueView>::is_nil(self)
    }
}
static NIL: Value = Value::Nil;
impl<T: ValueView> ValueView for Option<T> {
    fn as_debug(&self) -> &dyn fmt::Debug {
        self
    }
    fn render(&self) -> DisplayCow<'_> {
        forward(self).render()
    }
    fn source(&self) -> DisplayCow<'_> {
        forward(self).source()
    }
    fn type_name(&self) -> &'static str {
        forward(self).type_name()
    }
    fn query_state(&self, state: State) -> bool {
        forward(self).query_state(state)
    }
    fn to_kstr(&self) -> KStringCow<'_> {
        forward(self).to_kstr()
    }
    fn to_value(&self) -> Value {
        forward(self).to_value()
    }
    fn as_scalar(&self) -> Option<ScalarCow<'_>> {
        forward(self).as_scalar()
    }
    fn as_array(&self) -> Option<&dyn ArrayView> {
        forward(self).as_array()
    }
    fn as_object(&self) -> Option<&dyn ObjectView> {
        forward(self).as_object()
    }
    fn as_state(&self) -> Option<State> {
        forward(self).as_state()
    }
    fn is_nil(&self) -> bool {
        forward(self).is_nil()
    }
}
fn forward(o: &Option<impl ValueView>) -> &dyn ValueView {
    o.as_ref()
        .map(|v| v as &dyn ValueView)
        .unwrap_or(&NIL as &dyn ValueView)
}
#[derive(Copy, Clone, Debug)]
pub struct ValueViewCmp<'v>(&'v dyn ValueView);
impl<'v> ValueViewCmp<'v> {
    pub fn new(v: &dyn ValueView) -> ValueViewCmp<'_> {
        ValueViewCmp(v)
    }
}
impl<'v> PartialEq<ValueViewCmp<'v>> for ValueViewCmp<'v> {
    fn eq(&self, other: &Self) -> bool {
        value_eq(self.0, other.0)
    }
}
impl<'v> PartialEq<i64> for ValueViewCmp<'v> {
    fn eq(&self, other: &i64) -> bool {
        super::value_eq(self.0, other)
    }
}
impl<'v> PartialEq<f64> for ValueViewCmp<'v> {
    fn eq(&self, other: &f64) -> bool {
        super::value_eq(self.0, other)
    }
}
impl<'v> PartialEq<bool> for ValueViewCmp<'v> {
    fn eq(&self, other: &bool) -> bool {
        super::value_eq(self.0, other)
    }
}
impl<'v> PartialEq<crate::model::scalar::DateTime> for ValueViewCmp<'v> {
    fn eq(&self, other: &crate::model::scalar::DateTime) -> bool {
        super::value_eq(self.0, other)
    }
}
impl<'v> PartialEq<crate::model::scalar::Date> for ValueViewCmp<'v> {
    fn eq(&self, other: &crate::model::scalar::Date) -> bool {
        super::value_eq(self.0, other)
    }
}
impl<'v> PartialEq<str> for ValueViewCmp<'v> {
    fn eq(&self, other: &str) -> bool {
        let other = KStringCow::from_ref(other);
        super::value_eq(self.0, &other)
    }
}
impl<'v> PartialEq<&'v str> for ValueViewCmp<'v> {
    fn eq(&self, other: &&str) -> bool {
        super::value_eq(self.0, other)
    }
}
impl<'v> PartialEq<String> for ValueViewCmp<'v> {
    fn eq(&self, other: &String) -> bool {
        self == other.as_str()
    }
}
impl<'v> PartialEq<crate::model::KString> for ValueViewCmp<'v> {
    fn eq(&self, other: &crate::model::KString) -> bool {
        super::value_eq(self.0, &other.as_ref())
    }
}
impl<'v> PartialEq<crate::model::KStringRef<'v>> for ValueViewCmp<'v> {
    fn eq(&self, other: &crate::model::KStringRef<'v>) -> bool {
        super::value_eq(self.0, other)
    }
}
impl<'v> PartialEq<crate::model::KStringCow<'v>> for ValueViewCmp<'v> {
    fn eq(&self, other: &crate::model::KStringCow<'v>) -> bool {
        super::value_eq(self.0, other)
    }
}
impl<'v> PartialOrd<ValueViewCmp<'v>> for ValueViewCmp<'v> {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        value_cmp(self.0, other.0)
    }
}
pub(crate) fn value_eq(lhs: &dyn ValueView, rhs: &dyn ValueView) -> bool {
    if let (Some(x), Some(y)) = (lhs.as_array(), rhs.as_array()) {
        if x.size() != y.size() {
            return false;
        }
        return x.values().zip(y.values()).all(|(x, y)| value_eq(x, y));
    }
    if let (Some(x), Some(y)) = (lhs.as_object(), rhs.as_object()) {
        if x.size() != y.size() {
            return false;
        }
        return x.iter().all(|(key, value)| {
            y.get(key.as_str())
                .map(|v| value_eq(v, value))
                .unwrap_or(false)
        });
    }
    if lhs.is_nil() && rhs.is_nil() {
        return true;
    }
    if let Some(state) = lhs.as_state() {
        return rhs.query_state(state);
    } else if let Some(state) = rhs.as_state() {
        return lhs.query_state(state);
    }
    match (lhs.as_scalar(), rhs.as_scalar()) {
        (Some(x), Some(y)) => return x == y,
        (None, None) => (),
        (Some(x), _) => {
            if rhs.is_nil() {
                return !x.to_bool().unwrap_or(true);
            } else {
                return x.to_bool().unwrap_or(false);
            }
        }
        (_, Some(x)) => {
            if lhs.is_nil() {
                return !x.to_bool().unwrap_or(true);
            } else {
                return x.to_bool().unwrap_or(false);
            }
        }
    }
    false
}
pub(crate) fn value_cmp(lhs: &dyn ValueView, rhs: &dyn ValueView) -> Option<Ordering> {
    if let (Some(x), Some(y)) = (lhs.as_scalar(), rhs.as_scalar()) {
        return x.partial_cmp(&y);
    }
    if let (Some(x), Some(y)) = (lhs.as_array(), rhs.as_array()) {
        return x
            .values()
            .map(|v| ValueViewCmp(v))
            .partial_cmp(y.values().map(|v| ValueViewCmp(v)));
    }
    if let (Some(x), Some(y)) = (lhs.as_object(), rhs.as_object()) {
        return x
            .iter()
            .map(|(k, v)| (k, ValueViewCmp(v)))
            .partial_cmp(y.iter().map(|(k, v)| (k, ValueViewCmp(v))));
    }
    None
}
#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_debug() {
        let scalar = 5;
        println!("{:?}", scalar);
        let view: &dyn ValueView = &scalar;
        println!("{:?}", view);
        let debug: &dyn fmt::Debug = view.as_debug();
        println!("{:?}", debug);
    }
}