use crate::services::{notebooks_service, sync_service, workspaces_service};
use anyhow::Result;
use clap::Subcommand;
use std::path::Path;

#[derive(Subcommand)]
pub enum SyncCommands {
    /// Synchronize an entire workspace with a local directory
    Workspace {
        /// Workspace selector (slug or ID)
        #[arg(value_name = "WORKSPACE")]
        workspace: String,
        /// Local directory path (optional, defaults to current directory)
        #[arg(long = "path", short = 'p')]
        path: Option<String>,
        /// Skip all confirmations
        #[arg(long)]
        force: bool,
        /// How to handle remote-only notes: download, trash, delete, ignore
        #[arg(long, value_name = "ACTION")]
        remote_only: Option<String>,
        /// Don't delete local files with non-existent remote IDs
        #[arg(long)]
        keep_orphans: bool,
        /// Rename local files to match their slug
        #[arg(long)]
        rename_files: bool,
    },
    /// Synchronize a notebook with a local directory
    Notebook {
        /// Notebook selector (@notebook[workspace/notebook]) or notebook ID
        #[arg(value_name = "SELECTOR")]
        selector: String,
        /// Local directory path (optional, defaults to current directory)
        #[arg(long = "path", short = 'p')]
        path: Option<String>,
        /// Skip all confirmations
        #[arg(long)]
        force: bool,
        /// How to handle remote-only notes: download, trash, delete, ignore
        #[arg(long, value_name = "ACTION")]
        remote_only: Option<String>,
        /// Don't delete local files with non-existent remote IDs
        #[arg(long)]
        keep_orphans: bool,
        /// Rename local files to match their slug
        #[arg(long)]
        rename_files: bool,
    },
}

pub async fn handle_workspace(
    token: &str,
    workspace_selector: &str,
    path: &Option<String>,
    force: bool,
    remote_only: &Option<String>,
    keep_orphans: bool,
    rename_files: bool,
) -> Result<()> {
    let workspace_id = workspaces_service::resolve_workspace_id(token, workspace_selector).await?;
    let workspace = workspaces_service::get_workspace(token, &workspace_id).await?;

    let workspace_dir = if let Some(p) = path {
        Path::new(p).to_path_buf()
    } else {
        std::env::current_dir()?.join(&workspace.slug)
    };

    let options = sync_service::SyncOptions {
        force,
        remote_only: remote_only.clone(),
        keep_orphans,
        rename_files,
    };

    let result =
        sync_service::sync_workspace(token, &workspace_id, &workspace_dir, &options).await?;

    print_sync_result("Workspace sync", &result);

    Ok(())
}

pub async fn handle_notebook(
    token: &str,
    selector: &str,
    path: &Option<String>,
    force: bool,
    remote_only: &Option<String>,
    keep_orphans: bool,
    rename_files: bool,
) -> Result<()> {
    let notebook_id = notebooks_service::resolve_notebook_id(token, selector).await?;
    let notebook = notebooks_service::get_notebook(token, &notebook_id).await?;
    let workspace = workspaces_service::get_workspace(token, &notebook.workspace_id).await?;

    let local_path = if let Some(p) = path {
        Path::new(p).to_path_buf()
    } else {
        std::env::current_dir()?
    };

    println!(
        "Synchronizing notebook '{}/{}' to path: {}",
        workspace.slug,
        notebook.slug,
        local_path.display()
    );

    let options = sync_service::SyncOptions {
        force,
        remote_only: remote_only.clone(),
        keep_orphans,
        rename_files,
    };

    let result = sync_service::sync_notebook(token, &notebook_id, &local_path, &options).await?;

    print_sync_result("Sync", &result);

    Ok(())
}

fn print_sync_result(label: &str, result: &sync_service::SyncResult) {
    println!("\n{}", "=".repeat(60));
    println!("{} complete:", label);
    println!("  Downloaded: {}", result.downloaded);
    println!("  Uploaded: {}", result.uploaded);
    println!("  Skipped: {}", result.skipped);
    println!("  Deleted: {}", result.deleted);
    if result.conflicts > 0 {
        println!("  Conflicts: {}", result.conflicts);
    }
    println!("  Errors: {}", result.errors);
    println!("{}", "=".repeat(60));
}
