//! SQL query executor.

use super::parser::{
    BinaryOp, JoinType, ParsedExpr, ParsedOrderBy, ParsedSelect, ParsedSelectItem,
    ParsedStatement, SqlParser,
};
use super::row::{Row, RowBuilder, RowId};
use super::table::{ColumnDef, Table, TableDef};
use super::transaction::{IsolationLevel, TransactionId, TransactionManager, TransactionOp};
use super::types::{SqlError, SqlType, SqlValue};
use parking_lot::RwLock;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;

/// Result of a SQL query.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct QueryResult {
    /// Column names.
    pub columns: Vec<String>,
    /// Result rows.
    pub rows: Vec<Vec<SqlValue>>,
    /// Number of rows affected (for INSERT/UPDATE/DELETE).
    pub rows_affected: u64,
    /// Execution time in milliseconds.
    pub execution_time_ms: u64,
}

impl QueryResult {
    /// Creates an empty result.
    pub fn empty() -> Self {
        Self {
            columns: Vec::new(),
            rows: Vec::new(),
            rows_affected: 0,
            execution_time_ms: 0,
        }
    }

    /// Creates a result with affected count.
    pub fn affected(count: u64) -> Self {
        Self {
            columns: Vec::new(),
            rows: Vec::new(),
            rows_affected: count,
            execution_time_ms: 0,
        }
    }
}

/// SQL execution engine.
pub struct SqlEngine {
    /// Tables in this engine.
    tables: RwLock<HashMap<String, Arc<Table>>>,
    /// Transaction manager.
    txn_manager: TransactionManager,
}

impl SqlEngine {
    /// Creates a new SQL engine.
    pub fn new() -> Self {
        Self {
            tables: RwLock::new(HashMap::new()),
            txn_manager: TransactionManager::new(),
        }
    }

    /// Executes a SQL statement.
    pub fn execute(&self, sql: &str) -> Result<QueryResult, SqlError> {
        let start = std::time::Instant::now();
        let stmt = SqlParser::parse(sql)?;
        let mut result = self.execute_statement(&stmt)?;
        result.execution_time_ms = start.elapsed().as_millis() as u64;
        Ok(result)
    }

    /// Executes a parsed statement.
    fn execute_statement(&self, stmt: &ParsedStatement) -> Result<QueryResult, SqlError> {
        match stmt {
            ParsedStatement::CreateTable {
                name,
                columns,
                if_not_exists,
            } => self.execute_create_table(name, columns, *if_not_exists),
            ParsedStatement::DropTable { name, if_exists } => {
                self.execute_drop_table(name, *if_exists)
            }
            ParsedStatement::Select(select) => self.execute_select(select),
            ParsedStatement::Insert {
                table,
                columns,
                values,
            } => self.execute_insert(table, columns, values),
            ParsedStatement::Update {
                table,
                assignments,
                where_clause,
            } => self.execute_update(table, assignments, where_clause.as_ref()),
            ParsedStatement::Delete {
                table,
                where_clause,
            } => self.execute_delete(table, where_clause.as_ref()),
            ParsedStatement::CreateIndex {
                name,
                table,
                columns,
                unique,
            } => self.execute_create_index(name, table, columns, *unique),
            ParsedStatement::DropIndex { name } => self.execute_drop_index(name),
        }
    }

    /// Creates a table.
    fn execute_create_table(
        &self,
        name: &str,
        columns: &[super::parser::ParsedColumn],
        if_not_exists: bool,
    ) -> Result<QueryResult, SqlError> {
        let mut tables = self.tables.write();

        if tables.contains_key(name) {
            if if_not_exists {
                return Ok(QueryResult::empty());
            }
            return Err(SqlError::TableExists(name.to_string()));
        }

        let mut table_def = TableDef::new(name);
        for col in columns {
            let mut col_def = ColumnDef::new(&col.name, col.data_type.clone());
            if !col.nullable {
                col_def = col_def.not_null();
            }
            if let Some(ref default) = col.default {
                col_def = col_def.default(default.clone());
            }
            if col.primary_key {
                col_def = col_def.primary_key();
            }
            if col.unique {
                col_def = col_def.unique();
            }
            table_def = table_def.column(col_def);
        }

        let table = Arc::new(Table::new(table_def));
        tables.insert(name.to_string(), table);

        Ok(QueryResult::empty())
    }

    /// Drops a table.
    fn execute_drop_table(&self, name: &str, if_exists: bool) -> Result<QueryResult, SqlError> {
        let mut tables = self.tables.write();

        if !tables.contains_key(name) {
            if if_exists {
                return Ok(QueryResult::empty());
            }
            return Err(SqlError::TableNotFound(name.to_string()));
        }

        tables.remove(name);
        Ok(QueryResult::empty())
    }

    /// Executes a SELECT query.
    fn execute_select(&self, select: &ParsedSelect) -> Result<QueryResult, SqlError> {
        let tables = self.tables.read();
        let table = tables
            .get(&select.from)
            .ok_or_else(|| SqlError::TableNotFound(select.from.clone()))?;

        // Get all rows
        let mut rows = table.scan();

        // Apply WHERE filter
        if let Some(ref where_clause) = select.where_clause {
            rows = rows
                .into_iter()
                .filter(|row| self.evaluate_where(row, where_clause))
                .collect();
        }

        // Apply ORDER BY
        if !select.order_by.is_empty() {
            rows.sort_by(|a, b| {
                for ob in &select.order_by {
                    let a_val = a.get_or_null(&ob.column);
                    let b_val = b.get_or_null(&ob.column);
                    match a_val.partial_cmp(&b_val) {
                        Some(std::cmp::Ordering::Equal) => continue,
                        Some(ord) => {
                            return if ob.ascending {
                                ord
                            } else {
                                ord.reverse()
                            };
                        }
                        None => continue,
                    }
                }
                std::cmp::Ordering::Equal
            });
        }

        // Apply OFFSET
        if let Some(offset) = select.offset {
            rows = rows.into_iter().skip(offset).collect();
        }

        // Apply LIMIT
        if let Some(limit) = select.limit {
            rows = rows.into_iter().take(limit).collect();
        }

        // Handle aggregates
        if select.columns.iter().any(|c| matches!(c, ParsedSelectItem::Aggregate { .. })) {
            return self.execute_aggregate(select, &rows, table);
        }

        // Project columns
        let (column_names, result_rows) = self.project_rows(&select.columns, &rows, table);

        Ok(QueryResult {
            columns: column_names,
            rows: result_rows,
            rows_affected: 0,
            execution_time_ms: 0,
        })
    }

    /// Projects rows to selected columns.
    fn project_rows(
        &self,
        select_items: &[ParsedSelectItem],
        rows: &[Row],
        table: &Table,
    ) -> (Vec<String>, Vec<Vec<SqlValue>>) {
        let column_names: Vec<String> = select_items
            .iter()
            .flat_map(|item| match item {
                ParsedSelectItem::Wildcard => table.def.column_names(),
                ParsedSelectItem::Column(name) => vec![name.clone()],
                ParsedSelectItem::ColumnAlias { alias, .. } => vec![alias.clone()],
                ParsedSelectItem::Aggregate { function, alias, .. } => {
                    vec![alias.clone().unwrap_or_else(|| function.clone())]
                }
            })
            .collect();

        let result_rows: Vec<Vec<SqlValue>> = rows
            .iter()
            .map(|row| {
                select_items
                    .iter()
                    .flat_map(|item| match item {
                        ParsedSelectItem::Wildcard => table
                            .def
                            .column_names()
                            .into_iter()
                            .map(|c| row.get_or_null(&c))
                            .collect::<Vec<_>>(),
                        ParsedSelectItem::Column(name)
                        | ParsedSelectItem::ColumnAlias { column: name, .. } => {
                            vec![row.get_or_null(name)]
                        }
                        _ => vec![SqlValue::Null],
                    })
                    .collect()
            })
            .collect();

        (column_names, result_rows)
    }

    /// Executes aggregate functions.
    fn execute_aggregate(
        &self,
        select: &ParsedSelect,
        rows: &[Row],
        table: &Table,
    ) -> Result<QueryResult, SqlError> {
        let mut result_columns = Vec::new();
        let mut result_values = Vec::new();

        for item in &select.columns {
            match item {
                ParsedSelectItem::Aggregate {
                    function,
                    column,
                    alias,
                } => {
                    let col_name = alias.clone().unwrap_or_else(|| function.clone());
                    result_columns.push(col_name);

                    let value = match function.as_str() {
                        "COUNT" => SqlValue::Integer(rows.len() as i64),
                        "SUM" => {
                            let col = column.as_ref().ok_or_else(|| {
                                SqlError::InvalidOperation("SUM requires column".to_string())
                            })?;
                            let sum: f64 = rows
                                .iter()
                                .filter_map(|r| r.get_or_null(col).as_real())
                                .sum();
                            SqlValue::Real(sum)
                        }
                        "AVG" => {
                            let col = column.as_ref().ok_or_else(|| {
                                SqlError::InvalidOperation("AVG requires column".to_string())
                            })?;
                            let values: Vec<f64> = rows
                                .iter()
                                .filter_map(|r| r.get_or_null(col).as_real())
                                .collect();
                            if values.is_empty() {
                                SqlValue::Null
                            } else {
                                SqlValue::Real(values.iter().sum::<f64>() / values.len() as f64)
                            }
                        }
                        "MIN" => {
                            let col = column.as_ref().ok_or_else(|| {
                                SqlError::InvalidOperation("MIN requires column".to_string())
                            })?;
                            rows.iter()
                                .map(|r| r.get_or_null(col))
                                .filter(|v| !v.is_null())
                                .min_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
                                .unwrap_or(SqlValue::Null)
                        }
                        "MAX" => {
                            let col = column.as_ref().ok_or_else(|| {
                                SqlError::InvalidOperation("MAX requires column".to_string())
                            })?;
                            rows.iter()
                                .map(|r| r.get_or_null(col))
                                .filter(|v| !v.is_null())
                                .max_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal))
                                .unwrap_or(SqlValue::Null)
                        }
                        _ => {
                            return Err(SqlError::Unsupported(format!("Function: {}", function)))
                        }
                    };
                    result_values.push(value);
                }
                ParsedSelectItem::Column(name) => {
                    result_columns.push(name.clone());
                    // For non-aggregated columns in aggregate query, take first value
                    result_values.push(
                        rows.first()
                            .map(|r| r.get_or_null(name))
                            .unwrap_or(SqlValue::Null),
                    );
                }
                _ => {}
            }
        }

        Ok(QueryResult {
            columns: result_columns,
            rows: if result_values.is_empty() {
                Vec::new()
            } else {
                vec![result_values]
            },
            rows_affected: 0,
            execution_time_ms: 0,
        })
    }

    /// Evaluates a WHERE clause.
    fn evaluate_where(&self, row: &Row, expr: &ParsedExpr) -> bool {
        match self.evaluate_expr(row, expr) {
            SqlValue::Boolean(b) => b,
            SqlValue::Integer(i) => i != 0,
            _ => false,
        }
    }

    /// Evaluates an expression.
    fn evaluate_expr(&self, row: &Row, expr: &ParsedExpr) -> SqlValue {
        match expr {
            ParsedExpr::Column(name) => row.get_or_null(name),
            ParsedExpr::Literal(value) => value.clone(),
            ParsedExpr::BinaryOp { left, op, right } => {
                let left_val = self.evaluate_expr(row, left);
                let right_val = self.evaluate_expr(row, right);
                self.evaluate_binary_op(&left_val, op, &right_val)
            }
            ParsedExpr::Not(inner) => {
                let val = self.evaluate_expr(row, inner);
                match val {
                    SqlValue::Boolean(b) => SqlValue::Boolean(!b),
                    _ => SqlValue::Null,
                }
            }
            ParsedExpr::IsNull(inner) => {
                SqlValue::Boolean(self.evaluate_expr(row, inner).is_null())
            }
            ParsedExpr::IsNotNull(inner) => {
                SqlValue::Boolean(!self.evaluate_expr(row, inner).is_null())
            }
            ParsedExpr::InList { expr, list, negated } => {
                let val = self.evaluate_expr(row, expr);
                let in_list = list.iter().any(|item| {
                    let item_val = self.evaluate_expr(row, item);
                    val == item_val
                });
                SqlValue::Boolean(if *negated { !in_list } else { in_list })
            }
            ParsedExpr::Between {
                expr,
                low,
                high,
                negated,
            } => {
                let val = self.evaluate_expr(row, expr);
                let low_val = self.evaluate_expr(row, low);
                let high_val = self.evaluate_expr(row, high);
                let between = val >= low_val && val <= high_val;
                SqlValue::Boolean(if *negated { !between } else { between })
            }
            ParsedExpr::Function { name, args } => {
                self.evaluate_function(row, name, args)
            }
        }
    }

    /// Evaluates a binary operation.
    fn evaluate_binary_op(&self, left: &SqlValue, op: &BinaryOp, right: &SqlValue) -> SqlValue {
        match op {
            BinaryOp::Eq => SqlValue::Boolean(left == right),
            BinaryOp::Ne => SqlValue::Boolean(left != right),
            BinaryOp::Lt => SqlValue::Boolean(left < right),
            BinaryOp::Le => SqlValue::Boolean(left <= right),
            BinaryOp::Gt => SqlValue::Boolean(left > right),
            BinaryOp::Ge => SqlValue::Boolean(left >= right),
            BinaryOp::And => {
                let l = matches!(left, SqlValue::Boolean(true));
                let r = matches!(right, SqlValue::Boolean(true));
                SqlValue::Boolean(l && r)
            }
            BinaryOp::Or => {
                let l = matches!(left, SqlValue::Boolean(true));
                let r = matches!(right, SqlValue::Boolean(true));
                SqlValue::Boolean(l || r)
            }
            BinaryOp::Like => {
                if let (SqlValue::Text(text), SqlValue::Text(pattern)) = (left, right) {
                    SqlValue::Boolean(self.match_like(text, pattern))
                } else {
                    SqlValue::Boolean(false)
                }
            }
            BinaryOp::Plus => match (left, right) {
                (SqlValue::Integer(a), SqlValue::Integer(b)) => SqlValue::Integer(a + b),
                (SqlValue::Real(a), SqlValue::Real(b)) => SqlValue::Real(a + b),
                (SqlValue::Integer(a), SqlValue::Real(b)) => SqlValue::Real(*a as f64 + b),
                (SqlValue::Real(a), SqlValue::Integer(b)) => SqlValue::Real(a + *b as f64),
                _ => SqlValue::Null,
            },
            BinaryOp::Minus => match (left, right) {
                (SqlValue::Integer(a), SqlValue::Integer(b)) => SqlValue::Integer(a - b),
                (SqlValue::Real(a), SqlValue::Real(b)) => SqlValue::Real(a - b),
                _ => SqlValue::Null,
            },
            BinaryOp::Multiply => match (left, right) {
                (SqlValue::Integer(a), SqlValue::Integer(b)) => SqlValue::Integer(a * b),
                (SqlValue::Real(a), SqlValue::Real(b)) => SqlValue::Real(a * b),
                _ => SqlValue::Null,
            },
            BinaryOp::Divide => match (left, right) {
                (SqlValue::Integer(a), SqlValue::Integer(b)) if *b != 0 => {
                    SqlValue::Integer(a / b)
                }
                (SqlValue::Real(a), SqlValue::Real(b)) if *b != 0.0 => SqlValue::Real(a / b),
                _ => SqlValue::Null,
            },
        }
    }

    /// Evaluates a function call.
    fn evaluate_function(&self, row: &Row, name: &str, args: &[ParsedExpr]) -> SqlValue {
        match name.to_uppercase().as_str() {
            "COALESCE" => {
                for arg in args {
                    let val = self.evaluate_expr(row, arg);
                    if !val.is_null() {
                        return val;
                    }
                }
                SqlValue::Null
            }
            "UPPER" => {
                if let Some(arg) = args.first() {
                    if let SqlValue::Text(s) = self.evaluate_expr(row, arg) {
                        return SqlValue::Text(s.to_uppercase());
                    }
                }
                SqlValue::Null
            }
            "LOWER" => {
                if let Some(arg) = args.first() {
                    if let SqlValue::Text(s) = self.evaluate_expr(row, arg) {
                        return SqlValue::Text(s.to_lowercase());
                    }
                }
                SqlValue::Null
            }
            "LENGTH" => {
                if let Some(arg) = args.first() {
                    if let SqlValue::Text(s) = self.evaluate_expr(row, arg) {
                        return SqlValue::Integer(s.len() as i64);
                    }
                }
                SqlValue::Null
            }
            "ABS" => {
                if let Some(arg) = args.first() {
                    match self.evaluate_expr(row, arg) {
                        SqlValue::Integer(i) => return SqlValue::Integer(i.abs()),
                        SqlValue::Real(f) => return SqlValue::Real(f.abs()),
                        _ => {}
                    }
                }
                SqlValue::Null
            }
            _ => SqlValue::Null,
        }
    }

    /// Matches a LIKE pattern.
    fn match_like(&self, text: &str, pattern: &str) -> bool {
        // Simple LIKE implementation: % = any chars, _ = single char
        let regex_pattern = pattern
            .replace('%', ".*")
            .replace('_', ".");
        // For simplicity, just do case-insensitive contains for now
        if pattern.starts_with('%') && pattern.ends_with('%') {
            let inner = &pattern[1..pattern.len() - 1];
            text.to_lowercase().contains(&inner.to_lowercase())
        } else if pattern.starts_with('%') {
            let suffix = &pattern[1..];
            text.to_lowercase().ends_with(&suffix.to_lowercase())
        } else if pattern.ends_with('%') {
            let prefix = &pattern[..pattern.len() - 1];
            text.to_lowercase().starts_with(&prefix.to_lowercase())
        } else {
            text.to_lowercase() == pattern.to_lowercase()
        }
    }

    /// Executes an INSERT statement.
    fn execute_insert(
        &self,
        table_name: &str,
        columns: &[String],
        values: &[Vec<SqlValue>],
    ) -> Result<QueryResult, SqlError> {
        let tables = self.tables.read();
        let table = tables
            .get(table_name)
            .ok_or_else(|| SqlError::TableNotFound(table_name.to_string()))?;

        let cols = if columns.is_empty() {
            table.def.column_names()
        } else {
            columns.to_vec()
        };

        let mut count = 0;
        for row_values in values {
            if row_values.len() != cols.len() {
                return Err(SqlError::InvalidOperation(format!(
                    "Column count mismatch: expected {}, got {}",
                    cols.len(),
                    row_values.len()
                )));
            }

            let mut row_map = HashMap::new();
            for (col, val) in cols.iter().zip(row_values.iter()) {
                row_map.insert(col.clone(), val.clone());
            }

            table.insert(row_map)?;
            count += 1;
        }

        Ok(QueryResult::affected(count))
    }

    /// Executes an UPDATE statement.
    fn execute_update(
        &self,
        table_name: &str,
        assignments: &[(String, SqlValue)],
        where_clause: Option<&ParsedExpr>,
    ) -> Result<QueryResult, SqlError> {
        let tables = self.tables.read();
        let table = tables
            .get(table_name)
            .ok_or_else(|| SqlError::TableNotFound(table_name.to_string()))?;

        let rows = table.scan();
        let mut count = 0;

        for row in rows {
            let matches = where_clause
                .map(|w| self.evaluate_where(&row, w))
                .unwrap_or(true);

            if matches {
                let updates: HashMap<String, SqlValue> =
                    assignments.iter().cloned().collect();
                table.update(row.id, updates)?;
                count += 1;
            }
        }

        Ok(QueryResult::affected(count))
    }

    /// Executes a DELETE statement.
    fn execute_delete(
        &self,
        table_name: &str,
        where_clause: Option<&ParsedExpr>,
    ) -> Result<QueryResult, SqlError> {
        let tables = self.tables.read();
        let table = tables
            .get(table_name)
            .ok_or_else(|| SqlError::TableNotFound(table_name.to_string()))?;

        let rows = table.scan();
        let mut count = 0;

        let to_delete: Vec<RowId> = rows
            .iter()
            .filter(|row| {
                where_clause
                    .map(|w| self.evaluate_where(row, w))
                    .unwrap_or(true)
            })
            .map(|row| row.id)
            .collect();

        for id in to_delete {
            if table.delete(id)? {
                count += 1;
            }
        }

        Ok(QueryResult::affected(count))
    }

    /// Creates an index.
    fn execute_create_index(
        &self,
        name: &str,
        table_name: &str,
        columns: &[String],
        unique: bool,
    ) -> Result<QueryResult, SqlError> {
        let tables = self.tables.read();
        let table = tables
            .get(table_name)
            .ok_or_else(|| SqlError::TableNotFound(table_name.to_string()))?;

        // For simplicity, only support single-column indexes
        let column = columns
            .first()
            .ok_or_else(|| SqlError::InvalidOperation("Index requires at least one column".to_string()))?;

        table.create_index(name, column, unique)?;
        Ok(QueryResult::empty())
    }

    /// Drops an index.
    fn execute_drop_index(&self, name: &str) -> Result<QueryResult, SqlError> {
        // Would need to find which table has this index
        // For now, return success
        Ok(QueryResult::empty())
    }

    // Transaction methods

    /// Begins a transaction.
    pub fn begin_transaction(&self) -> TransactionId {
        self.txn_manager.begin(IsolationLevel::ReadCommitted)
    }

    /// Commits a transaction.
    pub fn commit(&self, txn_id: TransactionId) -> Result<(), SqlError> {
        self.txn_manager.commit(txn_id)?;
        Ok(())
    }

    /// Rolls back a transaction.
    pub fn rollback(&self, txn_id: TransactionId) -> Result<(), SqlError> {
        self.txn_manager.rollback(txn_id)?;
        Ok(())
    }

    /// Returns number of tables.
    pub fn table_count(&self) -> usize {
        self.tables.read().len()
    }

    /// Returns table names.
    pub fn table_names(&self) -> Vec<String> {
        self.tables.read().keys().cloned().collect()
    }

    /// Gets table definition.
    pub fn get_table_def(&self, name: &str) -> Option<TableDef> {
        self.tables.read().get(name).map(|t| t.def.clone())
    }
}

impl Default for SqlEngine {
    fn default() -> Self {
        Self::new()
    }
}

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

    fn setup_engine() -> SqlEngine {
        let engine = SqlEngine::new();
        engine
            .execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER)")
            .unwrap();
        engine
    }

    #[test]
    fn test_create_table() {
        let engine = SqlEngine::new();
        engine
            .execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)")
            .unwrap();
        assert_eq!(engine.table_count(), 1);
    }

    #[test]
    fn test_insert_and_select() {
        let engine = setup_engine();

        engine
            .execute("INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30)")
            .unwrap();
        engine
            .execute("INSERT INTO users (id, name, age) VALUES (2, 'Bob', 25)")
            .unwrap();

        let result = engine.execute("SELECT name, age FROM users").unwrap();
        assert_eq!(result.rows.len(), 2);
    }

    #[test]
    fn test_select_with_where() {
        let engine = setup_engine();

        engine
            .execute("INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30)")
            .unwrap();
        engine
            .execute("INSERT INTO users (id, name, age) VALUES (2, 'Bob', 25)")
            .unwrap();

        let result = engine.execute("SELECT name FROM users WHERE age > 26").unwrap();
        assert_eq!(result.rows.len(), 1);
        assert_eq!(result.rows[0][0], SqlValue::Text("Alice".to_string()));
    }

    #[test]
    fn test_select_order_by() {
        let engine = setup_engine();

        engine
            .execute("INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30)")
            .unwrap();
        engine
            .execute("INSERT INTO users (id, name, age) VALUES (2, 'Bob', 25)")
            .unwrap();

        let result = engine
            .execute("SELECT name FROM users ORDER BY age")
            .unwrap();
        assert_eq!(result.rows[0][0], SqlValue::Text("Bob".to_string()));
        assert_eq!(result.rows[1][0], SqlValue::Text("Alice".to_string()));
    }

    #[test]
    fn test_select_limit() {
        let engine = setup_engine();

        for i in 1..=10 {
            engine
                .execute(&format!(
                    "INSERT INTO users (id, name, age) VALUES ({}, 'User{}', {})",
                    i, i, 20 + i
                ))
                .unwrap();
        }

        let result = engine.execute("SELECT name FROM users LIMIT 3").unwrap();
        assert_eq!(result.rows.len(), 3);
    }

    #[test]
    fn test_aggregate_count() {
        let engine = setup_engine();

        engine
            .execute("INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30)")
            .unwrap();
        engine
            .execute("INSERT INTO users (id, name, age) VALUES (2, 'Bob', 25)")
            .unwrap();

        let result = engine.execute("SELECT COUNT(*) FROM users").unwrap();
        assert_eq!(result.rows[0][0], SqlValue::Integer(2));
    }

    #[test]
    fn test_aggregate_sum_avg() {
        let engine = setup_engine();

        engine
            .execute("INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30)")
            .unwrap();
        engine
            .execute("INSERT INTO users (id, name, age) VALUES (2, 'Bob', 20)")
            .unwrap();

        let result = engine.execute("SELECT SUM(age) FROM users").unwrap();
        assert_eq!(result.rows[0][0], SqlValue::Real(50.0));

        let result = engine.execute("SELECT AVG(age) FROM users").unwrap();
        assert_eq!(result.rows[0][0], SqlValue::Real(25.0));
    }

    #[test]
    fn test_update() {
        let engine = setup_engine();

        engine
            .execute("INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30)")
            .unwrap();

        let result = engine
            .execute("UPDATE users SET age = 31 WHERE name = 'Alice'")
            .unwrap();
        assert_eq!(result.rows_affected, 1);

        let result = engine
            .execute("SELECT age FROM users WHERE name = 'Alice'")
            .unwrap();
        assert_eq!(result.rows[0][0], SqlValue::Integer(31));
    }

    #[test]
    fn test_delete() {
        let engine = setup_engine();

        engine
            .execute("INSERT INTO users (id, name, age) VALUES (1, 'Alice', 30)")
            .unwrap();
        engine
            .execute("INSERT INTO users (id, name, age) VALUES (2, 'Bob', 25)")
            .unwrap();

        let result = engine
            .execute("DELETE FROM users WHERE name = 'Alice'")
            .unwrap();
        assert_eq!(result.rows_affected, 1);

        let result = engine.execute("SELECT COUNT(*) FROM users").unwrap();
        assert_eq!(result.rows[0][0], SqlValue::Integer(1));
    }

    #[test]
    fn test_drop_table() {
        let engine = setup_engine();
        assert_eq!(engine.table_count(), 1);

        engine.execute("DROP TABLE users").unwrap();
        assert_eq!(engine.table_count(), 0);
    }
}
