use baidu_netdisk_sdk::{BaiduNetDiskClient, PrecreateOptions};
use log::info;
use std::fs::File;
use std::io::{BufReader, Read};
use std::path::Path;

fn calculate_md5<P: AsRef<Path>>(path: P) -> Result<String, Box<dyn std::error::Error>> {
    let file = File::open(path)?;
    let mut reader = BufReader::new(file);
    let mut buffer = Vec::new();
    reader.read_to_end(&mut buffer)?;
    Ok(format!("{:x}", md5::compute(&buffer)))
}

fn get_file_md5blocks<P: AsRef<Path>>(
    path: P,
    chunk_size: usize,
) -> Result<(u64, Vec<String>), Box<dyn std::error::Error>> {
    let file = File::open(path)?;
    let metadata = file.metadata()?;
    let total_size = metadata.len() as u64;

    let mut reader = BufReader::new(file);
    let mut buffer = Vec::new();
    let mut block_list = Vec::new();

    loop {
        buffer.clear();
        let bytes_read = reader
            .by_ref()
            .take(chunk_size as u64)
            .read_to_end(&mut buffer)?;
        if bytes_read == 0 {
            break;
        }
        block_list.push(format!("{:x}", md5::compute(&buffer)));
    }

    Ok((total_size, block_list))
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("info")).init();

    let client = BaiduNetDiskClient::builder().build()?;
    info!("Client created successfully");

    client.load_token_from_env()?;
    info!("Token loaded successfully");

    let args: Vec<String> = std::env::args().collect();

    if args.len() < 3 {
        println!("Usage: {} <local_file> <remote_path>", args[0]);
        println!("Example: {} test.txt /apps/test/test.txt", args[0]);
        return Ok(());
    }

    let local_file = &args[1];
    let remote_path = &args[2];

    println!("=== Baidu NetDisk Preupload Test ===");
    println!("Local file: {}", local_file);
    println!("Remote path: {}", remote_path);
    println!();

    let (file_size, block_list) = get_file_md5blocks(local_file, 4 * 1024 * 1024)?;
    let file_md5 = calculate_md5(local_file)?;

    println!("File size: {} bytes", file_size);
    println!("File MD5: {}", file_md5);
    println!("Block count: {}", block_list.len());
    println!("Block list: {:?}", block_list);
    println!();

    let options = PrecreateOptions::new(remote_path, file_size, block_list)
        .content_md5(&file_md5)
        .rtype(1);

    println!("Sending precreate request...");
    match client.upload().precreate(options).await {
        Ok(response) => {
            println!("Precreate success!");
            println!("  Upload ID: {}", response.uploadid);
            println!("  Path: {:?}", response.path);
            println!("  Return type: {}", response.return_type);
            println!("  Block list to upload: {:?}", response.block_list);
        }
        Err(e) => {
            println!("Precreate failed: {}", e);
        }
    }

    Ok(())
}
