//! Query builder for Appwrite SDK

use serde::Serialize;
use serde_json::Value;

/// Query builder for filtering and sorting database queries
#[derive(Debug, Clone, Serialize)]
pub struct Query {
    method: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    attribute: Option<String>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    values: Vec<Value>,
}

impl Query {
    fn new(method: String, attribute: Option<String>, values: Vec<Value>) -> Self {
        Self {
            method,
            attribute,
            values,
        }
    }

    fn to_array(value: Value) -> Vec<Value> {
        match value {
            Value::Array(arr) => arr,
            _ => vec![value],
        }
    }

    pub fn equal<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("equal".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn not_equal<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("notEqual".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn less_than<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("lessThan".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn less_than_equal<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("lessThanEqual".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn greater_than<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("greaterThan".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn greater_than_equal<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("greaterThanEqual".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn is_null<S: Into<String>>(attribute: S) -> Self {
        Self::new("isNull".to_string(), Some(attribute.into()), vec![])
    }

    pub fn is_not_null<S: Into<String>>(attribute: S) -> Self {
        Self::new("isNotNull".to_string(), Some(attribute.into()), vec![])
    }

    pub fn between<S: Into<String>, V: Into<Value>>(attribute: S, start: V, end: V) -> Self {
        Self::new("between".to_string(), Some(attribute.into()), vec![start.into(), end.into()])
    }

    pub fn starts_with<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("startsWith".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn ends_with<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("endsWith".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn select<I: IntoIterator<Item = S>, S: Into<String>>(attributes: I) -> Self {
        let values: Vec<Value> = attributes.into_iter().map(|s| Value::String(s.into())).collect();
        Self::new("select".to_string(), None, values)
    }

    pub fn search<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("search".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn not_search<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("notSearch".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn order_asc<S: Into<String>>(attribute: S) -> Self {
        Self::new("orderAsc".to_string(), Some(attribute.into()), vec![])
    }

    pub fn order_desc<S: Into<String>>(attribute: S) -> Self {
        Self::new("orderDesc".to_string(), Some(attribute.into()), vec![])
    }

    pub fn order_random() -> Self {
        Self::new("orderRandom".to_string(), None, vec![])
    }

    pub fn cursor_after<S: Into<String>>(document_id: S) -> Self {
        Self::new("cursorAfter".to_string(), None, vec![Value::String(document_id.into())])
    }

    pub fn cursor_before<S: Into<String>>(document_id: S) -> Self {
        Self::new("cursorBefore".to_string(), None, vec![Value::String(document_id.into())])
    }

    pub fn limit(value: u32) -> Self {
        Self::new("limit".to_string(), None, vec![Value::Number(value.into())])
    }

    pub fn offset(value: u32) -> Self {
        Self::new("offset".to_string(), None, vec![Value::Number(value.into())])
    }

    pub fn contains<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("contains".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn contains_any<S: Into<String>, V: Into<Value>>(attribute: S, values: Vec<V>) -> Self {
        Self::new("containsAny".to_string(), Some(attribute.into()), values.into_iter().map(|v| v.into()).collect())
    }

    pub fn contains_all<S: Into<String>, V: Into<Value>>(attribute: S, values: Vec<V>) -> Self {
        Self::new("containsAll".to_string(), Some(attribute.into()), values.into_iter().map(|v| v.into()).collect())
    }

    pub fn not_contains<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("notContains".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn not_between<S: Into<String>, V: Into<Value>>(attribute: S, start: V, end: V) -> Self {
        Self::new("notBetween".to_string(), Some(attribute.into()), vec![start.into(), end.into()])
    }

    pub fn not_starts_with<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("notStartsWith".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn not_ends_with<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("notEndsWith".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn created_before<V: Into<Value>>(value: V) -> Self {
        Self::less_than("$createdAt", value)
    }

    pub fn created_after<V: Into<Value>>(value: V) -> Self {
        Self::greater_than("$createdAt", value)
    }

    pub fn created_between<V: Into<Value>>(start: V, end: V) -> Self {
        Self::between("$createdAt", start, end)
    }

    pub fn updated_before<V: Into<Value>>(value: V) -> Self {
        Self::less_than("$updatedAt", value)
    }

    pub fn updated_after<V: Into<Value>>(value: V) -> Self {
        Self::greater_than("$updatedAt", value)
    }

    pub fn updated_between<V: Into<Value>>(start: V, end: V) -> Self {
        Self::between("$updatedAt", start, end)
    }

    pub fn distance_equal<S: Into<String>, V: Into<Value>>(attribute: S, values: V, distance: impl Into<Value>, meters: bool) -> Self {
        let params = Value::Array(vec![values.into(), distance.into(), Value::Bool(meters)]);
        Self::new("distanceEqual".to_string(), Some(attribute.into()), vec![params])
    }

    pub fn distance_not_equal<S: Into<String>, V: Into<Value>>(attribute: S, values: V, distance: impl Into<Value>, meters: bool) -> Self {
        let params = Value::Array(vec![values.into(), distance.into(), Value::Bool(meters)]);
        Self::new("distanceNotEqual".to_string(), Some(attribute.into()), vec![params])
    }

    pub fn distance_greater_than<S: Into<String>, V: Into<Value>>(attribute: S, values: V, distance: impl Into<Value>, meters: bool) -> Self {
        let params = Value::Array(vec![values.into(), distance.into(), Value::Bool(meters)]);
        Self::new("distanceGreaterThan".to_string(), Some(attribute.into()), vec![params])
    }

    pub fn distance_less_than<S: Into<String>, V: Into<Value>>(attribute: S, values: V, distance: impl Into<Value>, meters: bool) -> Self {
        let params = Value::Array(vec![values.into(), distance.into(), Value::Bool(meters)]);
        Self::new("distanceLessThan".to_string(), Some(attribute.into()), vec![params])
    }

    pub fn intersects<S: Into<String>, V: Into<Value>>(attribute: S, values: V) -> Self {
        Self::new("intersects".to_string(), Some(attribute.into()), vec![values.into()])
    }

    pub fn not_intersects<S: Into<String>, V: Into<Value>>(attribute: S, values: V) -> Self {
        Self::new("notIntersects".to_string(), Some(attribute.into()), vec![values.into()])
    }

    pub fn crosses<S: Into<String>, V: Into<Value>>(attribute: S, values: V) -> Self {
        Self::new("crosses".to_string(), Some(attribute.into()), vec![values.into()])
    }

    pub fn not_crosses<S: Into<String>, V: Into<Value>>(attribute: S, values: V) -> Self {
        Self::new("notCrosses".to_string(), Some(attribute.into()), vec![values.into()])
    }

    pub fn overlaps<S: Into<String>, V: Into<Value>>(attribute: S, values: V) -> Self {
        Self::new("overlaps".to_string(), Some(attribute.into()), vec![values.into()])
    }

    pub fn not_overlaps<S: Into<String>, V: Into<Value>>(attribute: S, values: V) -> Self {
        Self::new("notOverlaps".to_string(), Some(attribute.into()), vec![values.into()])
    }

    pub fn touches<S: Into<String>, V: Into<Value>>(attribute: S, values: V) -> Self {
        Self::new("touches".to_string(), Some(attribute.into()), vec![values.into()])
    }

    pub fn not_touches<S: Into<String>, V: Into<Value>>(attribute: S, values: V) -> Self {
        Self::new("notTouches".to_string(), Some(attribute.into()), vec![values.into()])
    }

    pub fn or<I, S>(queries: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<str>,
    {
        let values: Vec<Value> = queries
            .into_iter()
            .filter_map(|query| serde_json::from_str(query.as_ref()).ok())
            .collect();
        Self::new("or".to_string(), None, values)
    }

    pub fn and<I, S>(queries: I) -> Self
    where
        I: IntoIterator<Item = S>,
        S: AsRef<str>,
    {
        let values: Vec<Value> = queries
            .into_iter()
            .filter_map(|query| serde_json::from_str(query.as_ref()).ok())
            .collect();
        Self::new("and".to_string(), None, values)
    }

    pub fn regex<S: Into<String>, V: Into<Value>>(attribute: S, value: V) -> Self {
        Self::new("regex".to_string(), Some(attribute.into()), Self::to_array(value.into()))
    }

    pub fn exists<V: Into<Value>>(attributes: Vec<V>) -> Self {
        Self::new("exists".to_string(), None, attributes.into_iter().map(|v| v.into()).collect())
    }

    pub fn not_exists<V: Into<Value>>(attributes: Vec<V>) -> Self {
        Self::new("notExists".to_string(), None, attributes.into_iter().map(|v| v.into()).collect())
    }

    pub fn elem_match<S, I, Q>(attribute: S, queries: I) -> Self
    where
        S: Into<String>,
        I: IntoIterator<Item = Q>,
        Q: AsRef<str>,
    {
        let values: Vec<Value> = queries
            .into_iter()
            .filter_map(|query| serde_json::from_str(query.as_ref()).ok())
            .collect();
        Self::new("elemMatch".to_string(), Some(attribute.into()), values)
    }

    /// Convert query to JSON value (matches Go/Python SDK format)
    pub fn to_value(self) -> Value {
        let mut obj = serde_json::Map::new();
        obj.insert("method".to_string(), Value::String(self.method));

        if let Some(attr) = self.attribute {
            obj.insert("attribute".to_string(), Value::String(attr));
        }

        if !self.values.is_empty() {
            obj.insert("values".to_string(), Value::Array(self.values));
        }

        Value::Object(obj)
    }
}

impl std::fmt::Display for Query {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let json_str = serde_json::to_string(self)
            .unwrap_or_else(|_| String::new());
        write!(f, "{}", json_str)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_equal_query() {
        let query = Query::equal("name", "John");
        let value = query.to_value();
        assert_eq!(value["method"], "equal");
        assert_eq!(value["attribute"], "name");
        assert_eq!(value["values"][0], "John");
    }

    #[test]
    fn test_greater_than_query() {
        let query = Query::greater_than("age", 18);
        let value = query.to_value();
        assert_eq!(value["method"], "greaterThan");
        assert_eq!(value["attribute"], "age");
        assert_eq!(value["values"][0], 18);
    }

    #[test]
    fn test_between_query() {
        let query = Query::between("age", 18, 65);
        let value = query.to_value();
        assert_eq!(value["method"], "between");
        assert_eq!(value["attribute"], "age");
        assert_eq!(value["values"][0], 18);
        assert_eq!(value["values"][1], 65);
    }

    #[test]
    fn test_select_query() {
        let query = Query::select(vec!["name", "age"]);
        let value = query.to_value();
        assert_eq!(value["method"], "select");
        assert_eq!(value["values"][0], "name");
        assert_eq!(value["values"][1], "age");
    }

    #[test]
    fn test_order_asc_query() {
        let query = Query::order_asc("name");
        let value = query.to_value();
        assert_eq!(value["method"], "orderAsc");
        assert_eq!(value["attribute"], "name");
    }

    #[test]
    fn test_limit_query() {
        let query = Query::limit(10);
        let value = query.to_value();
        assert_eq!(value["method"], "limit");
        assert_eq!(value["values"][0], 10);
    }

    #[test]
    fn test_or_query() {
        let query_strings = vec![
            Query::equal("released", true).to_string(),
            Query::less_than("releasedYear", 1990).to_string(),
        ];
        let query = Query::or(query_strings);
        let value = query.to_value();
        assert_eq!(value["method"], "or");
        assert!(value["values"].is_array());
        assert_eq!(value["values"].as_array().unwrap().len(), 2);
    }

    #[test]
    fn test_and_query() {
        let query_strings = vec![
            Query::equal("released", false).to_string(),
            Query::greater_than("releasedYear", 2015).to_string(),
        ];
        let query = Query::and(query_strings);
        let value = query.to_value();
        assert_eq!(value["method"], "and");
        assert!(value["values"].is_array());
        assert_eq!(value["values"].as_array().unwrap().len(), 2);
    }

    #[test]
    fn test_or_invalid_json_skipped() {
        let mixed_queries = vec![
            Query::equal("released", true).to_string(),
            "not valid json".to_string(),
            Query::less_than("releasedYear", 1990).to_string(),
        ];
        let query = Query::or(mixed_queries);
        let value = query.to_value();
        assert_eq!(value["method"], "or");
        assert_eq!(value["values"].as_array().unwrap().len(), 2);
    }

    #[test]
    fn test_and_invalid_json_skipped() {
        let mixed_queries = vec![
            "not valid json".to_string(),
            Query::greater_than("releasedYear", 2015).to_string(),
        ];
        let query = Query::and(mixed_queries);
        let value = query.to_value();
        assert_eq!(value["method"], "and");
        assert_eq!(value["values"].as_array().unwrap().len(), 1);
    }

    #[test]
    fn test_json_serialization() {
        let query = Query::equal("name", "John");
        let json_str = query.to_string();
        let parsed: Value = serde_json::from_str(&json_str).unwrap();
        assert_eq!(parsed["method"], "equal");
        assert_eq!(parsed["attribute"], "name");
        assert_eq!(parsed["values"][0], "John");
    }

    #[test]
    fn test_equal_with_array() {
        let arr = vec!["Movie1", "Movie2"];
        let query = Query::equal("title", Value::Array(arr.iter().map(|s| Value::String(s.to_string())).collect()));
        let value = query.to_value();
        assert_eq!(value["method"], "equal");
        assert_eq!(value["attribute"], "title");
        assert_eq!(value["values"].as_array().unwrap().len(), 2);
        assert_eq!(value["values"][0], "Movie1");
        assert_eq!(value["values"][1], "Movie2");
    }

    #[test]
    fn test_not_equal() {
        let query = Query::not_equal("status", "draft");
        let value = query.to_value();
        assert_eq!(value["method"], "notEqual");
        assert_eq!(value["attribute"], "status");
        assert_eq!(value["values"][0], "draft");
    }

    #[test]
    fn test_less_than() {
        let query = Query::less_than("age", 18);
        let value = query.to_value();
        assert_eq!(value["method"], "lessThan");
        assert_eq!(value["attribute"], "age");
        assert_eq!(value["values"][0], 18);
    }

    #[test]
    fn test_less_than_equal() {
        let query = Query::less_than_equal("score", 100);
        let value = query.to_value();
        assert_eq!(value["method"], "lessThanEqual");
        assert_eq!(value["attribute"], "score");
        assert_eq!(value["values"][0], 100);
    }

    #[test]
    fn test_greater_than_equal() {
        let query = Query::greater_than_equal("age", 21);
        let value = query.to_value();
        assert_eq!(value["method"], "greaterThanEqual");
        assert_eq!(value["attribute"], "age");
        assert_eq!(value["values"][0], 21);
    }

    #[test]
    fn test_search() {
        let query = Query::search("content", "keyword1 keyword2");
        let value = query.to_value();
        assert_eq!(value["method"], "search");
        assert_eq!(value["attribute"], "content");
        assert_eq!(value["values"][0], "keyword1 keyword2");
    }

    #[test]
    fn test_search_with_number() {
        let query = Query::search("age", 42);
        let value = query.to_value();
        assert_eq!(value["method"], "search");
        assert_eq!(value["attribute"], "age");
        assert_eq!(value["values"][0], 42);
    }

    #[test]
    fn test_is_null() {
        let query = Query::is_null("deletedAt");
        let value = query.to_value();
        assert_eq!(value["method"], "isNull");
        assert_eq!(value["attribute"], "deletedAt");
    }

    #[test]
    fn test_is_not_null() {
        let query = Query::is_not_null("publishedAt");
        let value = query.to_value();
        assert_eq!(value["method"], "isNotNull");
        assert_eq!(value["attribute"], "publishedAt");
    }

    #[test]
    fn test_contains() {
        let query = Query::contains("tags", "rust");
        let value = query.to_value();
        assert_eq!(value["method"], "contains");
        assert_eq!(value["attribute"], "tags");
        assert_eq!(value["values"][0], "rust");
    }

    #[test]
    fn test_not_contains() {
        let query = Query::not_contains("tags", "rust");
        let value = query.to_value();
        assert_eq!(value["method"], "notContains");
        assert_eq!(value["attribute"], "tags");
        assert_eq!(value["values"][0], "rust");
    }

    #[test]
    fn test_not_search_with_number() {
        let query = Query::not_search("age", 7);
        let value = query.to_value();
        assert_eq!(value["method"], "notSearch");
        assert_eq!(value["attribute"], "age");
        assert_eq!(value["values"][0], 7);
    }

    #[test]
    fn test_not_search_with_array() {
        let values = Value::Array(vec![Value::from("x"), Value::from("y")]);
        let query = Query::not_search("tags", values);
        let value = query.to_value();
        assert_eq!(value["method"], "notSearch");
        assert_eq!(value["attribute"], "tags");
        assert_eq!(value["values"][0], "x");
        assert_eq!(value["values"][1], "y");
    }

    #[test]
    fn test_starts_with() {
        let query = Query::starts_with("name", "John");
        let value = query.to_value();
        assert_eq!(value["method"], "startsWith");
        assert_eq!(value["attribute"], "name");
        assert_eq!(value["values"][0], "John");
    }

    #[test]
    fn test_starts_with_with_bool() {
        let query = Query::starts_with("active", true);
        let value = query.to_value();
        assert_eq!(value["method"], "startsWith");
        assert_eq!(value["attribute"], "active");
        assert_eq!(value["values"][0], true);
    }

    #[test]
    fn test_not_starts_with_with_bool() {
        let query = Query::not_starts_with("active", false);
        let value = query.to_value();
        assert_eq!(value["method"], "notStartsWith");
        assert_eq!(value["attribute"], "active");
        assert_eq!(value["values"][0], false);
    }

    #[test]
    fn test_ends_with() {
        let query = Query::ends_with("email", "@example.com");
        let value = query.to_value();
        assert_eq!(value["method"], "endsWith");
        assert_eq!(value["attribute"], "email");
        assert_eq!(value["values"][0], "@example.com");
    }

    #[test]
    fn test_ends_with_with_array() {
        let values = Value::Array(vec![Value::from("a"), Value::from("b")]);
        let query = Query::ends_with("tags", values);
        let value = query.to_value();
        assert_eq!(value["method"], "endsWith");
        assert_eq!(value["attribute"], "tags");
        assert_eq!(value["values"][0], "a");
        assert_eq!(value["values"][1], "b");
    }

    #[test]
    fn test_not_ends_with_with_array() {
        let values = Value::Array(vec![Value::from("x"), Value::from("y")]);
        let query = Query::not_ends_with("tags", values);
        let value = query.to_value();
        assert_eq!(value["method"], "notEndsWith");
        assert_eq!(value["attribute"], "tags");
        assert_eq!(value["values"][0], "x");
        assert_eq!(value["values"][1], "y");
    }

    #[test]
    fn test_order_desc() {
        let query = Query::order_desc("createdAt");
        let value = query.to_value();
        assert_eq!(value["method"], "orderDesc");
        assert_eq!(value["attribute"], "createdAt");
    }

    #[test]
    fn test_order_random() {
        let query = Query::order_random();
        let value = query.to_value();
        assert_eq!(value["method"], "orderRandom");
    }

    #[test]
    fn test_cursor_before() {
        let query = Query::cursor_before("doc123");
        let value = query.to_value();
        assert_eq!(value["method"], "cursorBefore");
        assert_eq!(value["values"][0], "doc123");
    }

    #[test]
    fn test_cursor_after() {
        let query = Query::cursor_after("doc456");
        let value = query.to_value();
        assert_eq!(value["method"], "cursorAfter");
        assert_eq!(value["values"][0], "doc456");
    }

    #[test]
    fn test_offset() {
        let query = Query::offset(50);
        let value = query.to_value();
        assert_eq!(value["method"], "offset");
        assert_eq!(value["values"][0], 50);
    }

    #[test]
    fn test_distance_equal() {
        let query = Query::distance_equal("location", Value::Array(vec![Value::from(40.7128), Value::from(-74.0060)]), 5000, true);
        let value = query.to_value();
        assert_eq!(value["method"], "distanceEqual");
        assert_eq!(value["attribute"], "location");
        let params = value["values"][0].as_array().unwrap();
        assert_eq!(params[1], 5000);
        assert_eq!(params[2], true);
    }

    #[test]
    fn test_distance_not_equal() {
        let query = Query::distance_not_equal("location", Value::Array(vec![Value::from(40.7128), Value::from(-74.0060)]), 5000, false);
        let value = query.to_value();
        assert_eq!(value["method"], "distanceNotEqual");
        assert_eq!(value["attribute"], "location");
        let params = value["values"][0].as_array().unwrap();
        assert_eq!(params[1], 5000);
        assert_eq!(params[2], false);
    }

    #[test]
    fn test_distance_greater_than() {
        let query = Query::distance_greater_than("location", Value::Array(vec![Value::from(1.0), Value::from(2.0)]), 123, true);
        let value = query.to_value();
        assert_eq!(value["method"], "distanceGreaterThan");
        assert_eq!(value["attribute"], "location");
        let params = value["values"][0].as_array().unwrap();
        assert_eq!(params[1], 123);
        assert_eq!(params[2], true);
    }

    #[test]
    fn test_distance_less_than() {
        let query = Query::distance_less_than("location", Value::Array(vec![Value::from(1.0), Value::from(2.0)]), 321, false);
        let value = query.to_value();
        assert_eq!(value["method"], "distanceLessThan");
        assert_eq!(value["attribute"], "location");
        let params = value["values"][0].as_array().unwrap();
        assert_eq!(params[1], 321);
        assert_eq!(params[2], false);
    }

    #[test]
    fn test_intersects() {
        let query = Query::intersects("geo", Value::Array(vec![Value::from(1), Value::from(2)]));
        let value = query.to_value();
        assert_eq!(value["method"], "intersects");
        assert_eq!(value["attribute"], "geo");
        assert_eq!(value["values"][0][0], 1);
        assert_eq!(value["values"][0][1], 2);
    }

    #[test]
    fn test_not_intersects() {
        let query = Query::not_intersects("geo", Value::Array(vec![Value::from(1), Value::from(2)]));
        let value = query.to_value();
        assert_eq!(value["method"], "notIntersects");
        assert_eq!(value["attribute"], "geo");
        assert_eq!(value["values"][0][0], 1);
        assert_eq!(value["values"][0][1], 2);
    }

    #[test]
    fn test_crosses() {
        let query = Query::crosses("geo", Value::Array(vec![Value::from(1), Value::from(2)]));
        let value = query.to_value();
        assert_eq!(value["method"], "crosses");
        assert_eq!(value["attribute"], "geo");
        assert_eq!(value["values"][0][0], 1);
        assert_eq!(value["values"][0][1], 2);
    }

    #[test]
    fn test_not_crosses() {
        let query = Query::not_crosses("geo", Value::Array(vec![Value::from(1), Value::from(2)]));
        let value = query.to_value();
        assert_eq!(value["method"], "notCrosses");
        assert_eq!(value["attribute"], "geo");
        assert_eq!(value["values"][0][0], 1);
        assert_eq!(value["values"][0][1], 2);
    }

    #[test]
    fn test_overlaps() {
        let query = Query::overlaps("geo", Value::Array(vec![Value::from(1), Value::from(2)]));
        let value = query.to_value();
        assert_eq!(value["method"], "overlaps");
        assert_eq!(value["attribute"], "geo");
        assert_eq!(value["values"][0][0], 1);
        assert_eq!(value["values"][0][1], 2);
    }

    #[test]
    fn test_not_overlaps() {
        let query = Query::not_overlaps("geo", Value::Array(vec![Value::from(1), Value::from(2)]));
        let value = query.to_value();
        assert_eq!(value["method"], "notOverlaps");
        assert_eq!(value["attribute"], "geo");
        assert_eq!(value["values"][0][0], 1);
        assert_eq!(value["values"][0][1], 2);
    }

    #[test]
    fn test_touches() {
        let query = Query::touches("geo", Value::Array(vec![Value::from(1), Value::from(2)]));
        let value = query.to_value();
        assert_eq!(value["method"], "touches");
        assert_eq!(value["attribute"], "geo");
        assert_eq!(value["values"][0][0], 1);
        assert_eq!(value["values"][0][1], 2);
    }

    #[test]
    fn test_not_touches() {
        let query = Query::not_touches("geo", Value::Array(vec![Value::from(1), Value::from(2)]));
        let value = query.to_value();
        assert_eq!(value["method"], "notTouches");
        assert_eq!(value["attribute"], "geo");
        assert_eq!(value["values"][0][0], 1);
        assert_eq!(value["values"][0][1], 2);
    }

    #[test]
    fn test_not_between() {
        let query = Query::not_between("age", 18, 30);
        let value = query.to_value();
        assert_eq!(value["method"], "notBetween");
        assert_eq!(value["attribute"], "age");
        assert_eq!(value["values"][0], 18);
        assert_eq!(value["values"][1], 30);
    }

    #[test]
    fn test_not_starts_with() {
        let query = Query::not_starts_with("name", "Ann");
        let value = query.to_value();
        assert_eq!(value["method"], "notStartsWith");
        assert_eq!(value["attribute"], "name");
        assert_eq!(value["values"][0], "Ann");
    }

    #[test]
    fn test_not_ends_with() {
        let query = Query::not_ends_with("name", "nne");
        let value = query.to_value();
        assert_eq!(value["method"], "notEndsWith");
        assert_eq!(value["attribute"], "name");
        assert_eq!(value["values"][0], "nne");
    }

    #[test]
    fn test_created_before() {
        let query = Query::created_before("2023-01-01");
        let value = query.to_value();
        assert_eq!(value["method"], "lessThan");
        assert_eq!(value["attribute"], "$createdAt");
        assert_eq!(value["values"][0], "2023-01-01");
    }

    #[test]
    fn test_created_after() {
        let query = Query::created_after("2023-01-01");
        let value = query.to_value();
        assert_eq!(value["method"], "greaterThan");
        assert_eq!(value["attribute"], "$createdAt");
        assert_eq!(value["values"][0], "2023-01-01");
    }

    #[test]
    fn test_created_between() {
        let query = Query::created_between("2023-01-01", "2023-12-31");
        let value = query.to_value();
        assert_eq!(value["method"], "between");
        assert_eq!(value["attribute"], "$createdAt");
        assert_eq!(value["values"][0], "2023-01-01");
        assert_eq!(value["values"][1], "2023-12-31");
    }

    #[test]
    fn test_updated_before() {
        let query = Query::updated_before("2023-01-01");
        let value = query.to_value();
        assert_eq!(value["method"], "lessThan");
        assert_eq!(value["attribute"], "$updatedAt");
        assert_eq!(value["values"][0], "2023-01-01");
    }

    #[test]
    fn test_updated_after() {
        let query = Query::updated_after("2023-01-01");
        let value = query.to_value();
        assert_eq!(value["method"], "greaterThan");
        assert_eq!(value["attribute"], "$updatedAt");
        assert_eq!(value["values"][0], "2023-01-01");
    }

    #[test]
    fn test_updated_between() {
        let query = Query::updated_between("2023-01-01", "2023-12-31");
        let value = query.to_value();
        assert_eq!(value["method"], "between");
        assert_eq!(value["attribute"], "$updatedAt");
        assert_eq!(value["values"][0], "2023-01-01");
        assert_eq!(value["values"][1], "2023-12-31");
    }

    #[test]
    fn test_not_search() {
        let query = Query::not_search("content", "spam keyword");
        let value = query.to_value();
        assert_eq!(value["method"], "notSearch");
        assert_eq!(value["attribute"], "content");
        assert_eq!(value["values"][0], "spam keyword");
    }
}
