//! Backend trait definitions for Athena client.
use async_trait::async_trait;
use serde_json::Value;
use std::fmt::{Debug, Formatter, Result as StdResult};
use std::time::Instant;

/// Supported database backends.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BackendType {
    Native,
    Supabase,
    Postgrest,
    Scylla,
    Neon,
    PostgreSQL,
}

/// The type of query language that will be executed.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum QueryLanguage {
    Sql,
    Cql,
    /// PostgREST style query string (e.g. `select=id,name,instruments(id,name)`).
    Postgrest,
}

/// A query that has already been translated into backend-specific SQL/CQL.
#[derive(Debug, Clone)]
pub struct TranslatedQuery {
    pub sql: String,
    pub language: QueryLanguage,
    pub params: Vec<Value>,
    pub table: Option<String>,
}

impl TranslatedQuery {
    /// Create a new translated query.
    pub fn new(
        sql: impl Into<String>,
        language: QueryLanguage,
        params: Vec<Value>,
        table: Option<String>,
    ) -> Self {
        Self {
            sql: sql.into(),
            language,
            params,
            table,
        }
    }
}

/// The normalized result of executing a query.
#[derive(Clone)]
pub struct QueryResult {
    pub rows: Vec<Value>,
    pub columns: Vec<String>,
}

/// Debug representation for query results.
impl Debug for QueryResult {
    fn fmt(&self, f: &mut Formatter<'_>) -> StdResult {
        f.debug_struct("QueryResult")
            .field("rows", &self.rows)
            .field("columns", &self.columns)
            .finish()
    }
}

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

/// Health status returned by a backend health check.
pub enum HealthStatus {
    Healthy,
    Offline(Instant),
}

/// Common result type for backend operations.
pub type BackendResult<T> = Result<T, BackendError>;

/// Unified error type for backend implementations.
#[derive(thiserror::Error, Debug)]
pub enum BackendError {
    #[error("backend error: {0}")]
    Generic(String),
}

/// Trait that every backend must implement.
#[async_trait]
pub trait DatabaseBackend: Send + Sync {
    async fn execute_query(&self, query: TranslatedQuery) -> BackendResult<QueryResult>;

    async fn health_check(&self) -> BackendResult<HealthStatus>;

    fn backend_type(&self) -> BackendType;

    fn supports_sql(&self) -> bool;

    fn supports_cql(&self) -> bool;

    /// Expose the concrete backend for downcasting when deeper capabilities are required
    /// (for example, schema introspection in SQL translators).
    fn as_any(&self) -> &dyn std::any::Any;
}
