use crate::types::*;
#[derive(Clone, Default)]
pub enum Value {
    #[default]
    X,
    Word(Width, u64),
    Vec(Vec<Value>),
    Ctor(String, Vec<Value>),
    Enum(Type, String),
    Struct(Type, Vec<(String, Value)>),
}
impl PartialEq for Value {
    #[rustfmt::skip]
    fn eq(&self, other: &Value) -> bool {
        match (self, other) {
            (Value::X, Value::X) => true,
            (Value::Word(w1, v1), Value::Word(w2, v2)) => w1 == w2 && v1 == v2,
            (Value::Vec(vs1), Value::Vec(vs2)) => {
                assert_eq!(vs1.len(), vs2.len());
                for (v1, v2) in vs1.iter().zip(vs2.iter()) {
                    if v1 != v2 {
                        return false;
                    }
                }
                true
            },
            (Value::Enum(typ1, name1), Value::Enum(typ2, name2)) => typ1.equals(typ2) && name1 == name2,
            (Value::Struct(typ1, fields1), Value::Struct(typ2, fields2)) => {
                if !typ1.equals(typ2) {
                    return false;
                }
                assert_eq!(fields1.len(), fields2.len());
                for ((name1, v1), (name2, v2)) in fields1.iter().zip(fields2.iter()) {
                    assert_eq!(name1, name2);
                    if v1 != v2 {
                        return false;
                    }
                }
                true
            },
            (Value::Ctor(ctor1, vs1), Value::Ctor(ctor2, vs2)) => {
                if ctor1 != ctor2 {
                    return false;
                }
                for (v1, v2) in vs1.iter().zip(vs2.iter()) {
                    if v1 != v2 {
                        return false;
                    }
                }
                true
            },
            _ => false,
        }
    }
}
impl Value {
    pub fn is_x(&self) -> bool {
        if let Value::X = self {
            true
        } else {
            false
        }
    }
    pub fn to_u64(&self) -> Option<u64> {
        match self {
            Value::X => None,
            Value::Word(w, n) => Some(n & ((1 << w) - 1)),
            Value::Vec(_vs) => panic!(),
            Value::Enum(_typedef, _name) => panic!(),
            Value::Struct(_typedef, _fields) => panic!(),
            Value::Ctor(_ctor, _e) => None,
        }
    }
    pub fn to_bool(&self) -> Option<bool> {
        match self {
            Value::Word(1, 0) => Some(false),
            Value::Word(1, 1) => Some(true),
            _ => None,
        }
    }
}
#[test]
fn value_to_usize() {
    let v: Value = Value::Word(4, 7);
    assert_eq!(v.to_u64(), Some(7));
    let v: Value = Value::Word(2, 7);
    assert_eq!(v.to_u64(), Some(3));
}
impl From<bool> for Value {
    fn from(x: bool) -> Value {
        Value::Word(1, if x { 1 } else { 0 })
    }
}
impl TryFrom<Value> for bool {
    type Error = ();
    fn try_from(value: Value) -> Result<bool, Self::Error> {
        match value {
            Value::Word(1, n) => Ok(n == 1),
            _ => Err(()),
        }
    }
}
impl TryFrom<Value> for u8 {
    type Error = ();
    fn try_from(value: Value) -> Result<u8, Self::Error> {
        match value {
            Value::Word(_w, n) => Ok(n as u8), _ => Err(()),
        }
    }
}
impl TryFrom<Value> for u64 {
    type Error = ();
    fn try_from(value: Value) -> Result<u64, Self::Error> {
        match value {
            Value::X => Err(()),
            Value::Word(_w, n) => Ok(n),
            Value::Enum(_typedef, _name) => Err(()),
            _ => Err(()),
        }
    }
}
impl std::fmt::Debug for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        match self {
            Value::X => write!(f, "XXX"),
            Value::Word(w, n) => write!(f, "{n}w{w}"),
            Value::Vec(vs) => {
                write!(f, "[")?;
                for (i, v) in vs.iter().enumerate() {
                    if i + 1 < vs.len() {
                        write!(f, "{v:?}, ")?;
                    } else {
                        write!(f, "{v:?}")?;
                    }
                }
                write!(f, "]")
            },
            Value::Enum(typ, name) => write!(f, "{}::{}", typ.name(), name),
            Value::Struct(_typedef, fields) => {
                let field_strs: Vec<_> = fields.iter().map(|(name, val)| format!("{name} = {val:?}")).collect();
                write!(f, "{{ {} }}", field_strs.join(", "))
            },
            Value::Ctor(ctor, vs) => {
                write!(f, "@{ctor}")?;
                if vs.len() > 0 {
                    write!(f, "(")?;
                    for (i, v) in vs.iter().enumerate() {
                        write!(f, "{v:?}")?;
                        if i + 1 < vs.len() {
                            write!(f, ", ")?;
                        }
                    }
                    write!(f, ")")
                } else {
                    Ok(())
                }
            },
        }
    }
}
impl std::fmt::Display for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
        match self {
            Value::X => write!(f, "XXX"),
            Value::Word(w, n) => write!(f, "{n}w{w}"),
            Value::Vec(vs) => {
                write!(f, "[")?;
                for (i, v) in vs.iter().enumerate() {
                    if i + 1 < vs.len() {
                        write!(f, "{v:?}, ")?;
                    } else {
                        write!(f, "{v:?}")?;
                    }
                }
                write!(f, "]")
            },
            Value::Enum(typedef, name) => write!(f, "{}::{}", typedef.name(), name),
            Value::Struct(_typedef, _fields) => write!(f, "{self}"),
            Value::Ctor(ctor, vs) => {
                write!(f, "@{ctor}")?;
                if vs.len() > 0 {
                    write!(f, "(")?;
                    for (i, v) in vs.iter().enumerate() {
                        write!(f, "{v:?}")?;
                        if i + 1 < vs.len() {
                            write!(f, ", ")?;
                        }
                    }
                    write!(f, ")")
                } else {
                    Ok(())
                }
            },
        }
    }
}
impl std::fmt::LowerHex for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Value::X => write!(f, "XXX"),
            Value::Word(w, _n) => write!(f, "0x{:x}w{w}", self.to_u64().unwrap()),
            Value::Vec(vs) => {
                write!(f, "[")?;
                for (i, v) in vs.iter().enumerate() {
                    if i + 1 < vs.len() {
                        write!(f, "{v:?}, ")?;
                    } else {
                        write!(f, "{v:?}")?;
                    }
                }
                write!(f, "]")
            },
            Value::Enum(typedef, name) => write!(f, "{}::{}", typedef.name(), name),
            Value::Struct(_typedef, _fields) => write!(f, "{self}"), Value::Ctor(ctor, vs) => {
                write!(f, "@{ctor}")?;
                if vs.len() > 0 {
                    write!(f, "(")?;
                    for (i, v) in vs.iter().enumerate() {
                        write!(f, "{v:?}")?;
                        if i + 1 < vs.len() {
                            write!(f, ", ")?;
                        }
                    }
                    write!(f, ")")
                } else {
                    Ok(())
                }
            },
        }
    }
}
impl std::fmt::UpperHex for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Value::X => write!(f, "XXX"),
            Value::Word(w, _n) => write!(f, "0x{:X}w{w}", self.to_u64().unwrap()),
            Value::Vec(vs) => {
                write!(f, "[")?;
                for (i, v) in vs.iter().enumerate() {
                    if i + 1 < vs.len() {
                        write!(f, "{v:?}, ")?;
                    } else {
                        write!(f, "{v:?}")?;
                    }
                }
                write!(f, "]")
            },
            Value::Enum(typedef, name) => write!(f, "{}::{}", typedef.name(), name),
            Value::Struct(_typedef, _fields) => write!(f, "{self}"),
            Value::Ctor(ctor, vs) => {
                write!(f, "@{ctor}")?;
                if vs.len() > 0 {
                    write!(f, "(")?;
                    for (i, v) in vs.iter().enumerate() {
                        write!(f, "{v:?}")?;
                        if i + 1 < vs.len() {
                            write!(f, ", ")?;
                        }
                    }
                    write!(f, ")")
                } else {
                    Ok(())
                }
            },
        }
    }
}
impl std::fmt::Binary for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Value::X => write!(f, "XXX"),
            Value::Word(w, _n) => write!(f, "0b{:b}w{w}", self.to_u64().unwrap()),
            Value::Vec(vs) => {
                write!(f, "[")?;
                for (i, v) in vs.iter().enumerate() {
                    if i + 1 < vs.len() {
                        write!(f, "{v:?}, ")?;
                    } else {
                        write!(f, "{v:?}")?;
                    }
                }
                write!(f, "]")
            },
            Value::Enum(typedef, name) => write!(f, "{}::{}", typedef.name(), name),
            Value::Struct(_typedef, _fields) => write!(f, "{self}"),
            Value::Ctor(ctor, vs) => {
                write!(f, "@{ctor}")?;
                if vs.len() > 0 {
                    write!(f, "(")?;
                    for (i, v) in vs.iter().enumerate() {
                        write!(f, "{v:?}")?;
                        if i + 1 < vs.len() {
                            write!(f, ", ")?;
                        }
                    }
                    write!(f, ")")
                } else {
                    Ok(())
                }
            },
        }
    }
}