//! Synor Database L2 - Multi-Model Database Layer
//!
//! Provides decentralized database services built on Synor Storage:
//!
//! - **Key-Value Store**: Redis-compatible API for caching and sessions
//! - **Document Store**: MongoDB-compatible queries for app data
//! - **Vector Store**: AI/RAG optimized with similarity search
//! - **Time-Series**: Metrics and analytics storage
//!
//! # Architecture
//!
//! ```text
//! ┌─────────────────────────────────────────────────────────────────┐
//! │                     SYNOR DATABASE L2                           │
//! ├─────────────────────────────────────────────────────────────────┤
//! │                                                                 │
//! │  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐  │
//! │  │   Key-Value  │  │   Document   │  │      Vector          │  │
//! │  │   (Redis)    │  │   (Mongo)    │  │   (AI/RAG)           │  │
//! │  └──────────────┘  └──────────────┘  └──────────────────────┘  │
//! │                                                                 │
//! │  ┌──────────────┐  ┌──────────────┐  ┌──────────────────────┐  │
//! │  │  Time-Series │  │    Index     │  │      Query           │  │
//! │  │  (Metrics)   │  │   Manager    │  │     Engine           │  │
//! │  └──────────────┘  └──────────────┘  └──────────────────────┘  │
//! │                                                                 │
//! │  ┌────────────────────────────────────────────────────────────┐ │
//! │  │              STORAGE LAYER (Synor Storage)                 │ │
//! │  └────────────────────────────────────────────────────────────┘ │
//! │                                                                 │
//! └─────────────────────────────────────────────────────────────────┘
//! ```
//!
//! # Pricing
//!
//! | Operation | Cost (SYNOR) |
//! |-----------|--------------|
//! | Storage/GB/month | 0.1 |
//! | Read/million | 0.001 |
//! | Write/million | 0.01 |
//! | Vector search/million | 0.05 |

#![allow(dead_code)]

pub mod document;
pub mod error;
pub mod gateway;
pub mod graph;
pub mod index;
pub mod keyvalue;
pub mod query;
pub mod replication;
pub mod schema;
pub mod sql;
pub mod timeseries;
pub mod vector;

pub use document::{Collection, Document, DocumentId, DocumentStore};
pub use error::DatabaseError;
pub use gateway::{GatewayConfig, GatewayServer};
pub use graph::{
    Direction, Edge, EdgeId, GraphError, GraphQuery, GraphQueryParser, GraphStore, Node, NodeId,
    PathFinder, PathResult, TraversalQuery, TraversalResult, Traverser,
};
pub use index::{Index, IndexConfig, IndexManager, IndexType};
pub use keyvalue::{KeyValue, KeyValueStore, KvEntry};
pub use query::{Filter, Query, QueryEngine, QueryResult, SortOrder};
pub use schema::{Field, FieldType, Schema, SchemaValidator};
pub use replication::{
    ClusterConfig, Command as RaftCommand, NodeRole, RaftConfig, RaftEvent, RaftNode, RaftState,
    ReplicatedLog,
};
pub use sql::{QueryResult as SqlQueryResult, SqlEngine, SqlParser, SqlType, SqlValue, Table, TableDef};
pub use timeseries::{DataPoint, Metric, TimeSeries, TimeSeriesStore};
pub use vector::{Embedding, SimilarityMetric, VectorIndex, VectorStore};

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

use parking_lot::RwLock;

/// Database identifier.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct DatabaseId(pub [u8; 32]);

impl DatabaseId {
    /// Creates a new database ID from name.
    pub fn from_name(owner: &[u8; 32], name: &str) -> Self {
        let mut input = Vec::new();
        input.extend_from_slice(owner);
        input.extend_from_slice(name.as_bytes());
        DatabaseId(*blake3::hash(&input).as_bytes())
    }

    /// Returns the bytes.
    pub fn as_bytes(&self) -> &[u8; 32] {
        &self.0
    }
}

impl std::fmt::Display for DatabaseId {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "db_{}", hex::encode(&self.0[..8]))
    }
}

/// Database configuration.
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DatabaseConfig {
    /// Database name.
    pub name: String,
    /// Owner address.
    pub owner: [u8; 32],
    /// Maximum storage size (bytes).
    pub max_size: u64,
    /// Enable vector indexing.
    pub vector_enabled: bool,
    /// Vector dimensions (if enabled).
    pub vector_dimensions: u32,
    /// Replication factor.
    pub replication: u8,
    /// TTL for entries (0 = no expiry).
    pub default_ttl: u64,
}

impl Default for DatabaseConfig {
    fn default() -> Self {
        Self {
            name: "default".to_string(),
            owner: [0u8; 32],
            max_size: 1024 * 1024 * 1024, // 1 GB
            vector_enabled: false,
            vector_dimensions: 0,
            replication: 3,
            default_ttl: 0,
        }
    }
}

/// Database statistics.
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct DatabaseStats {
    /// Total documents/entries.
    pub entry_count: u64,
    /// Total storage used (bytes).
    pub storage_used: u64,
    /// Total reads.
    pub reads: u64,
    /// Total writes.
    pub writes: u64,
    /// Total vector searches.
    pub vector_searches: u64,
    /// Index count.
    pub index_count: u32,
}

/// Unified database instance supporting multiple models.
pub struct Database {
    /// Database ID.
    pub id: DatabaseId,
    /// Configuration.
    pub config: DatabaseConfig,
    /// Key-value store.
    kv: Arc<KeyValueStore>,
    /// Document store.
    docs: Arc<DocumentStore>,
    /// Vector store.
    vectors: Arc<VectorStore>,
    /// Time-series store.
    timeseries: Arc<TimeSeriesStore>,
    /// Query engine.
    query_engine: Arc<QueryEngine>,
    /// Index manager.
    index_manager: Arc<IndexManager>,
    /// Statistics.
    stats: RwLock<DatabaseStats>,
}

impl Database {
    /// Creates a new database.
    pub fn new(config: DatabaseConfig) -> Self {
        let id = DatabaseId::from_name(&config.owner, &config.name);

        let kv = Arc::new(KeyValueStore::new());
        let docs = Arc::new(DocumentStore::new());
        let vectors = Arc::new(VectorStore::new(config.vector_dimensions));
        let timeseries = Arc::new(TimeSeriesStore::new());
        let index_manager = Arc::new(IndexManager::new());
        let query_engine = Arc::new(QueryEngine::new(
            docs.clone(),
            vectors.clone(),
            index_manager.clone(),
        ));

        Self {
            id,
            config,
            kv,
            docs,
            vectors,
            timeseries,
            query_engine,
            index_manager,
            stats: RwLock::new(DatabaseStats::default()),
        }
    }

    /// Returns the key-value store.
    pub fn kv(&self) -> &KeyValueStore {
        &self.kv
    }

    /// Returns the document store.
    pub fn documents(&self) -> &DocumentStore {
        &self.docs
    }

    /// Returns the vector store.
    pub fn vectors(&self) -> &VectorStore {
        &self.vectors
    }

    /// Returns the time-series store.
    pub fn timeseries(&self) -> &TimeSeriesStore {
        &self.timeseries
    }

    /// Returns the query engine.
    pub fn query(&self) -> &QueryEngine {
        &self.query_engine
    }

    /// Returns current statistics.
    pub fn stats(&self) -> DatabaseStats {
        self.stats.read().clone()
    }

    /// Records a read operation.
    pub fn record_read(&self) {
        self.stats.write().reads += 1;
    }

    /// Records a write operation.
    pub fn record_write(&self, bytes: u64) {
        let mut stats = self.stats.write();
        stats.writes += 1;
        stats.storage_used += bytes;
    }

    /// Records a vector search.
    pub fn record_vector_search(&self) {
        self.stats.write().vector_searches += 1;
    }
}

/// Database manager for multiple databases.
pub struct DatabaseManager {
    /// Active databases.
    databases: RwLock<HashMap<DatabaseId, Arc<Database>>>,
    /// Default configuration.
    default_config: DatabaseConfig,
}

impl DatabaseManager {
    /// Creates a new database manager.
    pub fn new() -> Self {
        Self {
            databases: RwLock::new(HashMap::new()),
            default_config: DatabaseConfig::default(),
        }
    }

    /// Creates a new database.
    pub fn create(&self, config: DatabaseConfig) -> Result<Arc<Database>, DatabaseError> {
        let db = Arc::new(Database::new(config));
        let id = db.id;

        let mut dbs = self.databases.write();
        if dbs.contains_key(&id) {
            return Err(DatabaseError::AlreadyExists(id.to_string()));
        }

        dbs.insert(id, db.clone());
        Ok(db)
    }

    /// Gets a database by ID.
    pub fn get(&self, id: &DatabaseId) -> Option<Arc<Database>> {
        self.databases.read().get(id).cloned()
    }

    /// Gets a database by name.
    pub fn get_by_name(&self, owner: &[u8; 32], name: &str) -> Option<Arc<Database>> {
        let id = DatabaseId::from_name(owner, name);
        self.get(&id)
    }

    /// Deletes a database.
    pub fn delete(&self, id: &DatabaseId) -> Result<(), DatabaseError> {
        let mut dbs = self.databases.write();
        if dbs.remove(id).is_none() {
            return Err(DatabaseError::NotFound(id.to_string()));
        }
        Ok(())
    }

    /// Lists all databases for an owner.
    pub fn list(&self, owner: &[u8; 32]) -> Vec<Arc<Database>> {
        self.databases
            .read()
            .values()
            .filter(|db| &db.config.owner == owner)
            .cloned()
            .collect()
    }
}

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

/// Pricing calculator for database operations.
pub struct DatabasePricing {
    /// Storage cost per GB per month (in atomic SYNOR).
    pub storage_per_gb_month: u64,
    /// Read cost per million operations.
    pub reads_per_million: u64,
    /// Write cost per million operations.
    pub writes_per_million: u64,
    /// Vector search cost per million.
    pub vector_search_per_million: u64,
}

impl Default for DatabasePricing {
    fn default() -> Self {
        Self {
            storage_per_gb_month: 100_000_000,     // 0.1 SYNOR
            reads_per_million: 1_000_000,          // 0.001 SYNOR
            writes_per_million: 10_000_000,        // 0.01 SYNOR
            vector_search_per_million: 50_000_000, // 0.05 SYNOR
        }
    }
}

impl DatabasePricing {
    /// Calculates cost for given usage.
    pub fn calculate(&self, stats: &DatabaseStats, days: u64) -> u64 {
        let gb = stats.storage_used as f64 / (1024.0 * 1024.0 * 1024.0);
        let months = days as f64 / 30.0;

        let storage_cost = (gb * months * self.storage_per_gb_month as f64) as u64;
        let read_cost = stats.reads * self.reads_per_million / 1_000_000;
        let write_cost = stats.writes * self.writes_per_million / 1_000_000;
        let vector_cost = stats.vector_searches * self.vector_search_per_million / 1_000_000;

        storage_cost + read_cost + write_cost + vector_cost
    }

    /// Estimates monthly cost for given parameters.
    pub fn estimate_monthly(
        &self,
        storage_gb: f64,
        reads_per_day: u64,
        writes_per_day: u64,
        vector_searches_per_day: u64,
    ) -> u64 {
        let storage_cost = (storage_gb * self.storage_per_gb_month as f64) as u64;
        let reads_monthly = reads_per_day * 30;
        let writes_monthly = writes_per_day * 30;
        let vectors_monthly = vector_searches_per_day * 30;

        let read_cost = reads_monthly * self.reads_per_million / 1_000_000;
        let write_cost = writes_monthly * self.writes_per_million / 1_000_000;
        let vector_cost = vectors_monthly * self.vector_search_per_million / 1_000_000;

        storage_cost + read_cost + write_cost + vector_cost
    }
}

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

    #[test]
    fn test_database_id() {
        let owner = [1u8; 32];
        let id1 = DatabaseId::from_name(&owner, "test");
        let id2 = DatabaseId::from_name(&owner, "test");
        let id3 = DatabaseId::from_name(&owner, "other");

        assert_eq!(id1, id2);
        assert_ne!(id1, id3);
    }

    #[test]
    fn test_database_creation() {
        let config = DatabaseConfig {
            name: "mydb".to_string(),
            owner: [1u8; 32],
            ..Default::default()
        };

        let db = Database::new(config);
        assert_eq!(db.stats().entry_count, 0);
    }

    #[test]
    fn test_database_manager() {
        let manager = DatabaseManager::new();

        let config = DatabaseConfig {
            name: "test".to_string(),
            owner: [1u8; 32],
            ..Default::default()
        };

        let db = manager.create(config.clone()).unwrap();
        assert!(manager.get(&db.id).is_some());

        // Duplicate should fail.
        assert!(manager.create(config).is_err());

        // Delete.
        manager.delete(&db.id).unwrap();
        assert!(manager.get(&db.id).is_none());
    }

    #[test]
    fn test_pricing() {
        let pricing = DatabasePricing::default();

        let stats = DatabaseStats {
            storage_used: 1024 * 1024 * 1024, // 1 GB
            reads: 1_000_000,
            writes: 100_000,
            vector_searches: 10_000,
            ..Default::default()
        };

        let cost = pricing.calculate(&stats, 30);
        assert!(cost > 0);

        // Estimate monthly.
        let monthly = pricing.estimate_monthly(1.0, 10000, 1000, 100);
        assert!(monthly > 0);
    }
}
