use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// SQL data types supported by FlareDB
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum DataType {
    Integer,
    BigInt,
    Text,
    Boolean,
    Timestamp,
}

/// SQL value (runtime representation)
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum Value {
    Null,
    Integer(i64),
    Text(String),
    Boolean(bool),
    Timestamp(u64),
}

impl Value {
    pub fn is_null(&self) -> bool {
        matches!(self, Value::Null)
    }

    pub fn data_type(&self) -> Option<DataType> {
        match self {
            Value::Null => None,
            Value::Integer(_) => Some(DataType::Integer),
            Value::Text(_) => Some(DataType::Text),
            Value::Boolean(_) => Some(DataType::Boolean),
            Value::Timestamp(_) => Some(DataType::Timestamp),
        }
    }
}

/// Column definition
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ColumnDef {
    pub name: String,
    pub data_type: DataType,
    pub nullable: bool,
    pub default_value: Option<Value>,
}

/// Table metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TableMetadata {
    pub table_id: u32,
    pub table_name: String,
    pub columns: Vec<ColumnDef>,
    pub primary_key: Vec<String>,
    pub created_at: u64,
}

impl TableMetadata {
    pub fn get_column(&self, name: &str) -> Option<&ColumnDef> {
        self.columns.iter().find(|c| c.name == name)
    }

    pub fn column_index(&self, name: &str) -> Option<usize> {
        self.columns.iter().position(|c| c.name == name)
    }
}

/// Row data (stored in KVS)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RowData {
    pub columns: HashMap<String, Value>,
    pub version: u64,
}

impl RowData {
    pub fn new(columns: HashMap<String, Value>) -> Self {
        Self { columns, version: 0 }
    }

    pub fn get(&self, column: &str) -> Option<&Value> {
        self.columns.get(column)
    }

    pub fn set(&mut self, column: String, value: Value) {
        self.columns.insert(column, value);
    }
}

/// SQL query result
#[derive(Debug, Clone)]
pub struct QueryResult {
    pub columns: Vec<String>,
    pub rows: Vec<Vec<Value>>,
}

impl QueryResult {
    pub fn new(columns: Vec<String>) -> Self {
        Self {
            columns,
            rows: Vec::new(),
        }
    }

    pub fn add_row(&mut self, row: Vec<Value>) {
        self.rows.push(row);
    }

    pub fn row_count(&self) -> usize {
        self.rows.len()
    }
}
