use anyhow::Result;
use clap::Subcommand;
use std::io::{self, Write};

#[derive(Subcommand)]
pub enum AdminCommands {
    /// User management commands
    Users {
        #[command(subcommand)]
        user_command: UserCommands,
    },
    /// Show system statistics
    Stats,
}

#[derive(Subcommand)]
pub enum UserCommands {
    /// List all users
    List,
    /// Delete a user
    Delete {
        /// User selector (ID, username, or email)
        selector: String,
    },
    /// Block a user
    Block {
        /// User selector (ID, username, or email)
        selector: String,
        /// Reason for blocking
        #[arg(short, long)]
        reason: String,
    },
    /// Unblock a user
    Unblock {
        /// User selector (ID, username, or email)
        selector: String,
    },
    /// Logout a user (revoke all tokens)
    Logout {
        /// User selector (ID, username, or email)
        selector: String,
    },
}

pub async fn handle_users_list(token: &str) -> Result<()> {
    use crate::services::auth_service;

    let users = auth_service::admin_list_users(token).await?;

    if users.is_empty() {
        println!("No users found.");
    } else {
        println!("Users:");
        println!(
            "{:<37} {:<20} {:<30} {:<30} {:<8}",
            "ID", "Username", "Name", "Email", "Blocked"
        );
        println!("{}", "-".repeat(130));
        for user in users {
            let blocked_status = if user.blocked { "Yes" } else { "No" };
            println!(
                "{:<37} {:<20} {:<30} {:<30} {:<8}",
                user.id, user.username, user.name, user.email, blocked_status
            );
            if user.blocked && user.blocking_reason.is_some() {
                println!("  └─ Reason: {}", user.blocking_reason.as_ref().unwrap());
            }
        }
    }

    Ok(())
}

pub async fn handle_users_delete(token: &str, selector: &str) -> Result<()> {
    use crate::services::auth_service;

    let user = auth_service::admin_find_user(token, selector).await?;

    print!(
        "Are you sure you want to delete user '{}' ({})?  [y/N]: ",
        user.username, user.email
    );
    io::stdout().flush()?;

    let mut input = String::new();
    io::stdin().read_line(&mut input)?;

    if !input.trim().eq_ignore_ascii_case("y") {
        println!("User deletion cancelled.");
        return Ok(());
    }

    auth_service::admin_delete_user(token, &user.id).await?;

    println!("✓ User '{}' deleted successfully", user.username);

    Ok(())
}

pub async fn handle_users_block(token: &str, selector: &str, reason: &str) -> Result<()> {
    use crate::services::auth_service;

    let user = auth_service::admin_find_user(token, selector).await?;

    if user.blocked {
        println!("User '{}' is already blocked", user.username);
        if let Some(ref existing_reason) = user.blocking_reason {
            println!("Current reason: {}", existing_reason);
        }
        return Ok(());
    }

    print!(
        "Are you sure you want to block user '{}' ({})?  [y/N]: ",
        user.username, user.email
    );
    io::stdout().flush()?;

    let mut input = String::new();
    io::stdin().read_line(&mut input)?;

    if !input.trim().eq_ignore_ascii_case("y") {
        println!("User blocking cancelled.");
        return Ok(());
    }

    auth_service::admin_block_user(token, &user.id, reason).await?;

    println!("✓ User '{}' blocked successfully", user.username);
    println!("  All active sessions have been revoked");

    Ok(())
}

pub async fn handle_users_unblock(token: &str, selector: &str) -> Result<()> {
    use crate::services::auth_service;

    let user = auth_service::admin_find_user(token, selector).await?;

    if !user.blocked {
        println!("User '{}' is not blocked", user.username);
        return Ok(());
    }

    auth_service::admin_unblock_user(token, &user.id).await?;

    println!("✓ User '{}' unblocked successfully", user.username);

    Ok(())
}

pub async fn handle_users_logout(token: &str, selector: &str) -> Result<()> {
    use crate::services::auth_service;

    let user = auth_service::admin_find_user(token, selector).await?;

    print!(
        "Are you sure you want to logout user '{}' ({})? This will revoke all their active sessions. [y/N]: ",
        user.username, user.email
    );
    io::stdout().flush()?;

    let mut input = String::new();
    io::stdin().read_line(&mut input)?;

    if !input.trim().eq_ignore_ascii_case("y") {
        println!("User logout cancelled.");
        return Ok(());
    }

    let revoked_count = auth_service::admin_logout_user(token, &user.id).await?;

    println!("✓ User '{}' logged out successfully", user.username);
    println!("  Revoked {} session token(s)", revoked_count);

    Ok(())
}

pub async fn handle_stats(token: &str) -> Result<()> {
    use crate::services::{admin_service, auth_service};

    println!("Fetching system statistics...\n");

    let auth_stats_future = auth_service::admin_auth_stats(token);
    let data_stats_future = admin_service::admin_data_stats(token);

    let (auth_result, data_result) = tokio::join!(auth_stats_future, data_stats_future);

    // Build a map of user ID -> username for later use
    let mut user_map = std::collections::HashMap::new();

    if let Ok(ref stats) = auth_result {
        if let Some(registered_users) = stats.get("registered-users").and_then(|v| v.as_array()) {
            for user in registered_users {
                if let (Some(id), Some(username)) = (
                    user.get("id").and_then(|v| v.as_str()),
                    user.get("username").and_then(|v| v.as_str()),
                ) {
                    user_map.insert(id.to_string(), username.to_string());
                }
            }
        }
    }

    // Display Auth Service Stats
    println!("════════════════════════════════════════════════════════");
    println!("  Authentication Service Statistics");
    println!("════════════════════════════════════════════════════════");

    match &auth_result {
        Ok(stats) => {
            if let Some(total_users) = stats.get("total-users") {
                println!("Total Users:          {}", total_users);
            }

            if let Some(total_tokens) = stats.get("total-tokens") {
                println!("Total Tokens:         {}", total_tokens);
            }

            if let Some(web_tokens) = stats.get("total-web-tokens") {
                println!("  Web Tokens:         {}", web_tokens);
            }

            if let Some(mobile_tokens) = stats.get("total-mobile-tokens") {
                println!("  Mobile Tokens:      {}", mobile_tokens);
            }

            if let Some(cli_tokens) = stats.get("total-cli-tokens") {
                println!("  CLI Tokens:         {}", cli_tokens);
            }

            if let Some(total_keys) = stats.get("total-keys") {
                println!("Total Keys:           {}", total_keys);
            }

            if let Some(pending_auths) = stats.get("pending-authentications") {
                println!("Pending Auths:        {}", pending_auths);
            }

            if let Some(connected_users) = stats.get("connected-users").and_then(|v| v.as_array()) {
                println!("Connected Users:      {}", connected_users.len());

                if !connected_users.is_empty() {
                    println!("\nCurrently Connected:");
                    for (i, session_id) in connected_users.iter().enumerate() {
                        if let Some(session) = session_id.as_str() {
                            // Parse session format: "session_<uuid>"
                            let user_id = if session.starts_with("session_") {
                                &session[8..] // Skip "session_" prefix
                            } else {
                                session
                            };

                            // Try to map user ID to username, fallback to session ID
                            let display_name =
                                user_map.get(user_id).map(|s| s.as_str()).unwrap_or(user_id);
                            println!("  {}. {} ({})", i + 1, session, display_name);
                        }
                    }
                }
            }

            if let Some(registered_users) = stats.get("registered-users").and_then(|v| v.as_array())
            {
                let blocked_count = registered_users
                    .iter()
                    .filter(|u| u.get("blocked").and_then(|b| b.as_bool()).unwrap_or(false))
                    .count();

                let verified_count = registered_users
                    .iter()
                    .filter(|u| {
                        u.get("emailValidated").is_some()
                            && !u.get("emailValidated").unwrap().is_null()
                    })
                    .count();

                println!("\nUser Details:");
                println!("  Email Verified:     {}", verified_count);
                println!("  Blocked:            {}", blocked_count);

                // Count users with subscriptions
                let subscribed_count = registered_users
                    .iter()
                    .filter(|u| u.get("plan").is_some() && !u.get("plan").unwrap().is_null())
                    .count();
                println!("  With Subscription:  {}", subscribed_count);

                // Count connected sessions per user
                let mut sessions_per_user: std::collections::HashMap<String, i64> =
                    std::collections::HashMap::new();
                if let Some(connected_users) =
                    stats.get("connected-users").and_then(|v| v.as_array())
                {
                    for session_id in connected_users {
                        if let Some(session) = session_id.as_str() {
                            // Parse session format: "session_<uuid>"
                            let user_id = if session.starts_with("session_") {
                                &session[8..] // Skip "session_" prefix
                            } else {
                                session
                            };
                            *sessions_per_user.entry(user_id.to_string()).or_insert(0) += 1;
                        }
                    }
                }

                // Display per-user token and key counts in table format
                println!("\nUser Authentication Resources:");
                println!(
                    "{:<18} {:<22} {:<28} {:>3} {:>3} {:>3} {:>3} {:>3} {:>6} {:>4} {:<17} {:<17}",
                    "Username",
                    "Name",
                    "Email",
                    "Ver",
                    "Blk",
                    "Web",
                    "Mob",
                    "CLI",
                    "Keys",
                    "Sess",
                    "Registered",
                    "Last Login"
                );
                println!("{}", "-".repeat(140));

                let mut user_auth_data: Vec<_> = registered_users
                    .iter()
                    .filter_map(|u| {
                        let user_id = u.get("id").and_then(|v| v.as_str())?;
                        let username_str = u.get("username").and_then(|v| v.as_str()).unwrap_or("");
                        let name = u
                            .get("name")
                            .and_then(|v| v.as_str())
                            .unwrap_or("")
                            .to_string();
                        let email = u
                            .get("email")
                            .and_then(|v| v.as_str())
                            .unwrap_or("")
                            .to_string();
                        let web_tokens = u
                            .get("webTokensCount")
                            .and_then(|v| v.as_i64())
                            .unwrap_or(0);
                        let mobile_tokens = u
                            .get("mobileTokensCount")
                            .and_then(|v| v.as_i64())
                            .unwrap_or(0);
                        let cli_tokens = u
                            .get("cliTokensCount")
                            .and_then(|v| v.as_i64())
                            .unwrap_or(0);
                        let keys = u.get("keysCount").and_then(|v| v.as_i64()).unwrap_or(0);
                        let sessions = *sessions_per_user.get(user_id).unwrap_or(&0);

                        let email_verified = u.get("emailValidated").is_some()
                            && !u.get("emailValidated").unwrap().is_null();

                        let blocked = u.get("blocked").and_then(|v| v.as_bool()).unwrap_or(false);

                        let created = u
                            .get("created")
                            .and_then(|v| v.as_str())
                            .unwrap_or("")
                            .to_string();
                        let last_login = u
                            .get("lastLogin")
                            .and_then(|v| v.as_str())
                            .unwrap_or("")
                            .to_string();

                        let display_name = user_map
                            .get(user_id)
                            .map(|s| s.to_string())
                            .unwrap_or_else(|| username_str.to_string());

                        Some((
                            display_name,
                            name,
                            email,
                            email_verified,
                            blocked,
                            web_tokens,
                            mobile_tokens,
                            cli_tokens,
                            keys,
                            sessions,
                            created,
                            last_login,
                        ))
                    })
                    .collect();

                // Sort by total tokens + keys descending
                user_auth_data
                    .sort_by(|a, b| (b.5 + b.6 + b.7 + b.8).cmp(&(a.5 + a.6 + a.7 + a.8)));

                for (
                    username,
                    name,
                    email,
                    verified,
                    blocked,
                    web_tokens,
                    mobile_tokens,
                    cli_tokens,
                    keys,
                    sessions,
                    created,
                    last_login,
                ) in &user_auth_data
                {
                    // Truncate long fields for table display
                    let name_display = if name.len() > 22 {
                        format!("{}...", &name[..19])
                    } else {
                        name.clone()
                    };
                    let email_display = if email.len() > 28 {
                        format!("{}...", &email[..25])
                    } else {
                        email.clone()
                    };

                    // Format dates with time (yyyy-MM-dd HH:mm)
                    let created_display = if created.len() >= 16 {
                        created[..16].replace("T", " ")
                    } else if created.len() >= 10 {
                        created[..10].to_string()
                    } else {
                        created.clone()
                    };
                    let last_login_display = if last_login.len() >= 16 {
                        last_login[..16].replace("T", " ")
                    } else if last_login.len() >= 10 {
                        last_login[..10].to_string()
                    } else {
                        last_login.clone()
                    };

                    let verified_display = if *verified { "✓" } else { " " };
                    let blocked_display = if *blocked { "✗" } else { " " };

                    println!(
                        "{:<18} {:<22} {:<28} {:>3} {:>3} {:>3} {:>3} {:>3} {:>6} {:>4} {:<17} {:<17}",
                        username,
                        name_display,
                        email_display,
                        verified_display,
                        blocked_display,
                        web_tokens,
                        mobile_tokens,
                        cli_tokens,
                        keys,
                        sessions,
                        created_display,
                        last_login_display
                    );
                }

                if let (Some(total_web), Some(total_mobile), Some(total_cli), Some(total_keys)) = (
                    stats.get("total-web-tokens").and_then(|v| v.as_i64()),
                    stats.get("total-mobile-tokens").and_then(|v| v.as_i64()),
                    stats.get("total-cli-tokens").and_then(|v| v.as_i64()),
                    stats.get("total-keys").and_then(|v| v.as_i64()),
                ) {
                    let total_sessions: i64 = sessions_per_user.values().sum();
                    println!("{}", "-".repeat(140));
                    println!(
                        "{:<18} {:<22} {:<28} {:>3} {:>3} {:>3} {:>3} {:>3} {:>6} {:>4} {:<17} {:<17}",
                        "TOTAL",
                        "",
                        "",
                        "",
                        "",
                        total_web,
                        total_mobile,
                        total_cli,
                        total_keys,
                        total_sessions,
                        "",
                        ""
                    );
                }
            }
        }
        Err(ref e) => {
            println!("❌ Failed to fetch auth stats: {}", e);
        }
    }

    // Display Data Service Stats
    println!("\n════════════════════════════════════════════════════════");
    println!("  Data Service Statistics");
    println!("════════════════════════════════════════════════════════");

    match data_result {
        Ok(stats) => {
            if let Some(user_stats) = stats.get("stats").and_then(|v| v.as_array()) {
                let mut total_workspaces = 0;
                let mut total_notebooks = 0;
                let mut total_notes = 0;
                let mut total_attachments = 0;
                let mut total_orphaned_attachments = 0;
                let active_users = user_stats.len();

                // Collect user data for table display
                let mut user_data: Vec<(String, i64, i64, i64, i64, i64)> = Vec::new();

                for user_stat in user_stats {
                    if let Some(user_id) = user_stat.get("userID").and_then(|v| v.as_str()) {
                        // Get summary object which contains the actual counts
                        let ws = user_stat
                            .get("summary")
                            .and_then(|s| s.get("workspaces"))
                            .and_then(|v| v.as_i64())
                            .unwrap_or(0);
                        let nb = user_stat
                            .get("summary")
                            .and_then(|s| s.get("notebooks"))
                            .and_then(|v| v.as_i64())
                            .unwrap_or(0);
                        let nt = user_stat
                            .get("summary")
                            .and_then(|s| s.get("notes"))
                            .and_then(|v| v.as_i64())
                            .unwrap_or(0);
                        let att = user_stat
                            .get("summary")
                            .and_then(|s| s.get("attachments"))
                            .and_then(|v| v.as_i64())
                            .unwrap_or(0);
                        let orphaned_att = user_stat
                            .get("summary")
                            .and_then(|s| s.get("orphaned"))
                            .and_then(|o| o.get("attachments"))
                            .and_then(|v| v.as_i64())
                            .unwrap_or(0);

                        total_workspaces += ws as usize;
                        total_notebooks += nb as usize;
                        total_notes += nt as usize;
                        total_attachments += att as usize;
                        total_orphaned_attachments += orphaned_att as usize;

                        // Get username from user_map
                        let username =
                            user_map
                                .get(user_id)
                                .map(|s| s.to_string())
                                .unwrap_or_else(|| {
                                    if user_id.len() >= 8 {
                                        user_id[..8].to_string()
                                    } else {
                                        user_id.to_string()
                                    }
                                });

                        user_data.push((username, ws, nb, nt, att, orphaned_att));
                    }
                }

                println!("Active Users:         {}", active_users);
                println!("Total Workspaces:     {}", total_workspaces);
                println!("Total Notebooks:      {}", total_notebooks);
                println!("Total Notes:          {}", total_notes);
                println!("Total Attachments:    {}", total_attachments);

                // Display user data in table format
                if !user_data.is_empty() {
                    println!("\nUser Content Breakdown:");
                    println!(
                        "{:<20} {:>12} {:>12} {:>12} {:>12} {:>12}",
                        "Username", "Workspaces", "Notebooks", "Notes", "Attachments", "Orphaned"
                    );
                    println!("{}", "-".repeat(87));

                    // Sort by notes count descending
                    user_data.sort_by(|a, b| b.3.cmp(&a.3));

                    for (username, ws, nb, nt, att, orphaned) in &user_data {
                        println!(
                            "{:<20} {:>12} {:>12} {:>12} {:>12} {:>12}",
                            username, ws, nb, nt, att, orphaned
                        );
                    }
                    println!("{}", "-".repeat(87));
                    println!(
                        "{:<20} {:>12} {:>12} {:>12} {:>12} {:>12}",
                        "TOTAL",
                        total_workspaces,
                        total_notebooks,
                        total_notes,
                        total_attachments,
                        total_orphaned_attachments
                    );
                }

                // Show orphaned data if any
                if let Some(orphaned) = stats.get("orphaned") {
                    if let Some(orphaned_attachments) =
                        orphaned.get("attachments").and_then(|v| v.as_array())
                    {
                        if !orphaned_attachments.is_empty() {
                            println!("\n⚠️  Orphaned Attachments: {}", orphaned_attachments.len());
                            println!("\nOrphaned Attachments Details:");
                            println!(
                                "{:<38} {:<20} {:<38} {:<30} {:>12}",
                                "Attachment ID", "Owner", "Note ID", "File Name", "Size (bytes)"
                            );
                            println!("{}", "-".repeat(145));

                            for attachment in orphaned_attachments {
                                let att_id =
                                    attachment.get("id").and_then(|v| v.as_str()).unwrap_or("");
                                let user_id = attachment
                                    .get("userId")
                                    .and_then(|v| v.as_str())
                                    .unwrap_or("");
                                let note_id = attachment
                                    .get("noteId")
                                    .and_then(|v| v.as_str())
                                    .unwrap_or("");
                                let file_name = attachment
                                    .get("fileName")
                                    .and_then(|v| v.as_str())
                                    .unwrap_or("");
                                let size =
                                    attachment.get("size").and_then(|v| v.as_i64()).unwrap_or(0);

                                // Get username from user_map or show first 8 chars of ID
                                let owner = user_map
                                    .get(user_id)
                                    .map(|s| s.to_string())
                                    .unwrap_or_else(|| {
                                        if user_id.len() >= 8 {
                                            user_id[..8].to_string()
                                        } else if user_id.is_empty() {
                                            "unknown".to_string()
                                        } else {
                                            user_id.to_string()
                                        }
                                    });

                                // Truncate file name if too long
                                let file_name_display = if file_name.len() > 30 {
                                    format!("{}...", &file_name[..27])
                                } else {
                                    file_name.to_string()
                                };

                                println!(
                                    "{:<38} {:<20} {:<38} {:<30} {:>12}",
                                    att_id, owner, note_id, file_name_display, size
                                );
                            }
                        }
                    }
                }
            }
        }
        Err(e) => {
            println!("❌ Failed to fetch data stats: {}", e);
        }
    }

    println!("\n");

    Ok(())
}
