use clap::Parser;
use std::path::PathBuf;
use std::process::Command;
use axum::{Extension, Router, routing::any};
use tokio::net::TcpListener;
use dav_server::{DavHandler, localfs::LocalFs, fakels::FakeLs};

#[derive(Parser)]
struct Args {
    #[arg(short, long, default_value = "4932")]
    port: u16,
    
    #[arg(long, default_value = "data/raid_simple.sparseimage")]
    vdisk_path: PathBuf,
    
    #[arg(long, default_value = "RAID_AUTO")]
    mount_name: String,
}

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 (Auto-Mount) ===");
    println!("Port: {}", args.port);
    println!("VDisk: {}", args.vdisk_path.display());
    println!("Mount Name: {}", args.mount_name);
    println!("");
    
    if !args.vdisk_path.exists() {
        eprintln!("Error: Virtual disk not found at {}", args.vdisk_path.display());
        return;
    }
    
    println!("Step 1: Check if already mounted...");
    let mount_point = check_or_mount(&args.vdisk_path, &args.mount_name);
    
    println!("Step 2: Verify mount point...");
    if !mount_point.exists() {
        eprintln!("Error: Mount point does not exist: {}", mount_point.display());
        return;
    }
    
    println!("✅ Mounted at: {}", mount_point.display());
    println!("");
    
    println!("Step 3: Starting WebDAV server...");
    let dav = DavHandler::builder()
        .filesystem(LocalFs::new(mount_point.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!("  Guest/Guest or blank password");
    println!("");
    println!("Press Ctrl+C to stop...");
    
    axum::serve(listener, router).await.unwrap();
}

fn check_or_mount(vdisk_path: &PathBuf, mount_name: &str) -> PathBuf {
    let expected_mount = PathBuf::from("/Volumes").join(mount_name);
    
    if expected_mount.exists() {
        println!("✅ Already mounted at: {}", expected_mount.display());
        return expected_mount;
    }
    
    println!("Mounting sparseimage...");
    let output = Command::new("hdiutil")
        .args(&["attach", "-nobrowse"])
        .arg(vdisk_path)
        .output()
        .expect("Failed to mount sparseimage");
    
    if !output.status.success() {
        eprintln!("Mount failed: {}", String::from_utf8_lossy(&output.stderr));
        return expected_mount;
    }
    
    println!("Mount output: {}", String::from_utf8_lossy(&output.stdout));
    
    let mount_output = String::from_utf8_lossy(&output.stdout);
    for line in mount_output.lines() {
        if line.contains("/Volumes/") {
            let parts: Vec<&str> = line.split_whitespace().collect();
            if let Some(mount_path) = parts.last() {
                println!("✅ Mounted at: {}", mount_path);
                return PathBuf::from(mount_path);
            }
        }
    }
    
    expected_mount
}

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