use sha2::{Digest, Sha256};
use std::path::PathBuf;

/// Compute UUID from file path using SHA256
/// UUID = SHA256(user_path + filename)[0:16]
pub fn compute_uuid(user_path: &str, filename: &str) -> String {
    let key = format!("{}/{}", user_path.trim_end_matches('/'), filename);
    let hash = Sha256::digest(key.as_bytes());
    let hash_str = hex::encode(hash);
    hash_str[0..16].to_string()
}

/// Compute UUID from full file path
pub fn compute_uuid_from_path(full_path: &str) -> String {
    let path = PathBuf::from(full_path);
    let parent = path
        .parent()
        .map(|p| p.to_string_lossy().to_string())
        .unwrap_or_default();
    let filename = path
        .file_name()
        .map(|n| n.to_string_lossy().to_string())
        .unwrap_or_default();

    compute_uuid(&parent, &filename)
}

/// Extract username and filepath from relative path
/// Input: ./demo/video.mp4 or ./demo/path/to/video.mp4
/// Returns: (username, filepath) e.g., ("demo", "video.mp4") or ("demo", "path/to/video.mp4")
pub fn extract_user_from_relative_path(relative_path: &str) -> (String, String) {
    // Remove leading ./
    let path = relative_path.strip_prefix("./").unwrap_or(relative_path);

    let path_buf = PathBuf::from(path);

    // First component is username
    let mut components = path_buf.components();
    let username = components
        .next()
        .map(|c| c.as_os_str().to_string_lossy().to_string())
        .unwrap_or_default();

    // Remaining path (filepath)
    let filepath: String = components
        .map(|c| c.as_os_str().to_string_lossy().to_string())
        .collect::<Vec<_>>()
        .join("/");

    (username, filepath)
}

/// Compute UUID from relative path (like ./demo/video.mp4)
/// The username is extracted from the first path component
pub fn compute_uuid_from_relative_path(relative_path: &str) -> String {
    let (username, filepath) = extract_user_from_relative_path(relative_path);
    compute_uuid(&username, &filepath)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_uuid_computation() {
        let uuid = compute_uuid("/Users/test/Videos", "video.mp4");
        assert_eq!(uuid.len(), 16);
        println!("UUID: {}", uuid);
    }

    #[test]
    fn test_uuid_from_path() {
        let uuid = compute_uuid_from_path("/Users/test/Videos/video.mp4");
        assert_eq!(uuid.len(), 16);
    }

    #[test]
    fn test_extract_user_from_relative_path() {
        let (username, filepath) = extract_user_from_relative_path("./demo/video.mp4");
        assert_eq!(username, "demo");
        assert_eq!(filepath, "video.mp4");

        let (username, filepath) = extract_user_from_relative_path("./demo/path/to/video.mp4");
        assert_eq!(username, "demo");
        assert_eq!(filepath, "path/to/video.mp4");
    }

    #[test]
    fn test_uuid_from_relative_path() {
        let uuid1 = compute_uuid_from_relative_path("./demo/video.mp4");
        let uuid2 = compute_uuid_from_relative_path("./demo/video.mp4");
        assert_eq!(uuid1, uuid2);
        assert_eq!(uuid1.len(), 16);

        // Different users with same filename should have different UUIDs
        let uuid_demo = compute_uuid_from_relative_path("./demo/video.mp4");
        let uuid_warren = compute_uuid_from_relative_path("./warren/video.mp4");
        assert_ne!(uuid_demo, uuid_warren);
    }
}
