Documentation
use anyhow::{anyhow, bail, Result};
use dialoguer::Confirm;
use std::path::{Path, PathBuf};

use super::types::PathKind;

pub fn parse_size(input: &str) -> Result<u64> {
    let s = input.trim();
    if s.is_empty() {
        bail!("size is empty");
    }

    let (num_str, unit) = s.split_at(s.len().saturating_sub(1));
    let (value, multiplier) = match unit.to_ascii_lowercase().as_str() {
        "k" => (num_str, 1024u64),
        "m" => (num_str, 1024u64 * 1024),
        "g" => (num_str, 1024u64 * 1024 * 1024),
        _ => (s, 1u64),
    };

    let num: u64 = value
        .parse()
        .map_err(|_| anyhow!("invalid size: {input}"))?;
    Ok(num.saturating_mul(multiplier))
}

pub fn parse_u64_any(input: &str) -> Result<u64> {
    let s = input.trim();
    if let Some(hex) = s.strip_prefix("0x") {
        u64::from_str_radix(hex, 16).map_err(|_| anyhow!("invalid hex: {input}"))
    } else {
        s.parse::<u64>().map_err(|_| anyhow!("invalid number: {input}"))
    }
}

pub fn align_up(value: u64, align: u64) -> u64 {
    if align == 0 {
        return value;
    }
    value.div_ceil(align) * align
}

pub fn confirm_or_yes(yes: bool, prompt: &str) -> Result<()> {
    if yes {
        return Ok(());
    }
    let confirmed = Confirm::new()
        .with_prompt(prompt)
        .default(false)
        .interact()
        .map_err(|e| anyhow!("prompt failed: {e}"))?;
    if confirmed {
        Ok(())
    } else {
        bail!("aborted by user")
    }
}

pub fn path_kind(path: &str) -> PathKind {
    if path.starts_with("host:") {
        PathKind::Host
    } else {
        PathKind::Image
    }
}

pub fn host_path(path: &str) -> Result<PathBuf> {
    let p = path
        .strip_prefix("host:")
        .ok_or_else(|| anyhow!("host path required"))?;
    Ok(PathBuf::from(p))
}

pub fn normalize_image_path(path: &str) -> String {
    if path.starts_with('/') {
        path.to_string()
    } else {
        format!("/{}", path)
    }
}

pub fn iter_path_components(path: &str) -> Vec<String> {
    let clean = normalize_image_path(path);
    let mut cur = String::new();
    let mut out = Vec::new();
    for part in clean.split('/') {
        if part.is_empty() {
            continue;
        }
        cur.push('/');
        cur.push_str(part);
        out.push(cur.clone());
    }
    out
}

pub fn format_fat_label(label: &str) -> Result<[u8; 11]> {
    let mut out = [b' '; 11];
    let upper = label.trim().to_ascii_uppercase();
    if upper.is_empty() {
        return Ok(out);
    }
    if upper.len() > 11 {
        bail!("FAT label too long (max 11 chars)");
    }
    for (i, b) in upper.bytes().enumerate() {
        out[i] = b;
    }
    Ok(out)
}

pub fn remove_host_path(path: &Path) -> Result<()> {
    if path.is_dir() {
        std::fs::remove_dir_all(path)?;
    } else {
        std::fs::remove_file(path)?;
    }
    Ok(())
}