//! Cross-platform renderer discovery without CLR assembly loading.

use std::path::Path;

use crate::Error;
use crate::rendering::IRendering;

const BUILTIN_SIMPLE: &str = "builtin:simple";

pub(crate) fn list_renderers(path: &str) -> Result<Vec<String>, Error> {
    let directory = Path::new(path);
    if !directory.is_dir() {
        return Err(Error::Argument);
    }
    let mut renderers = vec![BUILTIN_SIMPLE.to_owned()];
    let entries = std::fs::read_dir(directory).map_err(|_| Error::Argument)?;
    for entry in entries {
        let entry = entry.map_err(|_| Error::Argument)?;
        let file_type = entry.file_type().map_err(|_| Error::Argument)?;
        if !file_type.is_file() {
            continue;
        }
        let name = entry.file_name();
        let name = name.to_string_lossy().to_ascii_lowercase();
        if is_simple_artifact(&name) {
            renderers.push(entry.path().to_string_lossy().into_owned());
        }
    }
    renderers.sort();
    renderers.dedup();
    Ok(renderers)
}

pub(crate) fn load_renderer(filename: &str) -> Result<Box<dyn IRendering>, Error> {
    let normalized = Path::new(filename)
        .file_name()
        .and_then(|name| name.to_str())
        .unwrap_or(filename)
        .to_ascii_lowercase();
    if filename.eq_ignore_ascii_case(BUILTIN_SIMPLE)
        || filename.eq_ignore_ascii_case("simple")
        || filename.eq_ignore_ascii_case("LibreMetaverse.Rendering.Simple")
        || is_simple_artifact(&normalized)
    {
        return Ok(Box::new(
            crate::builtin_simple_renderer::SimpleRenderer::native_new()?,
        ));
    }
    Err(Error::Rendering {
        source: libremetaverse_types::UUID::zero(),
        context: "unknown or unsupported renderer",
    })
}

fn is_simple_artifact(name: &str) -> bool {
    name.contains("libremetaverse_rendering_simple")
        || name.contains("libremetaverse-rendering-simple")
        || name.contains("libremetaverse.rendering.simple")
}

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

    #[test]
    fn built_in_renderer_is_discoverable_and_constructible() {
        let renderers = list_renderers(env!("CARGO_MANIFEST_DIR")).unwrap();
        assert!(renderers.iter().any(|name| name == BUILTIN_SIMPLE));
        let renderer = load_renderer(BUILTIN_SIMPLE).unwrap();
        let mut vertices = Vec::new();
        renderer
            .transform_tex_coords(
                &mut vertices,
                libremetaverse_types::Vector3::zero(),
                crate::PrimitiveTextureEntryFace::new(None).unwrap(),
                libremetaverse_types::Vector3::one(),
            )
            .unwrap();
    }

    #[test]
    fn discovery_recognizes_platform_artifact_names() {
        assert!(is_simple_artifact("liblibremetaverse_rendering_simple.so"));
        assert!(is_simple_artifact("libremetaverse_rendering_simple.dll"));
        assert!(is_simple_artifact(
            "liblibremetaverse_rendering_simple.dylib"
        ));
    }
}
