use {
    super::{
        Value,
        date::{parse_date, parse_time, parse_timestamp},
        error::ValueError,
    },
    crate::{
        ast::DataType,
        data::{BigDecimalExt, Interval, Literal, Point, value::uuid::parse_uuid},
        result::{Error, Result},
    },
    bigdecimal::BigDecimal,
    chrono::NaiveDate,
    rust_decimal::Decimal,
    std::{
        cmp::Ordering,
        net::{IpAddr, Ipv4Addr, Ipv6Addr},
        str::FromStr,
    },
};

impl TryFrom<&Literal<'_>> for Value {
    type Error = Error;

    fn try_from(literal: &Literal<'_>) -> Result<Self> {
        match literal {
            Literal::Number(v) => v
                .to_i64()
                .map(Value::I64)
                .or_else(|| v.to_f64().map(Value::F64))
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            Literal::Boolean(v) => Ok(Value::Bool(*v)),
            Literal::Text(v) => Ok(Value::Str(v.as_ref().to_owned())),
            Literal::Bytea(v) => Ok(Value::Bytea(v.to_vec())),
            Literal::Null => Ok(Value::Null),
        }
    }
}

impl TryFrom<Literal<'_>> for Value {
    type Error = Error;

    fn try_from(literal: Literal<'_>) -> Result<Self> {
        match literal {
            Literal::Text(v) => Ok(Value::Str(v.into_owned())),
            _ => Value::try_from(&literal),
        }
    }
}

impl Value {
    pub fn evaluate_eq_with_literal(&self, other: &Literal<'_>) -> bool {
        match (self, other) {
            (Value::Bool(l), Literal::Boolean(r)) => l == r,
            (Value::I8(l), Literal::Number(r)) => r.to_i8().map(|r| *l == r).unwrap_or(false),
            (Value::I16(l), Literal::Number(r)) => r.to_i16().map(|r| *l == r).unwrap_or(false),
            (Value::I32(l), Literal::Number(r)) => r.to_i32().map(|r| *l == r).unwrap_or(false),
            (Value::I64(l), Literal::Number(r)) => r.to_i64().map(|r| *l == r).unwrap_or(false),
            (Value::I128(l), Literal::Number(r)) => r.to_i128().map(|r| *l == r).unwrap_or(false),
            (Value::U8(l), Literal::Number(r)) => r.to_u8().map(|r| *l == r).unwrap_or(false),
            (Value::U16(l), Literal::Number(r)) => r.to_u16().map(|r| *l == r).unwrap_or(false),
            (Value::U32(l), Literal::Number(r)) => r.to_u32().map(|r| *l == r).unwrap_or(false),
            (Value::U64(l), Literal::Number(r)) => r.to_u64().map(|r| *l == r).unwrap_or(false),
            (Value::U128(l), Literal::Number(r)) => r.to_u128().map(|r| *l == r).unwrap_or(false),
            (Value::F32(l), Literal::Number(r)) => r.to_f32().map(|r| *l == r).unwrap_or(false),
            (Value::F64(l), Literal::Number(r)) => r.to_f64().map(|r| *l == r).unwrap_or(false),
            (Value::Str(l), Literal::Text(r)) => l == r.as_ref(),
            (Value::Bytea(l), Literal::Bytea(r)) => l == r,
            (Value::Date(l), Literal::Text(r)) => match r.parse::<NaiveDate>() {
                Ok(r) => l == &r,
                Err(_) => false,
            },
            (Value::Timestamp(l), Literal::Text(r)) => match parse_timestamp(r) {
                Some(r) => l == &r,
                None => false,
            },
            (Value::Time(l), Literal::Text(r)) => match parse_time(r) {
                Some(r) => l == &r,
                None => false,
            },
            (Value::Uuid(l), Literal::Text(r)) => parse_uuid(r).map(|r| l == &r).unwrap_or(false),
            (Value::Inet(l), Literal::Text(r)) => match IpAddr::from_str(r) {
                Ok(x) => l == &x,
                Err(_) => false,
            },
            (Value::Inet(l), Literal::Number(r)) => {
                if let Some(x) = r.to_u32() {
                    l == &Ipv4Addr::from(x)
                } else if let Some(x) = r.to_u128() {
                    l == &Ipv6Addr::from(x)
                } else {
                    false
                }
            }
            (Value::Null, Literal::Null) => false,
            _ => false,
        }
    }

    pub fn evaluate_cmp_with_literal(&self, other: &Literal<'_>) -> Option<Ordering> {
        match (self, other) {
            (Value::I8(l), Literal::Number(r)) => l.partial_cmp(&r.to_i8()?),
            (Value::I16(l), Literal::Number(r)) => l.partial_cmp(&r.to_i16()?),
            (Value::I32(l), Literal::Number(r)) => l.partial_cmp(&r.to_i32()?),
            (Value::I64(l), Literal::Number(r)) => l.partial_cmp(&r.to_i64()?),
            (Value::I128(l), Literal::Number(r)) => l.partial_cmp(&r.to_i128()?),
            (Value::U8(l), Literal::Number(r)) => l.partial_cmp(&r.to_u8()?),
            (Value::U16(l), Literal::Number(r)) => l.partial_cmp(&r.to_u16()?),
            (Value::U32(l), Literal::Number(r)) => l.partial_cmp(&r.to_u32()?),
            (Value::U64(l), Literal::Number(r)) => l.partial_cmp(&r.to_u64()?),
            (Value::U128(l), Literal::Number(r)) => l.partial_cmp(&r.to_u128()?),
            (Value::F32(l), Literal::Number(r)) => l.partial_cmp(&r.to_f32()?),
            (Value::F64(l), Literal::Number(r)) => l.partial_cmp(&r.to_f64()?),
            (Value::Decimal(l), Literal::Number(r)) => {
                BigDecimal::new(l.mantissa().into(), l.scale() as i64).partial_cmp(r)
            }
            (Value::Str(l), Literal::Text(r)) => Some(l.as_str().cmp(r)),
            (Value::Date(l), Literal::Text(r)) => l.partial_cmp(&r.parse::<NaiveDate>().ok()?),
            (Value::Timestamp(l), Literal::Text(r)) => l.partial_cmp(&parse_timestamp(r)?),
            (Value::Time(l), Literal::Text(r)) => l.partial_cmp(&parse_time(r)?),
            (Value::Uuid(l), Literal::Text(r)) => l.partial_cmp(&parse_uuid(r).ok()?),
            (Value::Inet(l), Literal::Text(r)) => l.partial_cmp(&IpAddr::from_str(r).ok()?),
            (Value::Inet(l), Literal::Number(r)) => {
                if let Some(x) = r.to_u32() {
                    l.partial_cmp(&Ipv4Addr::from(x))
                } else if let Some(x) = r.to_u128() {
                    l.partial_cmp(&Ipv6Addr::from(x))
                } else {
                    None
                }
            }
            _ => None,
        }
    }

    pub fn try_from_literal(data_type: &DataType, literal: &Literal<'_>) -> Result<Value> {
        match (data_type, literal) {
            (DataType::Boolean, Literal::Boolean(v)) => Ok(Value::Bool(*v)),
            (DataType::Int8, Literal::Number(v)) => v
                .to_i8()
                .map(Value::I8)
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            (DataType::Int16, Literal::Number(v)) => v
                .to_i16()
                .map(Value::I16)
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            (DataType::Int32, Literal::Number(v)) => v
                .to_i32()
                .map(Value::I32)
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            (DataType::Int, Literal::Number(v)) => v
                .to_i64()
                .map(Value::I64)
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            (DataType::Int128, Literal::Number(v)) => v
                .to_i128()
                .map(Value::I128)
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            (DataType::Uint8, Literal::Number(v)) => v
                .to_u8()
                .map(Value::U8)
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            (DataType::Uint16, Literal::Number(v)) => v
                .to_u16()
                .map(Value::U16)
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            (DataType::Uint32, Literal::Number(v)) => v
                .to_u32()
                .map(Value::U32)
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            (DataType::Uint64, Literal::Number(v)) => v
                .to_u64()
                .map(Value::U64)
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            (DataType::Uint128, Literal::Number(v)) => v
                .to_u128()
                .map(Value::U128)
                .ok_or_else(|| ValueError::FailedToParseNumber.into()),
            (DataType::Float32, Literal::Number(v)) => v
                .to_f32()
                .map(Value::F32)
                .ok_or_else(|| ValueError::UnreachableNumberParsing.into()),
            (DataType::Float, Literal::Number(v)) => v
                .to_f64()
                .map(Value::F64)
                .ok_or_else(|| ValueError::UnreachableNumberParsing.into()),
            (DataType::Text, Literal::Text(v)) => Ok(Value::Str(v.to_string())),
            (DataType::Bytea, Literal::Bytea(v)) => Ok(Value::Bytea(v.to_vec())),
            (DataType::Bytea, Literal::Text(v)) => hex::decode(v.as_ref())
                .map(Value::Bytea)
                .map_err(|_| ValueError::FailedToParseHexString(v.to_string()).into()),
            (DataType::Inet, Literal::Text(v)) => IpAddr::from_str(v.as_ref())
                .map(Value::Inet)
                .map_err(|_| ValueError::FailedToParseInetString(v.to_string()).into()),
            (DataType::Inet, Literal::Number(v)) => {
                if let Some(x) = v.to_u32() {
                    Ok(Value::Inet(IpAddr::V4(Ipv4Addr::from(x))))
                } else {
                    Ok(Value::Inet(IpAddr::V6(Ipv6Addr::from(
                        v.to_u128().unwrap(),
                    ))))
                }
            }
            (DataType::Date, Literal::Text(v)) => v
                .parse::<NaiveDate>()
                .map(Value::Date)
                .map_err(|_| ValueError::FailedToParseDate(v.to_string()).into()),
            (DataType::Timestamp, Literal::Text(v)) => parse_timestamp(v)
                .map(Value::Timestamp)
                .ok_or_else(|| ValueError::FailedToParseTimestamp(v.to_string()).into()),
            (DataType::Time, Literal::Text(v)) => parse_time(v)
                .map(Value::Time)
                .ok_or_else(|| ValueError::FailedToParseTime(v.to_string()).into()),
            (DataType::Uuid, Literal::Text(v)) => parse_uuid(v).map(Value::Uuid),
            (DataType::Uuid, Literal::Bytea(v)) => parse_uuid(&hex::encode(v)).map(Value::Uuid),
            (DataType::Map, Literal::Text(v)) => Value::parse_json_map(v),
            (DataType::List, Literal::Text(v)) => Value::parse_json_list(v),
            (DataType::Decimal, Literal::Number(v)) => v
                .to_string()
                .parse::<Decimal>()
                .map(Value::Decimal)
                .map_err(|_| ValueError::FailedToParseDecimal(v.to_string()).into()),
            (_, Literal::Null) => Ok(Value::Null),
            _ => Err(ValueError::IncompatibleLiteralForDataType {
                data_type: data_type.clone(),
                literal: format!("{:?}", literal),
            }
            .into()),
        }
    }

    pub fn try_cast_from_literal(data_type: &DataType, literal: &Literal<'_>) -> Result<Value> {
        match (data_type, literal) {
            (DataType::Boolean, Literal::Boolean(v)) => Ok(Value::Bool(*v)),
            (DataType::Boolean, Literal::Text(v)) => match v.to_uppercase().as_str() {
                "TRUE" | "1" => Ok(Value::Bool(true)),
                "FALSE" | "0" => Ok(Value::Bool(false)),
                _ => Err(ValueError::LiteralCastToBooleanFailed(v.to_string()).into()),
            },
            (DataType::Boolean, Literal::Number(v)) => match v.to_i64() {
                Some(0) => Ok(Value::Bool(false)),
                Some(1) => Ok(Value::Bool(true)),
                _ => Err(ValueError::LiteralCastToBooleanFailed(v.to_string()).into()),
            },
            (DataType::Int8, Literal::Text(v)) => v
                .parse::<i8>()
                .map(Value::I8)
                .map_err(|_| ValueError::LiteralCastFromTextToIntegerFailed(v.to_string()).into()),
            (DataType::Int8, Literal::Number(v)) => match v.to_i8() {
                Some(x) => Ok(Value::I8(x)),
                None => Err(ValueError::LiteralCastToInt8Failed(v.to_string()).into()),
            },
            (DataType::Int8, Literal::Boolean(v)) => {
                let v = i8::from(*v);

                Ok(Value::I8(v))
            }
            (DataType::Int16, Literal::Text(v)) => v
                .parse::<i16>()
                .map(Value::I16)
                .map_err(|_| ValueError::LiteralCastFromTextToIntegerFailed(v.to_string()).into()),
            (DataType::Int16, Literal::Number(v)) => match v.to_i16() {
                Some(x) => Ok(Value::I16(x)),
                None => Err(ValueError::LiteralCastToInt8Failed(v.to_string()).into()),
            },
            (DataType::Int16, Literal::Boolean(v)) => {
                let v = i16::from(*v);

                Ok(Value::I16(v))
            }
            (DataType::Int32, Literal::Text(v)) => v
                .parse::<i32>()
                .map(Value::I32)
                .map_err(|_| ValueError::LiteralCastFromTextToIntegerFailed(v.to_string()).into()),
            (DataType::Int32, Literal::Number(v)) => match v.to_i32() {
                Some(x) => Ok(Value::I32(x)),
                None => Err(ValueError::LiteralCastToDataTypeFailed(
                    DataType::Int32,
                    v.to_string(),
                )
                .into()),
            },
            (DataType::Int32, Literal::Boolean(v)) => {
                let v = i32::from(*v);

                Ok(Value::I32(v))
            }
            (DataType::Int, Literal::Text(v)) => v
                .parse::<i64>()
                .map(Value::I64)
                .map_err(|_| ValueError::LiteralCastFromTextToIntegerFailed(v.to_string()).into()),
            (DataType::Int, Literal::Number(v)) => match v.to_i64() {
                Some(x) => Ok(Value::I64(x)),
                None => Err(
                    ValueError::LiteralCastToDataTypeFailed(DataType::Int, v.to_string()).into(),
                ),
            },
            (DataType::Int, Literal::Boolean(v)) => {
                let v = i64::from(*v);

                Ok(Value::I64(v))
            }
            (DataType::Int128, Literal::Text(v)) => v
                .parse::<i128>()
                .map(Value::I128)
                .map_err(|_| ValueError::LiteralCastFromTextToIntegerFailed(v.to_string()).into()),
            (DataType::Int128, Literal::Number(v)) => match v.to_i128() {
                Some(x) => Ok(Value::I128(x)),
                None => Err(ValueError::LiteralCastToDataTypeFailed(
                    DataType::Int128,
                    v.to_string(),
                )
                .into()),
            },
            (DataType::Int128, Literal::Boolean(v)) => {
                let v = i128::from(*v);

                Ok(Value::I128(v))
            }
            (DataType::Uint8, Literal::Text(v)) => v.parse::<u8>().map(Value::U8).map_err(|_| {
                ValueError::LiteralCastFromTextToUnsignedInt8Failed(v.to_string()).into()
            }),
            (DataType::Uint8, Literal::Number(v)) => match v.to_u8() {
                Some(x) => Ok(Value::U8(x)),
                None => Err(ValueError::LiteralCastToUnsignedInt8Failed(v.to_string()).into()),
            },
            (DataType::Uint8, Literal::Boolean(v)) => {
                let v = u8::from(*v);

                Ok(Value::U8(v))
            }
            (DataType::Uint16, Literal::Text(v)) => v
                .parse::<u16>()
                .map(Value::U16)
                .map_err(|_| ValueError::LiteralCastFromTextToUint16Failed(v.to_string()).into()),
            (DataType::Uint16, Literal::Number(v)) => match v.to_u16() {
                Some(x) => Ok(Value::U16(x)),
                None => Err(ValueError::LiteralCastToUint16Failed(v.to_string()).into()),
            },
            (DataType::Uint16, Literal::Boolean(v)) => {
                let v = u16::from(*v);

                Ok(Value::U16(v))
            }
            (DataType::Uint32, Literal::Text(v)) => v
                .parse::<u32>()
                .map(Value::U32)
                .map_err(|_| ValueError::LiteralCastFromTextToUint32Failed(v.to_string()).into()),
            (DataType::Uint32, Literal::Number(v)) => match v.to_u32() {
                Some(x) => Ok(Value::U32(x)),
                None => Err(ValueError::LiteralCastToUint32Failed(v.to_string()).into()),
            },
            (DataType::Uint32, Literal::Boolean(v)) => {
                let v = u32::from(*v);

                Ok(Value::U32(v))
            }

            (DataType::Uint64, Literal::Text(v)) => v
                .parse::<u64>()
                .map(Value::U64)
                .map_err(|_| ValueError::LiteralCastFromTextToUint64Failed(v.to_string()).into()),
            (DataType::Uint64, Literal::Number(v)) => match v.to_u64() {
                Some(x) => Ok(Value::U64(x)),
                None => Err(ValueError::LiteralCastToUint64Failed(v.to_string()).into()),
            },
            (DataType::Uint64, Literal::Boolean(v)) => {
                let v = u64::from(*v);

                Ok(Value::U64(v))
            }

            (DataType::Uint128, Literal::Text(v)) => v
                .parse::<u128>()
                .map(Value::U128)
                .map_err(|_| ValueError::LiteralCastFromTextToUint128Failed(v.to_string()).into()),
            (DataType::Uint128, Literal::Number(v)) => match v.to_u128() {
                Some(x) => Ok(Value::U128(x)),
                None => Err(ValueError::LiteralCastToUint128Failed(v.to_string()).into()),
            },
            (DataType::Uint128, Literal::Boolean(v)) => {
                let v = u128::from(*v);

                Ok(Value::U128(v))
            }

            (DataType::Float32, Literal::Text(v)) => v
                .parse::<f32>()
                .map(Value::F32)
                .map_err(|_| ValueError::LiteralCastFromTextToFloatFailed(v.to_string()).into()),
            (DataType::Float32, Literal::Number(v)) => {
                v.to_f32().map(Value::F32).ok_or_else(|| {
                    ValueError::UnreachableLiteralCastFromNumberToFloat(v.to_string()).into()
                })
            }
            (DataType::Float32, Literal::Boolean(v)) => {
                let v = if *v { 1.0 } else { 0.0 };

                Ok(Value::F32(v))
            }
            (DataType::Float, Literal::Text(v)) => v
                .parse::<f64>()
                .map(Value::F64)
                .map_err(|_| ValueError::LiteralCastFromTextToFloatFailed(v.to_string()).into()),
            (DataType::Float, Literal::Number(v)) => v.to_f64().map(Value::F64).ok_or_else(|| {
                ValueError::UnreachableLiteralCastFromNumberToFloat(v.to_string()).into()
            }),
            (DataType::Float, Literal::Boolean(v)) => {
                let v = if *v { 1.0 } else { 0.0 };

                Ok(Value::F64(v))
            }
            (DataType::Decimal, Literal::Text(v)) => v
                .parse::<Decimal>()
                .map(Value::Decimal)
                .map_err(|_| ValueError::LiteralCastFromTextToDecimalFailed(v.to_string()).into()),
            (DataType::Decimal, Literal::Number(v)) => v
                .to_string()
                .parse::<Decimal>()
                .map(Value::Decimal)
                .map_err(|_| ValueError::LiteralCastFromTextToDecimalFailed(v.to_string()).into()),
            (DataType::Decimal, Literal::Boolean(v)) => {
                let v = if *v { Decimal::ONE } else { Decimal::ZERO };

                Ok(Value::Decimal(v))
            }

            (DataType::Text, Literal::Number(v)) => Ok(Value::Str(v.to_string())),
            (DataType::Text, Literal::Text(v)) => Ok(Value::Str(v.to_string())),
            (DataType::Text, Literal::Boolean(v)) => {
                let v = if *v { "TRUE" } else { "FALSE" };

                Ok(Value::Str(v.to_owned()))
            }
            (DataType::Interval, Literal::Text(v)) => {
                Interval::parse(v.as_ref()).map(Value::Interval)
            }
            (DataType::Uuid, Literal::Text(v)) => parse_uuid(v).map(Value::Uuid),
            (DataType::Boolean, Literal::Null)
            | (DataType::Int8, Literal::Null)
            | (DataType::Int16, Literal::Null)
            | (DataType::Int32, Literal::Null)
            | (DataType::Int, Literal::Null)
            | (DataType::Int128, Literal::Null)
            | (DataType::Uint8, Literal::Null)
            | (DataType::Uint16, Literal::Null)
            | (DataType::Uint32, Literal::Null)
            | (DataType::Uint64, Literal::Null)
            | (DataType::Uint128, Literal::Null)
            | (DataType::Float32, Literal::Null)
            | (DataType::Float, Literal::Null)
            | (DataType::Decimal, Literal::Null)
            | (DataType::Text, Literal::Null) => Ok(Value::Null),
            (DataType::Date, Literal::Text(v)) => parse_date(v)
                .map(Value::Date)
                .ok_or_else(|| ValueError::LiteralCastToDateFailed(v.to_string()).into()),
            (DataType::Time, Literal::Text(v)) => parse_time(v)
                .map(Value::Time)
                .ok_or_else(|| ValueError::LiteralCastToTimeFailed(v.to_string()).into()),
            (DataType::Timestamp, Literal::Text(v)) => parse_timestamp(v)
                .map(Value::Timestamp)
                .ok_or_else(|| ValueError::LiteralCastToTimestampFailed(v.to_string()).into()),
            (DataType::Inet, Literal::Number(v)) => {
                if let Some(x) = v.to_u32() {
                    Ok(Value::Inet(IpAddr::V4(Ipv4Addr::from(x))))
                } else if let Some(x) = v.to_u128() {
                    Ok(Value::Inet(IpAddr::V6(Ipv6Addr::from(x))))
                } else {
                    Err(ValueError::FailedToParseInetString(v.to_string()).into())
                }
            }
            (DataType::Inet, Literal::Text(v)) => IpAddr::from_str(v)
                .map(Value::Inet)
                .map_err(|_| ValueError::FailedToParseInetString(v.to_string()).into()),
            (DataType::Point, Literal::Text(v)) => Point::from_wkt(v)
                .map(Value::Point)
                .map_err(|_| ValueError::FailedToParsePoint(v.to_string()).into()),
            (DataType::Map, Literal::Text(v)) => Value::parse_json_map(v),
            (DataType::List, Literal::Text(v)) => Value::parse_json_list(v),
            _ => Err(ValueError::UnimplementedLiteralCast {
                data_type: data_type.clone(),
                literal: format!("{:?}", literal),
            }
            .into()),
        }
    }
}

#[cfg(test)]
mod tests {
    use {
        super::parse_uuid,
        crate::data::{Literal, Value},
        bigdecimal::BigDecimal,
        chrono::{NaiveDate, NaiveDateTime, NaiveTime},
        rust_decimal::Decimal,
        std::{
            borrow::Cow,
            cmp::Ordering,
            net::{IpAddr, Ipv4Addr, Ipv6Addr},
            str::FromStr,
        },
    };

    fn date(year: i32, month: u32, day: u32) -> NaiveDate {
        chrono::NaiveDate::from_ymd_opt(year, month, day).unwrap()
    }

    fn date_time(y: i32, m: u32, d: u32, hh: u32, mm: u32, ss: u32, ms: u32) -> NaiveDateTime {
        chrono::NaiveDate::from_ymd_opt(y, m, d)
            .unwrap()
            .and_hms_milli_opt(hh, mm, ss, ms)
            .unwrap()
    }

    fn time(hour: u32, min: u32, sec: u32, milli: u32) -> NaiveTime {
        chrono::NaiveTime::from_hms_milli_opt(hour, min, sec, milli).unwrap()
    }

    #[test]
    fn evaluate_eq_with_literal() {
        macro_rules! num {
            ($num: expr) => {
                &Literal::Number(Cow::Owned(BigDecimal::from_str($num).unwrap()))
            };
        }

        macro_rules! text {
            ($text: expr) => {
                &Literal::Text(Cow::Owned($text.to_owned()))
            };
        }

        let uuid_text = "936DA01F9ABD4d9d80C702AF85C822A8";
        let uuid = parse_uuid(uuid_text).unwrap();

        let bytea = || hex::decode("123456").unwrap();
        let inet = |v: &str| Value::Inet(IpAddr::from_str(v).unwrap());

        assert!(Value::Bool(true).evaluate_eq_with_literal(&Literal::Boolean(true)));
        assert!(Value::I8(8).evaluate_eq_with_literal(num!("8")));
        assert!(Value::I32(32).evaluate_eq_with_literal(num!("32")));
        assert!(Value::I16(16).evaluate_eq_with_literal(num!("16")));
        assert!(Value::I32(32).evaluate_eq_with_literal(num!("32")));
        assert!(Value::I64(64).evaluate_eq_with_literal(num!("64")));
        assert!(Value::I128(128).evaluate_eq_with_literal(num!("128")));
        assert!(Value::U8(7).evaluate_eq_with_literal(num!("7")));
        assert!(Value::U16(64).evaluate_eq_with_literal(num!("64")));
        assert!(Value::U32(64).evaluate_eq_with_literal(num!("64")));
        assert!(Value::U64(64).evaluate_eq_with_literal(num!("64")));
        assert!(Value::U128(64).evaluate_eq_with_literal(num!("64")));
        assert!(Value::F32(7.123).evaluate_eq_with_literal(num!("7.123")));
        assert!(Value::F64(7.123).evaluate_eq_with_literal(num!("7.123")));
        assert!(Value::Str("Hello".to_owned()).evaluate_eq_with_literal(text!("Hello")));
        assert!(Value::Bytea(bytea()).evaluate_eq_with_literal(&Literal::Bytea(bytea())));
        assert!(inet("127.0.0.1").evaluate_eq_with_literal(text!("127.0.0.1")));
        assert!(inet("::1").evaluate_eq_with_literal(text!("::1")));
        assert!(inet("0.0.0.0").evaluate_eq_with_literal(num!("0")));
        assert!(!inet("::1").evaluate_eq_with_literal(num!("0")));
        assert!(inet("::2:4cb0:16ea").evaluate_eq_with_literal(num!("9876543210")));
        assert!(!inet("::1").evaluate_eq_with_literal(text!("-1")));
        assert!(!inet("::1").evaluate_eq_with_literal(num!("-1")));
        assert!(Value::Date(date(2021, 11, 20)).evaluate_eq_with_literal(text!("2021-11-20")));
        assert!(!Value::Date(date(2021, 11, 20)).evaluate_eq_with_literal(text!("202=abcdef")));
        assert!(
            Value::Timestamp(date_time(2021, 11, 20, 10, 0, 0, 0))
                .evaluate_eq_with_literal(text!("2021-11-20T10:00:00Z"))
        );
        assert!(
            !Value::Timestamp(date_time(2021, 11, 20, 10, 0, 0, 0))
                .evaluate_eq_with_literal(text!("2021-11-Hello"))
        );
        assert!(Value::Time(time(10, 0, 0, 0)).evaluate_eq_with_literal(text!("10:00:00")));
        assert!(!Value::Time(time(10, 0, 0, 0)).evaluate_eq_with_literal(text!("FALSE")));
        assert!(Value::Uuid(uuid).evaluate_eq_with_literal(text!(uuid_text)));
    }

    #[test]
    fn evaluate_cmp_with_literal() {
        let num = |n| Literal::Number(Cow::Owned(BigDecimal::from(n)));
        let text = |v: &str| Literal::Text(Cow::Owned(v.to_owned()));

        let test = |value: Value, literal, expected| {
            assert_eq!(value.evaluate_cmp_with_literal(&literal), expected);
        };

        test(Value::I8(1), num(1), Some(Ordering::Equal));
        test(Value::I16(1), num(2), Some(Ordering::Less));
        test(Value::I32(10), num(3), Some(Ordering::Greater));
        test(Value::I64(10), num(10), Some(Ordering::Equal));
        test(Value::I128(10), num(10), Some(Ordering::Equal));
        test(Value::U8(1), num(1), Some(Ordering::Equal));
        test(Value::U16(1), num(2), Some(Ordering::Less));
        test(Value::U32(10), num(3), Some(Ordering::Greater));
        test(Value::U64(10), num(10), Some(Ordering::Equal));
        test(Value::U128(10), num(10), Some(Ordering::Equal));
        test(Value::F32(10.0), num(10), Some(Ordering::Equal));
        test(Value::F64(10.0), num(10), Some(Ordering::Equal));
        test(
            Value::Decimal(Decimal::new(215, 2)),
            num(3),
            Some(Ordering::Less),
        );
        test(
            Value::Str("Hello".to_owned()),
            text("Hello"),
            Some(Ordering::Equal),
        );
        test(
            Value::Date(date(2021, 11, 21)),
            text("2021-11-21"),
            Some(Ordering::Equal),
        );
        test(
            Value::Timestamp(date_time(2021, 11, 21, 10, 0, 0, 0)),
            text("2021-11-21T10:00:00Z"),
            Some(Ordering::Equal),
        );
        test(
            Value::Time(time(10, 0, 0, 0)),
            text("10:00:00"),
            Some(Ordering::Equal),
        );
        test(
            Value::Uuid(parse_uuid("936DA01F9ABD4d9d80C702AF85C822A8").unwrap()),
            text("936DA01F9ABD4d9d80C702AF85C822A8"),
            Some(Ordering::Equal),
        );
        test(
            Value::Inet(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
            text("215.87.1.1"),
            Some(Ordering::Less),
        );
        test(
            Value::Inet(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))),
            text("215.87.1.1"),
            Some(Ordering::Less),
        );
        test(
            Value::Inet(IpAddr::V4(Ipv4Addr::new(255, 255, 255, 255))),
            Literal::Number(Cow::Owned(BigDecimal::new(4294967295u32.into(), 0))),
            Some(Ordering::Equal),
        );
        test(
            Value::Inet(IpAddr::from_str("::2:4cb0:16ea").unwrap()),
            Literal::Number(Cow::Owned(BigDecimal::new(9876543210u128.into(), 0))),
            Some(Ordering::Equal),
        );
        test(Value::Null, num(1), None);
    }

    #[test]
    fn timestamp_literal() {
        macro_rules! test (
            ($timestamp: literal, $result: expr) => {
                assert_eq!(super::parse_timestamp($timestamp), Some($result));
            }
        );

        test!("2022-12-20T10:00:00Z", date_time(2022, 12, 20, 10, 0, 0, 0));
        test!(
            "2022-12-20T10:00:00.132Z",
            date_time(2022, 12, 20, 10, 0, 0, 132)
        );
        test!(
            "2022-12-20T10:00:00.132+09:00",
            date_time(2022, 12, 20, 1, 0, 0, 132)
        );
        test!("2022-11-21", date_time(2022, 11, 21, 0, 0, 0, 0));
        test!("2022-12-20T10:00:00", date_time(2022, 12, 20, 10, 0, 0, 0));
        test!("2022-12-20 10:00:00Z", date_time(2022, 12, 20, 10, 0, 0, 0));
        test!("2022-12-20 10:00:00", date_time(2022, 12, 20, 10, 0, 0, 0));
        test!(
            "2022-12-20 10:00:00.987",
            date_time(2022, 12, 20, 10, 0, 0, 987)
        );
    }

    #[test]
    fn time_literal() {
        macro_rules! test (
            ($time: literal, $result: expr) => {
                assert_eq!(super::parse_time($time), Some($result));
            }
        );

        test!("12:00:35", time(12, 0, 35, 0));
        test!("12:00:35.917", time(12, 0, 35, 917));
        test!("AM 08:00", time(8, 0, 0, 0));
        test!("PM 8:00", time(20, 0, 0, 0));
        test!("AM 09:30:37", time(9, 30, 37, 0));
        test!("PM 3:30:37", time(15, 30, 37, 0));
        test!("PM 03:30:37.123", time(15, 30, 37, 123));
        test!("AM 9:30:37.917", time(9, 30, 37, 917));
        test!("08:00 AM", time(8, 0, 0, 0));
        test!("8:00 PM", time(20, 0, 0, 0));
        test!("09:30:37 AM", time(9, 30, 37, 0));
        test!("3:30:37 PM", time(15, 30, 37, 0));
        test!("03:30:37.123 PM", time(15, 30, 37, 123));
        test!("9:30:37.917 AM", time(9, 30, 37, 917));
    }

    #[test]
    fn try_from_literal() {
        use {
            crate::{ast::DataType, data::ValueError},
            chrono::NaiveDate,
            rust_decimal::Decimal,
            std::{borrow::Cow, str::FromStr},
        };

        macro_rules! num {
            ($num: expr) => {
                Literal::Number(Cow::Owned(BigDecimal::from_str($num).unwrap()))
            };
        }

        macro_rules! text {
            ($text: expr) => {
                Literal::Text(Cow::Owned($text.to_owned()))
            };
        }

        macro_rules! test {
            ($to: expr, $from: expr, $expected: expr) => {
                assert_eq!(Value::try_from_literal(&$to, &$from), Ok($expected));
            };
        }

        let bytea = |v| hex::decode(v).unwrap();
        let inet = |v| IpAddr::from_str(v).unwrap();

        test!(DataType::Boolean, Literal::Boolean(true), Value::Bool(true));
        test!(DataType::Int, num!("123456789"), Value::I64(123456789));
        test!(DataType::Int8, num!("64"), Value::I8(64));
        test!(DataType::Int16, num!("64"), Value::I16(64));
        test!(DataType::Int32, num!("64"), Value::I32(64));
        test!(DataType::Int, num!("64"), Value::I64(64));
        test!(DataType::Int128, num!("64"), Value::I128(64));
        test!(DataType::Uint8, num!("8"), Value::U8(8));
        test!(DataType::Uint16, num!("64"), Value::U16(64));
        test!(DataType::Uint32, num!("64"), Value::U32(64));
        test!(DataType::Uint64, num!("64"), Value::U64(64));
        test!(DataType::Uint128, num!("64"), Value::U128(64));
        test!(
            DataType::Float32,
            num!("123456789"),
            Value::F32(123456789.0_f32)
        );
        test!(DataType::Float, num!("123456789"), Value::F64(123456789.0));
        test!(
            DataType::Text,
            text!("Good!"),
            Value::Str("Good!".to_owned())
        );
        test!(
            DataType::Bytea,
            Literal::Bytea(bytea("1234")),
            Value::Bytea(bytea("1234"))
        );
        test!(DataType::Bytea, text!("1234"), Value::Bytea(bytea("1234")));
        assert_eq!(
            Value::try_from_literal(&DataType::Bytea, &text!("123")),
            Err(ValueError::FailedToParseHexString("123".to_owned()).into())
        );
        test!(DataType::Inet, text!("::1"), Value::Inet(inet("::1")));
        test!(
            DataType::Inet,
            num!("4294967295"),
            Value::Inet(inet("255.255.255.255"))
        );
        test!(
            DataType::Inet,
            num!("9876543210"),
            Value::Inet(inet("::2:4cb0:16ea"))
        );
        test!(
            DataType::Inet,
            num!("9876543210"),
            Value::Inet(inet("::2:4cb0:16ea"))
        );
        assert_eq!(
            Value::try_from_literal(&DataType::Inet, &text!("123")),
            Err(ValueError::FailedToParseInetString("123".to_owned()).into())
        );
        test!(
            DataType::Date,
            text!("2015-09-05"),
            Value::Date(NaiveDate::from_ymd_opt(2015, 9, 5).unwrap())
        );
        test!(
            DataType::Timestamp,
            text!("2022-12-20 10:00:00.987"),
            Value::Timestamp(date_time(2022, 12, 20, 10, 0, 0, 987))
        );
        test!(
            DataType::Time,
            text!("12:00:35"),
            Value::Time(chrono::NaiveTime::from_hms_milli_opt(12, 0, 35, 0).unwrap())
        );
        test!(
            DataType::Uuid,
            text!("936DA01F9ABD4d9d80C702AF85C822A8"),
            Value::Uuid(195965723427462096757863453463987888808)
        );
        test!(
            DataType::Uuid,
            Literal::Bytea(bytea("936DA01F9ABD4d9d80C702AF85C822A8")),
            Value::Uuid(195965723427462096757863453463987888808)
        );

        assert_eq!(
            Value::try_from_literal(
                &DataType::Map,
                &text!(
                    r#"{
            "name": "John Doe",
            "age": 43
        }"#
                )
            ),
            Value::parse_json_map(
                r#"{
            "name": "John Doe",
            "age": 43
        }"#
            )
        );
        assert_eq!(
            Value::try_from_literal(
                &DataType::List,
                &text!(
                    r#"[
            "+44 1234567",
            "+44 2345678"
        ]"#
                )
            ),
            Value::parse_json_list(
                r#"[
            "+44 1234567",
            "+44 2345678"
        ]"#
            )
        );
        test!(
            DataType::Decimal,
            num!("200"),
            Value::Decimal(Decimal::new(200, 0))
        );
    }

    #[test]
    fn try_from() {
        use std::{borrow::Cow, str::FromStr};

        macro_rules! text {
            ($text: expr) => {
                Literal::Text(Cow::Owned($text.to_owned()))
            };
        }

        macro_rules! num {
            ($num: expr) => {
                &Literal::Number(Cow::Owned(BigDecimal::from_str($num).unwrap()))
            };
        }

        let bytea = |v| hex::decode(v).unwrap();

        macro_rules! test {
            ($from: expr, $expected: expr) => {
                assert!(Value::try_from($from).unwrap().evaluate_eq(&$expected));
            };
        }

        test!(text!("hello"), Value::Str("hello".to_owned()));
        test!(&text!("hallo"), Value::Str("hallo".to_owned()));
        test!(Literal::Bytea(bytea("1234")), Value::Bytea(bytea("1234")));
        test!(&Literal::Bytea(bytea("1234")), Value::Bytea(bytea("1234")));
        test!(num!("1234567890"), Value::I64(1234567890));
        test!(num!("1.0"), Value::F32(1.0_f32));
        test!(num!("1.0"), Value::F64(1.0));
        test!(&Literal::Boolean(false), Value::Bool(false));
        assert!(matches!(Value::try_from(&Literal::Null), Ok(Value::Null)))
    }

    #[test]
    fn try_cast_from_literal() {
        use {
            crate::{ast::DataType, data::Interval as I},
            chrono::NaiveDate,
            std::{borrow::Cow, str::FromStr},
        };

        macro_rules! text {
            ($text: expr) => {
                Literal::Text(Cow::Owned($text.to_owned()))
            };
        }

        macro_rules! num {
            ($num: expr) => {
                &Literal::Number(Cow::Owned(BigDecimal::from_str($num).unwrap()))
            };
        }

        macro_rules! test {
            ($to: expr, $from: expr, $expected: expr) => {
                let actual = Value::try_cast_from_literal(&$to, &$from);

                assert_eq!(actual, Ok($expected))
            };
        }

        macro_rules! test_null {
            ($to: expr, $from: expr) => {
                assert!(matches!(
                    Value::try_cast_from_literal(&$to, &$from),
                    Ok(Value::Null)
                ))
            };
        }

        let timestamp = |y, m, d, hh, mm, ss, ms| {
            chrono::NaiveDate::from_ymd_opt(y, m, d)
                .unwrap()
                .and_hms_milli_opt(hh, mm, ss, ms)
                .unwrap()
        };

        test!(
            DataType::Boolean,
            Literal::Boolean(false),
            Value::Bool(false)
        );
        test!(DataType::Boolean, text!("false"), Value::Bool(false));
        test!(DataType::Boolean, text!("true"), Value::Bool(true));
        test!(DataType::Boolean, num!("0"), Value::Bool(false));
        test!(DataType::Boolean, num!("1"), Value::Bool(true));

        test!(DataType::Int8, text!("127"), Value::I8(127));
        test!(DataType::Int8, num!("125"), Value::I8(125));
        test!(DataType::Int8, Literal::Boolean(true), Value::I8(1));
        test!(DataType::Int8, Literal::Boolean(false), Value::I8(0));

        test!(DataType::Int16, text!("127"), Value::I16(127));
        test!(DataType::Int16, num!("125"), Value::I16(125));
        test!(DataType::Int16, Literal::Boolean(true), Value::I16(1));
        test!(DataType::Int16, Literal::Boolean(false), Value::I16(0));

        test!(DataType::Int32, text!("127"), Value::I32(127));
        test!(DataType::Int32, num!("125"), Value::I32(125));
        test!(DataType::Int32, Literal::Boolean(true), Value::I32(1));
        test!(DataType::Int32, Literal::Boolean(false), Value::I32(0));

        test!(DataType::Int, text!("1234567890"), Value::I64(1234567890));
        test!(DataType::Int, num!("1234567890"), Value::I64(1234567890));
        test!(DataType::Int, Literal::Boolean(true), Value::I64(1));
        test!(DataType::Int, Literal::Boolean(false), Value::I64(0));
        test!(DataType::Int128, text!("127"), Value::I128(127));
        test!(DataType::Int128, num!("125"), Value::I128(125));
        test!(DataType::Int128, Literal::Boolean(true), Value::I128(1));
        test!(DataType::Int128, Literal::Boolean(false), Value::I128(0));

        test!(DataType::Uint8, text!("127"), Value::U8(127));
        test!(DataType::Uint8, num!("125"), Value::U8(125));
        test!(DataType::Uint8, Literal::Boolean(true), Value::U8(1));
        test!(DataType::Uint8, Literal::Boolean(false), Value::U8(0));

        test!(DataType::Uint16, text!("127"), Value::U16(127));
        test!(DataType::Uint16, num!("125"), Value::U16(125));
        test!(DataType::Uint16, Literal::Boolean(true), Value::U16(1));
        test!(DataType::Uint16, Literal::Boolean(false), Value::U16(0));

        test!(DataType::Uint32, text!("127"), Value::U32(127));
        test!(DataType::Uint32, num!("125"), Value::U32(125));
        test!(DataType::Uint32, Literal::Boolean(true), Value::U32(1));
        test!(DataType::Uint32, Literal::Boolean(false), Value::U32(0));

        test!(DataType::Uint64, text!("127"), Value::U64(127));
        test!(DataType::Uint64, num!("125"), Value::U64(125));
        test!(DataType::Uint64, Literal::Boolean(true), Value::U64(1));
        test!(DataType::Uint64, Literal::Boolean(false), Value::U64(0));

        test!(DataType::Uint128, text!("127"), Value::U128(127));
        test!(DataType::Uint128, num!("125"), Value::U128(125));
        test!(DataType::Uint128, Literal::Boolean(true), Value::U128(1));
        test!(DataType::Uint128, Literal::Boolean(false), Value::U128(0));

        test!(
            DataType::Float32,
            text!("12345.67"),
            Value::F32(12345.67_f32)
        );
        test!(
            DataType::Float32,
            num!("123456.78"),
            Value::F32(123456.78_f32)
        );
        test!(
            DataType::Float32,
            Literal::Boolean(true),
            Value::F32(1.0_f32)
        );
        test!(
            DataType::Float32,
            Literal::Boolean(false),
            Value::F32(0.0_f32)
        );

        test!(DataType::Float, text!("12345.6789"), Value::F64(12345.6789));
        test!(DataType::Float, num!("123456.789"), Value::F64(123456.789));
        test!(DataType::Float, Literal::Boolean(true), Value::F64(1.0));
        test!(DataType::Float, Literal::Boolean(false), Value::F64(0.0));
        test!(
            DataType::Text,
            num!("1234567890"),
            Value::Str("1234567890".to_owned())
        );
        test!(DataType::Text, text!("Cow"), Value::Str("Cow".to_owned()));
        test!(
            DataType::Text,
            Literal::Boolean(true),
            Value::Str("TRUE".to_owned())
        );
        test!(
            DataType::Text,
            Literal::Boolean(false),
            Value::Str("FALSE".to_owned())
        );
        test!(
            DataType::Interval,
            text!("'+22-10' YEAR TO MONTH"),
            Value::Interval(I::Month(274))
        );
        test!(
            DataType::Uuid,
            text!("936DA01F9ABD4d9d80C702AF85C822A8"),
            Value::Uuid(195965723427462096757863453463987888808)
        );
        test_null!(DataType::Boolean, Literal::Null);
        test_null!(DataType::Int, Literal::Null);
        test_null!(DataType::Int8, Literal::Null);
        test_null!(DataType::Uint8, Literal::Null);
        test_null!(DataType::Uint16, Literal::Null);
        test_null!(DataType::Uint32, Literal::Null);
        test_null!(DataType::Uint64, Literal::Null);
        test_null!(DataType::Uint128, Literal::Null);
        test_null!(DataType::Float32, Literal::Null);
        test_null!(DataType::Float, Literal::Null);
        test_null!(DataType::Text, Literal::Null);
        test!(
            DataType::Date,
            text!("2015-09-05"),
            Value::Date(NaiveDate::from_ymd_opt(2015, 9, 5).unwrap())
        );
        test!(
            DataType::Time,
            text!("12:00:35"),
            Value::Time(chrono::NaiveTime::from_hms_milli_opt(12, 0, 35, 0).unwrap())
        );
        test!(
            DataType::Timestamp,
            text!("2022-12-20 10:00:00.987"),
            Value::Timestamp(timestamp(2022, 12, 20, 10, 0, 0, 987))
        );
        test!(
            DataType::Inet,
            num!("1234567890"),
            Value::Inet(IpAddr::from(Ipv4Addr::from(1234567890)))
        );
        test!(
            DataType::Inet,
            num!("91234567890"),
            Value::Inet(IpAddr::from(Ipv6Addr::from(91234567890)))
        );
        test!(
            DataType::Inet,
            text!("::1"),
            Value::Inet(IpAddr::from_str("::1").unwrap())
        );
        test!(
            DataType::Map,
            text!(r#"{ "a": 1 }"#),
            Value::parse_json_map(r#"{ "a": 1 }"#).unwrap()
        );
        test!(
            DataType::List,
            text!(r#"[ 1, 2, 3 ]"#),
            Value::parse_json_list(r#"[ 1, 2, 3 ]"#).unwrap()
        );
    }
}
