use clap::Parser;
use std::path::PathBuf;

#[derive(Parser, Debug, Clone)]
#[command(name = "pumlv", about = "PlantUML diagram viewer in the browser")]
pub struct Config {
    /// Root directory to serve .puml files from (overrides first positional path)
    #[arg(long, env = "PUMLV_ROOT")]
    pub root: Option<PathBuf>,

    /// HTTP listen port
    #[arg(long, env = "PUMLV_PORT", default_value = "8080")]
    pub port: u16,

    /// Path to plantuml.jar
    #[arg(long, env = "PLANTUML_JAR", default_value = "/opt/plantuml.jar")]
    pub plantuml_jar: PathBuf,

    /// Files or directories to serve; first directory (or file parent) becomes root
    pub paths: Vec<PathBuf>,
}

impl Config {
    /// Resolve the effective root directory.
    pub fn resolve_root(&self) -> PathBuf {
        if let Some(ref r) = self.root {
            return r.clone();
        }
        for p in &self.paths {
            if p.is_dir() {
                return p.clone();
            }
            if p.is_file() {
                if let Some(parent) = p.parent() {
                    return parent.to_path_buf();
                }
            }
        }
        std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."))
    }

    /// Return the first explicitly named file, if any (used to pre-select on load).
    pub fn initial_file(&self, root: &std::path::Path) -> Option<String> {
        for p in &self.paths {
            if p.is_file() {
                if let Ok(rel) = p.strip_prefix(root) {
                    return Some(rel.to_string_lossy().into_owned());
                }
                // file outside root: just use the filename
                if let Some(name) = p.file_name() {
                    return Some(name.to_string_lossy().into_owned());
                }
            }
        }
        None
    }
}

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

    fn dir_config(dir: &TempDir) -> Config {
        Config {
            root: None,
            port: 8080,
            plantuml_jar: PathBuf::from("/opt/plantuml.jar"),
            paths: vec![dir.path().to_path_buf()],
        }
    }

    #[test]
    fn resolve_root_uses_explicit_root() {
        let dir = TempDir::new().unwrap();
        let cfg = Config {
            root: Some(dir.path().to_path_buf()),
            port: 8080,
            plantuml_jar: PathBuf::from("/opt/plantuml.jar"),
            paths: vec![],
        };
        assert_eq!(cfg.resolve_root(), dir.path());
    }

    #[test]
    fn resolve_root_uses_first_directory_arg() {
        let dir = TempDir::new().unwrap();
        let cfg = dir_config(&dir);
        assert_eq!(cfg.resolve_root(), dir.path());
    }

    #[test]
    fn resolve_root_uses_file_parent() {
        let dir = TempDir::new().unwrap();
        let file = dir.path().join("a.puml");
        std::fs::write(&file, "").unwrap();
        let cfg = Config {
            root: None,
            port: 8080,
            plantuml_jar: PathBuf::from("/opt/plantuml.jar"),
            paths: vec![file],
        };
        assert_eq!(cfg.resolve_root(), dir.path());
    }

    #[test]
    fn initial_file_returns_relative_path() {
        let dir = TempDir::new().unwrap();
        let file = dir.path().join("diagram.puml");
        std::fs::write(&file, "").unwrap();
        let cfg = Config {
            root: None,
            port: 8080,
            plantuml_jar: PathBuf::from("/opt/plantuml.jar"),
            paths: vec![file],
        };
        let root = cfg.resolve_root();
        assert_eq!(cfg.initial_file(&root).as_deref(), Some("diagram.puml"));
    }
}
