//! HTTP request handlers for Database Gateway.

use crate::document::{Document, DocumentFilter, DocumentId};
use crate::error::DatabaseError;
use crate::gateway::{ApiResponse, Pagination};
use crate::keyvalue::KeyValueStore;
use crate::query::{Filter, Query, QueryResult, SortOrder};
use crate::timeseries::{Aggregation, DataPoint};
use crate::vector::{Embedding, VectorSearchResult};
use crate::{Database, DatabaseManager};

use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
use std::sync::Arc;

// ============================================================================
// Key-Value Handlers
// ============================================================================

/// Get a key-value pair.
#[derive(Debug, Serialize)]
pub struct KvGetResponse {
    pub key: String,
    pub value: Option<String>,
    pub ttl: Option<u64>,
}

/// Set a key-value pair request.
#[derive(Debug, Deserialize)]
pub struct KvSetRequest {
    pub value: String,
    #[serde(default)]
    pub ttl: u64,
}

/// Batch KV operation request.
#[derive(Debug, Deserialize)]
pub struct KvBatchRequest {
    pub operations: Vec<KvOperation>,
}

#[derive(Debug, Deserialize)]
pub struct KvOperation {
    pub op: String, // "get", "set", "delete"
    pub key: String,
    pub value: Option<String>,
    pub ttl: Option<u64>,
}

#[derive(Debug, Serialize)]
pub struct KvBatchResponse {
    pub results: Vec<KvOperationResult>,
}

#[derive(Debug, Serialize)]
pub struct KvOperationResult {
    pub key: String,
    pub success: bool,
    pub value: Option<String>,
    pub error: Option<String>,
}

/// Handles KV get operation.
pub fn handle_kv_get(store: &KeyValueStore, key: &str) -> ApiResponse<KvGetResponse> {
    let value = store.get_string(key);
    let ttl = store.ttl(key);

    ApiResponse::ok(KvGetResponse {
        key: key.to_string(),
        value,
        ttl,
    })
}

/// Handles KV set operation.
pub fn handle_kv_set(
    store: &KeyValueStore,
    key: &str,
    req: KvSetRequest,
) -> ApiResponse<KvGetResponse> {
    match store.set_string(key, &req.value, req.ttl) {
        Ok(_) => ApiResponse::ok(KvGetResponse {
            key: key.to_string(),
            value: Some(req.value),
            ttl: if req.ttl > 0 { Some(req.ttl) } else { None },
        }),
        Err(e) => ApiResponse::error(e.to_string()),
    }
}

/// Handles KV delete operation.
pub fn handle_kv_delete(store: &KeyValueStore, key: &str) -> ApiResponse<bool> {
    match store.delete(key) {
        Ok(deleted) => ApiResponse::ok(deleted),
        Err(e) => ApiResponse::error(e.to_string()),
    }
}

/// Handles batch KV operations.
pub fn handle_kv_batch(store: &KeyValueStore, req: KvBatchRequest) -> ApiResponse<KvBatchResponse> {
    let mut results = Vec::with_capacity(req.operations.len());

    for op in req.operations {
        let result = match op.op.as_str() {
            "get" => {
                let value = store.get_string(&op.key);
                KvOperationResult {
                    key: op.key,
                    success: true,
                    value,
                    error: None,
                }
            }
            "set" => {
                if let Some(value) = op.value {
                    match store.set_string(&op.key, &value, op.ttl.unwrap_or(0)) {
                        Ok(_) => KvOperationResult {
                            key: op.key,
                            success: true,
                            value: Some(value),
                            error: None,
                        },
                        Err(e) => KvOperationResult {
                            key: op.key,
                            success: false,
                            value: None,
                            error: Some(e.to_string()),
                        },
                    }
                } else {
                    KvOperationResult {
                        key: op.key,
                        success: false,
                        value: None,
                        error: Some("Missing value for set operation".to_string()),
                    }
                }
            }
            "delete" => match store.delete(&op.key) {
                Ok(deleted) => KvOperationResult {
                    key: op.key,
                    success: deleted,
                    value: None,
                    error: if deleted {
                        None
                    } else {
                        Some("Key not found".to_string())
                    },
                },
                Err(e) => KvOperationResult {
                    key: op.key,
                    success: false,
                    value: None,
                    error: Some(e.to_string()),
                },
            },
            _ => KvOperationResult {
                key: op.key,
                success: false,
                value: None,
                error: Some(format!("Unknown operation: {}", op.op)),
            },
        };
        results.push(result);
    }

    ApiResponse::ok(KvBatchResponse { results })
}

// ============================================================================
// Document Handlers
// ============================================================================

/// Create collection request.
#[derive(Debug, Deserialize)]
pub struct CreateCollectionRequest {
    pub name: String,
    #[serde(default)]
    pub schema: Option<JsonValue>,
}

/// Insert document request.
#[derive(Debug, Deserialize)]
pub struct InsertDocumentRequest {
    pub document: JsonValue,
}

/// Insert many documents request.
#[derive(Debug, Deserialize)]
pub struct InsertManyRequest {
    pub documents: Vec<JsonValue>,
}

/// Update document request.
#[derive(Debug, Deserialize)]
pub struct UpdateDocumentRequest {
    pub update: JsonValue,
}

/// Query documents request.
#[derive(Debug, Deserialize)]
pub struct QueryDocumentsRequest {
    #[serde(default)]
    pub filter: Option<JsonValue>,
    #[serde(default)]
    pub sort: Option<Vec<SortSpec>>,
    #[serde(default)]
    pub skip: usize,
    #[serde(default = "default_limit")]
    pub limit: usize,
    #[serde(default)]
    pub select: Option<Vec<String>>,
}

fn default_limit() -> usize {
    100
}

#[derive(Debug, Deserialize)]
pub struct SortSpec {
    pub field: String,
    #[serde(default = "default_order")]
    pub order: String,
}

fn default_order() -> String {
    "asc".to_string()
}

/// Document response.
#[derive(Debug, Serialize)]
pub struct DocumentResponse {
    pub id: String,
    pub data: JsonValue,
    pub created_at: u64,
    pub updated_at: u64,
    pub version: u64,
}

impl From<Document> for DocumentResponse {
    fn from(doc: Document) -> Self {
        Self {
            id: doc.id.to_hex(),
            data: doc.data,
            created_at: doc.created_at,
            updated_at: doc.updated_at,
            version: doc.version,
        }
    }
}

/// Query response.
#[derive(Debug, Serialize)]
pub struct QueryDocumentsResponse {
    pub documents: Vec<DocumentResponse>,
    pub total: u64,
    pub has_more: bool,
    pub execution_time_ms: u64,
}

impl From<QueryResult> for QueryDocumentsResponse {
    fn from(result: QueryResult) -> Self {
        Self {
            documents: result.documents.into_iter().map(Into::into).collect(),
            total: result.total,
            has_more: result.has_more,
            execution_time_ms: result.execution_time_ms,
        }
    }
}

/// Converts JSON filter to Filter enum.
pub fn json_to_filter(json: &JsonValue) -> Option<Filter> {
    let obj = json.as_object()?;

    // Handle $and
    if let Some(and_arr) = obj.get("$and").and_then(|v| v.as_array()) {
        let filters: Vec<Filter> = and_arr
            .iter()
            .filter_map(json_to_filter)
            .collect();
        return Some(Filter::And(filters));
    }

    // Handle $or
    if let Some(or_arr) = obj.get("$or").and_then(|v| v.as_array()) {
        let filters: Vec<Filter> = or_arr
            .iter()
            .filter_map(json_to_filter)
            .collect();
        return Some(Filter::Or(filters));
    }

    // Handle field conditions
    let mut filters = Vec::new();
    for (field, condition) in obj {
        if field.starts_with('$') {
            continue;
        }

        if let Some(cond_obj) = condition.as_object() {
            for (op, value) in cond_obj {
                let filter = match op.as_str() {
                    "$eq" => Filter::Eq(field.clone(), value.clone()),
                    "$ne" => Filter::Ne(field.clone(), value.clone()),
                    "$gt" => Filter::Gt(field.clone(), value.clone()),
                    "$gte" => Filter::Gte(field.clone(), value.clone()),
                    "$lt" => Filter::Lt(field.clone(), value.clone()),
                    "$lte" => Filter::Lte(field.clone(), value.clone()),
                    "$in" => {
                        if let Some(arr) = value.as_array() {
                            Filter::In(field.clone(), arr.clone())
                        } else {
                            continue;
                        }
                    }
                    "$contains" => {
                        if let Some(s) = value.as_str() {
                            Filter::Contains(field.clone(), s.to_string())
                        } else {
                            continue;
                        }
                    }
                    "$exists" => Filter::Exists(field.clone()),
                    _ => continue,
                };
                filters.push(filter);
            }
        } else {
            // Simple equality
            filters.push(Filter::Eq(field.clone(), condition.clone()));
        }
    }

    if filters.is_empty() {
        None
    } else if filters.len() == 1 {
        Some(filters.remove(0))
    } else {
        Some(Filter::And(filters))
    }
}

// ============================================================================
// Vector Handlers
// ============================================================================

/// Insert embeddings request.
#[derive(Debug, Deserialize)]
pub struct InsertEmbeddingsRequest {
    pub embeddings: Vec<EmbeddingInput>,
}

#[derive(Debug, Deserialize)]
pub struct EmbeddingInput {
    pub id: String,
    pub vector: Vec<f32>,
    #[serde(default)]
    pub metadata: Option<JsonValue>,
    #[serde(default)]
    pub namespace: Option<String>,
}

/// Vector search request.
#[derive(Debug, Deserialize)]
pub struct VectorSearchRequest {
    pub vector: Vec<f32>,
    #[serde(default = "default_search_limit")]
    pub limit: usize,
    #[serde(default)]
    pub namespace: Option<String>,
    #[serde(default)]
    pub threshold: Option<f32>,
}

fn default_search_limit() -> usize {
    10
}

/// Vector search response.
#[derive(Debug, Serialize)]
pub struct VectorSearchResponse {
    pub results: Vec<VectorMatch>,
    pub count: usize,
}

#[derive(Debug, Serialize)]
pub struct VectorMatch {
    pub id: String,
    pub score: f32,
    pub metadata: JsonValue,
}

impl From<VectorSearchResult> for VectorMatch {
    fn from(result: VectorSearchResult) -> Self {
        Self {
            id: result.embedding.id,
            score: result.score,
            metadata: result.embedding.metadata,
        }
    }
}

// ============================================================================
// Time-Series Handlers
// ============================================================================

/// Record metric request.
#[derive(Debug, Deserialize)]
pub struct RecordMetricRequest {
    pub value: f64,
    #[serde(default)]
    pub timestamp: Option<u64>,
    #[serde(default)]
    pub tags: Option<std::collections::HashMap<String, String>>,
}

/// Query metrics request.
#[derive(Debug, Deserialize)]
pub struct QueryMetricsRequest {
    pub start: u64,
    pub end: u64,
    #[serde(default)]
    pub aggregation: Option<String>,
    #[serde(default)]
    pub interval_ms: Option<u64>,
}

/// Metrics response.
#[derive(Debug, Serialize)]
pub struct MetricsResponse {
    pub name: String,
    pub points: Vec<DataPointResponse>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub aggregation: Option<f64>,
}

#[derive(Debug, Serialize)]
pub struct DataPointResponse {
    pub timestamp: u64,
    pub value: f64,
}

impl From<DataPoint> for DataPointResponse {
    fn from(point: DataPoint) -> Self {
        Self {
            timestamp: point.timestamp,
            value: point.value,
        }
    }
}

// ============================================================================
// Database Management Handlers
// ============================================================================

/// Create database request.
#[derive(Debug, Deserialize)]
pub struct CreateDatabaseRequest {
    pub name: String,
    #[serde(default)]
    pub vector_dimensions: Option<u32>,
    #[serde(default)]
    pub replication: Option<u8>,
}

/// Database info response.
#[derive(Debug, Serialize)]
pub struct DatabaseInfoResponse {
    pub id: String,
    pub name: String,
    pub entry_count: u64,
    pub storage_used: u64,
    pub reads: u64,
    pub writes: u64,
    pub vector_searches: u64,
}

/// List databases response.
#[derive(Debug, Serialize)]
pub struct ListDatabasesResponse {
    pub databases: Vec<DatabaseInfoResponse>,
}

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

    #[test]
    fn test_json_to_filter_simple() {
        let json = serde_json::json!({
            "name": "Alice"
        });

        let filter = json_to_filter(&json).unwrap();
        match filter {
            Filter::Eq(field, value) => {
                assert_eq!(field, "name");
                assert_eq!(value, serde_json::json!("Alice"));
            }
            _ => panic!("Expected Eq filter"),
        }
    }

    #[test]
    fn test_json_to_filter_operators() {
        let json = serde_json::json!({
            "age": { "$gte": 18 }
        });

        let filter = json_to_filter(&json).unwrap();
        match filter {
            Filter::Gte(field, value) => {
                assert_eq!(field, "age");
                assert_eq!(value, serde_json::json!(18));
            }
            _ => panic!("Expected Gte filter"),
        }
    }

    #[test]
    fn test_json_to_filter_and() {
        let json = serde_json::json!({
            "$and": [
                { "status": "active" },
                { "age": { "$gte": 18 } }
            ]
        });

        let filter = json_to_filter(&json).unwrap();
        match filter {
            Filter::And(filters) => {
                assert_eq!(filters.len(), 2);
            }
            _ => panic!("Expected And filter"),
        }
    }
}
