use anyhow::Result;
use clap::Parser;

// Generated OpenAPI clients
#[path = "../generated/doqium_data_client/mod.rs"]
mod doqium_data_client;

#[path = "../generated/doqium_auth_client/mod.rs"]
mod doqium_auth_client;

mod api;
mod apis;
mod auth;
mod banner;
mod commands;
mod config;
mod crypto;
mod repository;
mod selector;
mod services;
mod utils;
mod version_check;

use commands::{Cli, Commands};

#[tokio::main]
async fn main() -> Result<()> {
    let cli = Cli::parse();

    // Show banner at the very top for non-auth commands
    let show_banner = !cli.no_banner
        && match &cli.command {
            Some(Commands::Auth { .. }) => false,
            _ => true,
        };

    if show_banner {
        banner::print_banner();
    }

    // Check if this command needs authentication
    let needs_auth = match &cli.command {
        Some(Commands::Auth { auth_command }) => match auth_command {
            commands::auth::AuthCommands::Login { .. } => false,
            commands::auth::AuthCommands::Profiles { profile_command } => match profile_command {
                commands::auth::ProfileCommands::List => false,
                commands::auth::ProfileCommands::Switch { .. } => false,
                commands::auth::ProfileCommands::Delete { .. } => false,
            },
            _ => true,
        },
        _ => true,
    };

    let token = if needs_auth {
        let t = auth::get_or_authenticate_with_override(cli.profile.as_deref()).await?;

        // Show token details unless banner is hidden
        if !cli.no_banner {
            if let Some((username, name, created_at)) = auth::get_token_details(&t) {
                let profile_info = if let Some(profile) = &cli.profile {
                    format!(" [Profile: {}]", profile)
                } else {
                    String::new()
                };
                println!(
                    "✓ Authenticated as: {} ({}) - Token created: {}{}",
                    username, name, created_at, profile_info
                );
                println!();
            }
        }
        t
    } else {
        String::new() // Placeholder for commands that don't need auth
    };

    match &cli.command {
        Some(Commands::Auth { auth_command }) => match auth_command {
            commands::auth::AuthCommands::Login { profile } => {
                // Check if we need to logout existing session for this profile
                if let Ok(Some(existing_token)) = auth::load_token_for_profile(profile) {
                    println!(
                        "Logging out from current session for profile '{}'...",
                        profile
                    );
                    match auth::logout(&existing_token, Some(profile)).await {
                        Ok(_) => println!("✓ Previous session logged out"),
                        Err(e) => eprintln!("Warning: Failed to revoke previous token: {}", e),
                    }
                }

                let _token = auth::authenticate(Some(profile)).await?;
                println!("✓ Authenticated successfully with profile '{}'!", profile);
                return Ok(());
            }
            commands::auth::AuthCommands::Logout { session_id } => {
                let active_profile =
                    auth::get_active_profile_with_override(cli.profile.as_deref())?;
                let token = auth::load_token_with_override(cli.profile.as_deref())?
                    .ok_or_else(|| anyhow::anyhow!("No active session found"))?;

                if let Some(session_id) = session_id {
                    auth::logout_session(&token, session_id).await?;
                    println!("✓ Session logged out successfully");
                } else {
                    auth::logout(&token, Some(&active_profile)).await?;
                    println!(
                        "✓ Logged out successfully from profile '{}'",
                        active_profile
                    );
                }
                return Ok(());
            }
            commands::auth::AuthCommands::List => {
                let token = auth::get_or_authenticate_with_override(cli.profile.as_deref()).await?;
                let tokens = auth::list_auth_tokens(&token).await?;

                if tokens.is_empty() {
                    println!("No active authentication tokens.");
                } else {
                    println!("Active Authentication Tokens:");
                    println!(
                        "{:<37} {:<7} {:<30} {:<25} {}",
                        "ID", "Type", "Session Name", "Expires At", "Created"
                    );
                    println!("{}", "-".repeat(120));
                    for token in tokens {
                        println!(
                            "{:<37} {:<7} {:<30} {:<25} {}",
                            token.id,
                            token.token_type,
                            token.session_name.as_deref().unwrap_or("-"),
                            token.expires_at,
                            token.created
                        );
                    }
                }
                return Ok(());
            }
            commands::auth::AuthCommands::Profiles { profile_command } => {
                use commands::auth::ProfileCommands;
                match profile_command {
                    ProfileCommands::Switch { name } => {
                        auth::switch_profile(name)?;
                        println!("✓ Switched to profile '{}'", name);
                        return Ok(());
                    }
                    ProfileCommands::List => {
                        let profiles = auth::list_profiles()?;

                        if profiles.is_empty() {
                            println!("No profiles found.");
                        } else {
                            println!("Available Profiles:");
                            println!(
                                "{:<3} {:<20} {:<30} {}",
                                "", "Profile", "Username", "Created"
                            );
                            println!("{}", "-".repeat(80));
                            for (name, info, is_active) in profiles {
                                let marker = if is_active { "*" } else { " " };
                                println!(
                                    "{:<3} {:<20} {:<30} {}",
                                    marker, name, info.username, info.created_at
                                );
                            }
                            println!();
                            println!("* = active profile");
                        }
                        return Ok(());
                    }
                    ProfileCommands::Delete { name } => {
                        // Get the token before deleting the profile
                        if let Ok(Some(token)) = auth::load_token_for_profile(name) {
                            // Try to logout from the server (don't pass profile name to avoid double deletion)
                            match auth::logout(&token, None).await {
                                Ok(_) => println!("✓ Logged out from server"),
                                Err(e) => eprintln!("Warning: Failed to logout from server: {}", e),
                            }
                        }

                        auth::delete_profile(name)?;
                        println!("✓ Profile '{}' deleted", name);
                        return Ok(());
                    }
                }
            }
        },
        Some(Commands::Workspaces { workspace_command }) => {
            use commands::workspaces::WorkspaceCommands;
            match workspace_command {
                WorkspaceCommands::List => {
                    commands::workspaces::handle_list(&token).await?;
                }
                WorkspaceCommands::Create { name } => {
                    commands::workspaces::handle_create(&token, name).await?;
                }
                WorkspaceCommands::Rename { selector, new_name } => {
                    commands::workspaces::handle_rename(&token, selector, new_name).await?;
                }
                WorkspaceCommands::Delete { selector } => {
                    commands::workspaces::handle_delete(&token, selector).await?;
                }
            }
        }
        Some(Commands::Notebooks { notebook_command }) => {
            use commands::notebooks::NotebookCommands;
            match notebook_command {
                NotebookCommands::List { workspace } => {
                    commands::notebooks::handle_list(&token, workspace).await?;
                }
                NotebookCommands::Create { name, workspace } => {
                    commands::notebooks::handle_create(&token, name, workspace).await?;
                }
                NotebookCommands::Rename { selector, new_name } => {
                    commands::notebooks::handle_rename(&token, selector, new_name).await?;
                }
                NotebookCommands::Delete { selector } => {
                    commands::notebooks::handle_delete(&token, selector).await?;
                }
            }
        }
        Some(Commands::Sync { sync_command }) => {
            use commands::sync::SyncCommands;
            let token = match auth::load_token_with_override(cli.profile.as_deref())? {
                Some(t) => t,
                None => {
                    eprintln!("Error: No authentication token found. Please login first.");
                    std::process::exit(1);
                }
            };
            match sync_command {
                SyncCommands::Workspace {
                    workspace,
                    path,
                    force,
                    remote_only,
                    keep_orphans,
                    rename_files,
                } => {
                    commands::sync::handle_workspace(
                        &token,
                        workspace,
                        path,
                        *force,
                        remote_only,
                        *keep_orphans,
                        *rename_files,
                    )
                    .await?;
                }
                SyncCommands::Notebook {
                    selector,
                    path,
                    force,
                    remote_only,
                    keep_orphans,
                    rename_files,
                } => {
                    commands::sync::handle_notebook(
                        &token,
                        selector,
                        path,
                        *force,
                        remote_only,
                        *keep_orphans,
                        *rename_files,
                    )
                    .await?;
                }
            }
        }
        Some(Commands::Notes { notes_command }) => {
            use commands::notes::NotesCommands;
            match notes_command {
                NotesCommands::List { selector } => {
                    commands::notes::handle_list(&token, selector).await?;
                }
                NotesCommands::Save {
                    selector,
                    notebook_id,
                    output,
                } => {
                    commands::notes::handle_save(&token, selector, notebook_id.clone(), output)
                        .await?;
                }
                NotesCommands::Update {
                    selector,
                    input,
                    notebook_id,
                } => {
                    commands::notes::handle_update(&token, selector, input, notebook_id.clone())
                        .await?;
                }
                NotesCommands::Create { input, notebook } => {
                    commands::notes::handle_create(&token, input, notebook).await?;
                }
                NotesCommands::Trash {
                    selector,
                    notebook_id,
                } => {
                    commands::notes::handle_trash(&token, selector, notebook_id.clone()).await?;
                }
                NotesCommands::Untrash {
                    selector,
                    notebook_id,
                } => {
                    commands::notes::handle_untrash(&token, selector, notebook_id.clone()).await?;
                }
                NotesCommands::Publish {
                    selector,
                    notebook_id,
                } => {
                    commands::notes::handle_publish(&token, selector, notebook_id.clone()).await?;
                }
                NotesCommands::Unpublish {
                    selector,
                    notebook_id,
                } => {
                    commands::notes::handle_unpublish(&token, selector, notebook_id.clone())
                        .await?;
                }
                NotesCommands::Favorite {
                    selector,
                    notebook_id,
                } => {
                    commands::notes::handle_favorite(&token, selector, notebook_id.clone()).await?;
                }
                NotesCommands::Unfavorite {
                    selector,
                    notebook_id,
                } => {
                    commands::notes::handle_unfavorite(&token, selector, notebook_id.clone())
                        .await?;
                }
                NotesCommands::Delete {
                    selector,
                    notebook_id,
                } => {
                    commands::notes::handle_delete(&token, selector, notebook_id.clone()).await?;
                }
            }
        }
        Some(Commands::Admin { admin_command }) => {
            // Check if user is admin
            if !auth::is_admin_token(&token) {
                eprintln!("❌ Error: Admin privileges required for this command.");
                eprintln!("   Only users with admin role can execute admin commands.");
                std::process::exit(1);
            }

            use commands::admin::AdminCommands;
            match admin_command {
                AdminCommands::Users { user_command } => {
                    use commands::admin::UserCommands;
                    match user_command {
                        UserCommands::List => {
                            commands::admin::handle_users_list(&token).await?;
                        }
                        UserCommands::Delete { selector } => {
                            commands::admin::handle_users_delete(&token, selector).await?;
                        }
                        UserCommands::Block { selector, reason } => {
                            commands::admin::handle_users_block(&token, selector, reason).await?;
                        }
                        UserCommands::Unblock { selector } => {
                            commands::admin::handle_users_unblock(&token, selector).await?;
                        }
                        UserCommands::Logout { selector } => {
                            commands::admin::handle_users_logout(&token, selector).await?;
                        }
                    }
                }
                AdminCommands::Stats => {
                    commands::admin::handle_stats(&token).await?;
                }
            }
        }
        Some(Commands::Version) => {
            banner::print_version_info();
            return Ok(());
        }
        None => {
            // Check for updates asynchronously
            version_check::check_for_updates().await;

            println!("Available commands:");
            println!("  auth login [--profile <NAME>]                       - Login (with optional profile, defaults to 'default')");
            println!(
                "  auth logout                                          - Logout and revoke token"
            );
            println!("  auth list                                            - List active authentication tokens");
            println!("  auth profiles list                                   - List all profiles");
            println!("  auth profiles switch <NAME>                          - Switch to a different profile");
            println!("  auth profiles delete <NAME>                          - Delete a profile");
            println!();
            println!(
                "  workspaces list                                      - List all workspaces"
            );
            println!(
                "  workspaces create <NAME>                             - Create a new workspace"
            );
            println!("  workspaces rename <SELECTOR> <NEW_NAME>              - Rename a workspace");
            println!("  workspaces delete <SELECTOR>                         - Delete a workspace");
            println!();
            println!("  notebooks list [WORKSPACE]                           - List notebooks (optionally filtered by workspace)");
            println!(
                "  notebooks create <NAME> -w <WORKSPACE>               - Create a new notebook"
            );
            println!("  notebooks rename <SELECTOR> <NEW_NAME>               - Rename a notebook");
            println!("  notebooks delete <SELECTOR>                          - Delete a notebook");
            println!();
            println!("  notes list [SELECTOR]                                - List notes (optionally filtered by workspace/notebook)");
            println!(
                "  notes save <SELECTOR> [-o <FILE>]                    - Save a note to a file"
            );
            println!(
                "  notes update <SELECTOR> [-i <FILE>]                  - Update an existing note"
            );
            println!("  notes create -i <FILE> -n <NOTEBOOK>                 - Create a new note");
            println!("  notes trash <SELECTOR>                               - Trash a note");
            println!("  notes untrash <SELECTOR>                             - Restore a note from trash");
            println!("  notes publish <SELECTOR>                             - Publish a note (make it public)");
            println!("  notes unpublish <SELECTOR>                           - Unpublish a note (make it private)");
            println!(
                "  notes favorite <SELECTOR>                            - Mark a note as favorite"
            );
            println!("  notes unfavorite <SELECTOR>                          - Remove a note from favorites");
            println!("  notes delete <SELECTOR>                              - Permanently delete a note");
            println!();
            println!("  sync workspace <SELECTOR> [-p <PATH>]                - Sync workspace notebooks & notes with local directory");
            println!("  sync notebook <SELECTOR> [-p <PATH>]                 - Sync notes with local directory");

            // Show admin commands if user is an admin
            if auth::is_admin_token(&token) {
                println!();
                println!("Admin commands:");
                println!("  admin stats                                          - Show system statistics");
                println!("  admin users list                                     - List all users");
                println!("  admin users delete <SELECTOR>                        - Delete a user");
                println!("  admin users block <SELECTOR> -r <REASON>             - Block a user");
                println!("  admin users unblock <SELECTOR>                       - Unblock a user");
                println!("  admin users logout <SELECTOR>                        - Logout user (revoke all tokens)");
            }

            println!();
            println!("Run 'doqium-cli --help' for more information.");
        }
    }

    Ok(())
}
