use std::{
    env, fs,
    path::{Path, PathBuf},
};

use proc_macro2::Span;
use syn::Error;

/// Folder within a project that holds bundled WIT files
const BUNDLED_WIT_DEPS_DIR: &str = "bundled-miden-wit";

/// The prefix for the folder within a project that holds autogenerated WIT files
const GENERATED_WIT_DIR: &str = "generated-wit";

fn target_folder() -> PathBuf {
    let mut manifest_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not set");
    manifest_dir.push_str("/target/");
    PathBuf::from(manifest_dir)
}

pub fn bundled_wit_folder() -> Result<PathBuf, Error> {
    let out_dir = target_folder();
    let wit_deps_dir = out_dir.join(BUNDLED_WIT_DEPS_DIR);
    fs::create_dir_all(&wit_deps_dir).map_err(|err| {
        Error::new(
            Span::call_site(),
            format!(
                "failed to create WIT dependencies directory '{}': {err}",
                wit_deps_dir.display()
            ),
        )
    })?;
    Ok(wit_deps_dir)
}

pub fn generated_wit_folder() -> Result<PathBuf, Error> {
    let out_dir = target_folder();
    let wit_deps_dir = out_dir.join(GENERATED_WIT_DIR);
    fs::create_dir_all(&wit_deps_dir).map_err(|err| {
        Error::new(
            Span::call_site(),
            format!(
                "failed to create WIT dependencies directory '{}': {err}",
                wit_deps_dir.display()
            ),
        )
    })?;
    Ok(wit_deps_dir)
}

pub fn generated_wit_folder_at(manifest_dir: &Path) -> Result<PathBuf, String> {
    let out_dir = { manifest_dir.join("target/") };
    let wit_deps_dir = out_dir.join(GENERATED_WIT_DIR);
    fs::create_dir_all(&wit_deps_dir).map_err(|err| {
        format!(
            "failed to create WIT dependencies directory '{}': {err}",
            wit_deps_dir.display()
        )
    })?;
    Ok(wit_deps_dir)
}

/// Strips line comments starting with `//` from the provided source line.
///
/// Returns the portion of the line before the comment, or the entire line if no comment exists.
///
/// **Note:** This is a simple heuristic that doesn't account for `//` appearing
/// inside string literals. Only use for WIT source parsing where this is not an issue.
pub fn strip_line_comment(line: &str) -> &str {
    match line.split_once("//") {
        Some((before, _)) => before,
        None => line,
    }
}
