//! Admin Dashboard Handler
//!
//! Provides admin dashboard endpoints using proper database abstractions

use crate::auth::middleware::RequireAuth;
use crate::database::Database;
use crate::database::connection::DatabaseConnection;
use axum::{
    extract::{Query, State},
    http::StatusCode,
    response::Json,
};
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use shared::auth::{HasPermissions, User};
use std::collections::HashMap;
use uuid::Uuid;

#[derive(Debug, Serialize, Deserialize)]
pub struct AdminStats {
    pub total_users: u32,
    pub active_users: u32,
    pub content_items: u32,
    pub total_roles: u32,
    pub pending_approvals: u32,
    pub system_health: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct RecentActivity {
    pub id: String,
    pub user_id: String,
    pub user_email: String,
    pub action: String,
    pub resource_type: String,
    pub resource_id: Option<String>,
    pub timestamp: DateTime<Utc>,
    pub status: String,
    pub ip_address: Option<String>,
    pub user_agent: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct SystemHealth {
    pub database_status: String,
    pub cache_status: String,
    pub email_service_status: String,
    pub storage_status: String,
    pub last_backup: Option<DateTime<Utc>>,
    pub uptime: String,
    pub memory_usage: f64,
    pub cpu_usage: f64,
}

#[derive(Debug, Deserialize)]
pub struct ActivityQuery {
    pub limit: Option<u32>,
    pub offset: Option<u32>,
    pub user_id: Option<String>,
    pub action: Option<String>,
    pub from_date: Option<DateTime<Utc>>,
    pub to_date: Option<DateTime<Utc>>,
}

/// Get admin dashboard statistics
pub async fn get_admin_stats(
    RequireAuth(user): RequireAuth,
    State(db): State<Database>,
) -> Result<Json<AdminStats>, StatusCode> {
    // Check admin permissions using shared auth trait
    if !user.has_permission(shared::auth::Permission::ManageSystem) {
        return Err(StatusCode::FORBIDDEN);
    }

    let conn = db.pool().create_connection();

    // Get user statistics using database abstraction
    let total_users = get_total_users(&conn)
        .await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    let active_users = get_active_users(&conn)
        .await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    // Get content statistics if content feature is enabled
    let content_items = if cfg!(feature = "content-db") {
        get_content_items(&conn)
            .await
            .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
    } else {
        0
    };

    // Get role statistics
    let total_roles = get_total_roles(&conn)
        .await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    // Get pending approvals
    let pending_approvals = get_pending_approvals(&conn)
        .await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    // Check system health
    let system_health = check_system_health(&conn)
        .await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    Ok(Json(AdminStats {
        total_users,
        active_users,
        content_items,
        total_roles,
        pending_approvals,
        system_health,
    }))
}

/// Get recent activity logs
pub async fn get_recent_activity(
    RequireAuth(user): RequireAuth,
    Query(query): Query<ActivityQuery>,
    State(db): State<Database>,
) -> Result<Json<Vec<RecentActivity>>, StatusCode> {
    // Check admin permissions
    if !user.has_permission(shared::auth::Permission::ManageSystem) {
        return Err(StatusCode::FORBIDDEN);
    }

    let conn = db.pool().create_connection();
    let limit = query.limit.unwrap_or(50).min(100);
    let offset = query.offset.unwrap_or(0);

    let activities = get_activity_logs(&conn, &query, limit, offset)
        .await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;

    Ok(Json(activities))
}

/// Get system health information
pub async fn get_system_health(
    RequireAuth(user): RequireAuth,
    State(db): State<Database>,
) -> Result<Json<SystemHealth>, StatusCode> {
    // Check admin permissions
    if !user.has_permission(shared::auth::Permission::ManageSystem) {
        return Err(StatusCode::FORBIDDEN);
    }

    let conn = db.pool().create_connection();

    let health = SystemHealth {
        database_status: check_database_health(&conn).await,
        cache_status: check_cache_health().await,
        email_service_status: check_email_service_health().await,
        storage_status: check_storage_health().await,
        last_backup: get_last_backup_time(&conn).await.ok().flatten(),
        uptime: get_system_uptime(),
        memory_usage: get_memory_usage(),
        cpu_usage: get_cpu_usage(),
    };

    Ok(Json(health))
}

/// Get admin dashboard summary
pub async fn get_dashboard_summary(
    RequireAuth(user): RequireAuth,
    State(db): State<Database>,
) -> Result<Json<HashMap<String, serde_json::Value>>, StatusCode> {
    // Check admin permissions
    if !user.has_permission(shared::auth::Permission::ManageSystem) {
        return Err(StatusCode::FORBIDDEN);
    }

    let conn = db.pool().create_connection();
    let mut summary = HashMap::new();

    // Get basic stats
    let stats = get_admin_stats(RequireAuth(user.clone()), State(db.clone())).await?;
    summary.insert("stats".to_string(), serde_json::to_value(stats.0).unwrap());

    // Get recent activity (limited)
    let recent_activity = get_recent_activity(
        RequireAuth(user.clone()),
        Query(ActivityQuery {
            limit: Some(10),
            offset: Some(0),
            user_id: None,
            action: None,
            from_date: None,
            to_date: None,
        }),
        State(db.clone()),
    )
    .await?;
    summary.insert(
        "recent_activity".to_string(),
        serde_json::to_value(recent_activity.0).unwrap(),
    );

    // Get system health
    let health = get_system_health(RequireAuth(user), State(db.clone())).await?;
    summary.insert(
        "system_health".to_string(),
        serde_json::to_value(health.0).unwrap(),
    );

    // Get top users by activity
    let top_users = get_top_users_by_activity(&conn)
        .await
        .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
    summary.insert(
        "top_users".to_string(),
        serde_json::to_value(top_users).unwrap(),
    );

    // Get content statistics by type if content feature is enabled
    if cfg!(feature = "content-db") {
        let content_stats = get_content_statistics(&conn)
            .await
            .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
        summary.insert(
            "content_stats".to_string(),
            serde_json::to_value(content_stats).unwrap(),
        );
    }

    Ok(Json(summary))
}

// Database abstraction helper functions

async fn get_total_users(conn: &DatabaseConnection) -> anyhow::Result<u32> {
    let sql = "SELECT COUNT(*) as count FROM users";
    let row = conn.fetch_one(sql, &[]).await?;
    Ok(row.get_i64("count")? as u32)
}

async fn get_active_users(conn: &DatabaseConnection) -> anyhow::Result<u32> {
    let sql = match conn.database_type() {
        crate::database::DatabaseType::PostgreSQL => {
            "SELECT COUNT(*) as count FROM users WHERE is_active = true AND last_login > NOW() - INTERVAL '30 days'"
        }
        crate::database::DatabaseType::SQLite => {
            "SELECT COUNT(*) as count FROM users WHERE is_active = 1 AND last_login > datetime('now', '-30 days')"
        }
    };
    let row = conn.fetch_one(sql, &[]).await?;
    Ok(row.get_i64("count")? as u32)
}

async fn get_content_items(conn: &DatabaseConnection) -> anyhow::Result<u32> {
    let sql = "SELECT COUNT(*) as count FROM content_items WHERE status = 'published'";
    let row = conn.fetch_optional(sql, &[]).await?;
    match row {
        Some(row) => Ok(row.get_i64("count")? as u32),
        None => Ok(0),
    }
}

async fn get_total_roles(conn: &DatabaseConnection) -> anyhow::Result<u32> {
    let sql = "SELECT COUNT(*) as count FROM roles";
    let row = conn.fetch_one(sql, &[]).await?;
    Ok(row.get_i64("count")? as u32)
}

async fn get_pending_approvals(conn: &DatabaseConnection) -> anyhow::Result<u32> {
    let sql = "SELECT COUNT(*) as count FROM content_items WHERE status = 'pending_approval'";
    let row = conn.fetch_optional(sql, &[]).await?;
    match row {
        Some(row) => Ok(row.get_i64("count")? as u32),
        None => Ok(0),
    }
}

async fn check_system_health(conn: &DatabaseConnection) -> anyhow::Result<String> {
    // Test database connection
    let sql = "SELECT 1 as test";
    match conn.fetch_one(sql, &[]).await {
        Ok(_) => Ok("Healthy".to_string()),
        Err(_) => Ok("Degraded".to_string()),
    }
}

async fn get_activity_logs(
    conn: &DatabaseConnection,
    query: &ActivityQuery,
    limit: u32,
    offset: u32,
) -> anyhow::Result<Vec<RecentActivity>> {
    let mut sql = "SELECT al.id, al.user_id, u.email as user_email, al.action, al.resource_type, al.resource_id, al.timestamp, al.status, al.ip_address, al.user_agent FROM activity_logs al JOIN users u ON al.user_id = u.id WHERE 1=1".to_string();
    let mut params = Vec::new();
    let mut param_index = 1;

    if let Some(user_id) = &query.user_id {
        sql.push_str(&format!(" AND al.user_id = ${}", param_index));
        params.push(user_id.into());
        param_index += 1;
    }

    if let Some(action) = &query.action {
        sql.push_str(&format!(" AND al.action = ${}", param_index));
        params.push(action.into());
        param_index += 1;
    }

    if let Some(from_date) = &query.from_date {
        sql.push_str(&format!(" AND al.timestamp >= ${}", param_index));
        params.push((*from_date).into());
        param_index += 1;
    }

    if let Some(to_date) = &query.to_date {
        sql.push_str(&format!(" AND al.timestamp <= ${}", param_index));
        params.push((*to_date).into());
        param_index += 1;
    }

    sql.push_str(&format!(
        " ORDER BY al.timestamp DESC LIMIT ${} OFFSET ${}",
        param_index,
        param_index + 1
    ));
    params.push((limit as i64).into());
    params.push((offset as i64).into());

    let rows = conn.fetch_all(&sql, &params).await?;
    let mut activities = Vec::new();

    for row in rows {
        activities.push(RecentActivity {
            id: row.get_string("id")?,
            user_id: row.get_string("user_id")?,
            user_email: row.get_string("user_email")?,
            action: row.get_string("action")?,
            resource_type: row.get_string("resource_type")?,
            resource_id: row.get_optional_string("resource_id")?,
            timestamp: row.get_datetime("timestamp")?,
            status: row.get_string("status")?,
            ip_address: row.get_optional_string("ip_address")?,
            user_agent: row.get_optional_string("user_agent")?,
        });
    }

    Ok(activities)
}

async fn check_database_health(conn: &DatabaseConnection) -> String {
    match conn.fetch_one("SELECT 1 as test", &[]).await {
        Ok(_) => "Healthy".to_string(),
        Err(_) => "Unhealthy".to_string(),
    }
}

async fn check_cache_health() -> String {
    // Implement cache health check if available
    "Healthy".to_string()
}

async fn check_email_service_health() -> String {
    // Implement email service health check if available
    "Healthy".to_string()
}

async fn check_storage_health() -> String {
    // Implement storage health check
    "Healthy".to_string()
}

async fn get_last_backup_time(conn: &DatabaseConnection) -> anyhow::Result<Option<DateTime<Utc>>> {
    let sql = "SELECT MAX(created_at) as last_backup FROM backups";
    let row = conn.fetch_optional(sql, &[]).await?;
    match row {
        Some(row) => Ok(row.get_optional_datetime("last_backup")?),
        None => Ok(None),
    }
}

fn get_system_uptime() -> String {
    // Implement system uptime calculation
    "24h 30m".to_string()
}

fn get_memory_usage() -> f64 {
    // Implement memory usage calculation
    0.65
}

fn get_cpu_usage() -> f64 {
    // Implement CPU usage calculation
    0.45
}

async fn get_top_users_by_activity(
    conn: &DatabaseConnection,
) -> anyhow::Result<Vec<serde_json::Value>> {
    let sql = match conn.database_type() {
        crate::database::DatabaseType::PostgreSQL => {
            "SELECT u.id, u.email, u.display_name, COUNT(al.id) as activity_count
             FROM users u
             LEFT JOIN activity_logs al ON u.id::text = al.user_id
             WHERE al.timestamp > NOW() - INTERVAL '7 days'
             GROUP BY u.id, u.email, u.display_name
             ORDER BY activity_count DESC
             LIMIT 10"
        }
        crate::database::DatabaseType::SQLite => {
            "SELECT u.id, u.email, u.display_name, COUNT(al.id) as activity_count
             FROM users u
             LEFT JOIN activity_logs al ON u.id = al.user_id
             WHERE al.timestamp > datetime('now', '-7 days')
             GROUP BY u.id, u.email, u.display_name
             ORDER BY activity_count DESC
             LIMIT 10"
        }
    };

    let rows = conn.fetch_all(sql, &[]).await?;
    let mut result = Vec::new();

    for row in rows {
        result.push(serde_json::json!({
            "id": row.get_string("id")?,
            "email": row.get_string("email")?,
            "display_name": row.get_optional_string("display_name")?,
            "activity_count": row.get_i64("activity_count")?
        }));
    }

    Ok(result)
}

async fn get_content_statistics(
    conn: &DatabaseConnection,
) -> anyhow::Result<Vec<serde_json::Value>> {
    let sql = "SELECT content_type, status, COUNT(*) as count
               FROM content_items
               GROUP BY content_type, status
               ORDER BY content_type, status";

    let rows = conn.fetch_all(sql, &[]).await?;
    let mut result = Vec::new();

    for row in rows {
        result.push(serde_json::json!({
            "content_type": row.get_string("content_type")?,
            "status": row.get_string("status")?,
            "count": row.get_i64("count")?
        }));
    }

    Ok(result)
}

/// Log admin activity using database abstraction
pub async fn log_admin_activity(
    conn: &DatabaseConnection,
    user_id: &str,
    action: &str,
    resource_type: &str,
    resource_id: Option<&str>,
    ip_address: Option<&str>,
    user_agent: Option<&str>,
) -> anyhow::Result<()> {
    let sql = match conn.database_type() {
        crate::database::DatabaseType::PostgreSQL => {
            "INSERT INTO activity_logs (id, user_id, action, resource_type, resource_id, ip_address, user_agent, timestamp, status)
             VALUES (gen_random_uuid(), $1, $2, $3, $4, $5, $6, NOW(), 'success')"
        }
        crate::database::DatabaseType::SQLite => {
            "INSERT INTO activity_logs (id, user_id, action, resource_type, resource_id, ip_address, user_agent, timestamp, status)
             VALUES (hex(randomblob(16)), $1, $2, $3, $4, $5, $6, datetime('now'), 'success')"
        }
    };

    let params = vec![
        user_id.into(),
        action.into(),
        resource_type.into(),
        resource_id.map(|s| s.into()).unwrap_or("".into()),
        ip_address.map(|s| s.into()).unwrap_or("".into()),
        user_agent.map(|s| s.into()).unwrap_or("".into()),
    ];

    conn.execute(sql, &params).await?;
    Ok(())
}
