use clap::Parser;
use std::path::PathBuf;
use axum::{Extension, Router, routing::any};
use tokio::net::TcpListener;
use dav_server::{DavHandler, localfs::LocalFs, fakels::FakeLs};
use markbase::raid::{RaidController, RaidLevel, RaidExporter};

#[derive(Parser)]
struct Args {
    #[arg(short, long, default_value = "4925")]
    port: u16,
    
    #[arg(long, default_value = "raid0")]
    raid_level: String,
    
    #[arg(long, default_value = "3")]
    num_disks: usize,
    
    #[arg(long, default_value = "5")]
    disk_size_gb: u64,
}

fn main() {
    tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .build()
        .unwrap()
        .block_on(async_main());
}

async fn async_main() {
    let args = Args::parse();
    
    println!("=== RAID WebDAV Server ===");
    println!("RAID Level: {}", args.raid_level);
    println!("Number of disks: {}", args.num_disks);
    println!("Disk size: {}GB each", args.disk_size_gb);
    println!("Port: {}", args.port);
    println!("");
    
    let controller = RaidController::new();
    
    println!("Creating RAID test disks...");
    let disk_paths = create_test_disks(args.num_disks, args.disk_size_gb);
    
    let raid_level = match args.raid_level.as_str() {
        "raid0" => RaidLevel::RAID0,
        "raid1" => RaidLevel::RAID1,
        "raid5" => RaidLevel::RAID5,
        _ => RaidLevel::RAID0,
    };
    
    println!("Creating RAID array...");
    let array_id = controller.create_array(
        raid_level,
        disk_paths.clone(),
        64 * 1024,
    ).unwrap();
    
    println!("✅ RAID array created: {}", array_id);
    
    println!("Exporting RAID to virtual disk...");
    let exporter = RaidExporter::new(controller);
    let vdisk_path = PathBuf::from("data/raid_export.vdisk");
    
    std::fs::create_dir_all("data").ok();
    
    let exported_bytes = exporter.export_to_vdisk(&array_id, &vdisk_path, 1024 * 1024)?;
    println!("✅ Exported {} bytes to {}", exported_bytes, vdisk_path.display());
    
    println!("");
    println!("Starting WebDAV server...");
    
    let dav = DavHandler::builder()
        .filesystem(LocalFs::new(vdisk_path.to_string_lossy().to_string(), false, false, false))
        .locksystem(FakeLs::new())
        .strip_prefix("/webdav")
        .build_handler();
    
    let addr = format!("127.0.0.1:{}", args.port);
    let listener = TcpListener::bind(&addr).await.unwrap();
    
    let router = Router::new()
        .route("/webdav", any(handle_dav))
        .route("/webdav/", any(handle_dav))
        .route("/webdav/{*path}", any(handle_dav))
        .layer(Extension(dav));
    
    println!("Listening on: http://{}", addr);
    println!("Mount with Finder:");
    println!("  Cmd+K → http://localhost:{}/webdav", args.port);
    println!("");
    println!("Press Ctrl+C to stop...");
    
    axum::serve(listener, router).await.unwrap();
}

fn create_test_disks(num_disks: usize, size_gb: u64) -> Vec<PathBuf> {
    let mut paths = Vec::new();
    let base_dir = PathBuf::from("data/raid_test_disks");
    std::fs::create_dir_all(&base_dir).ok();
    
    for i in 0..num_disks {
        let disk_path = base_dir.join(format!("disk{}.sparseimage", i));
        
        if !disk_path.exists() {
            println!("Creating disk {} ({}GB)...", i, size_gb);
            std::process::Command::new("hdiutil")
                .args(&["create", "-size", &format!("{}g", size_gb), "-type", "SPARSE"])
                .arg(&disk_path)
                .output()
                .expect("Failed to create disk");
        }
        
        paths.push(disk_path);
    }
    
    paths
}

async fn handle_dav(Extension(dav): Extension<dav_server::DavHandler>, req: axum::extract::Request) -> impl axum::response::IntoResponse {
    dav.handle(req).await
}