use std::path::PathBuf;

pub fn get_config_path(cli_override: Option<&str>) -> PathBuf {
    if let Some(path) = cli_override {
        return PathBuf::from(path);
    }

    if let Ok(path) = std::env::var("LORE_CONFIG_PATH") {
        return PathBuf::from(path);
    }

    let xdg_path = get_xdg_config_dir().join("lore").join("config.json");
    if xdg_path.exists() {
        return xdg_path;
    }

    let local_path = PathBuf::from("lore.config.json");
    if local_path.exists() {
        return local_path;
    }

    xdg_path
}

pub fn get_data_dir() -> PathBuf {
    get_xdg_data_dir().join("lore")
}

pub fn get_db_path(config_override: Option<&str>) -> PathBuf {
    if let Some(path) = config_override {
        return PathBuf::from(path);
    }
    get_data_dir().join("lore.db")
}

pub fn get_log_dir(config_override: Option<&str>) -> PathBuf {
    if let Some(path) = config_override {
        return PathBuf::from(path);
    }
    get_data_dir().join("logs")
}

pub fn get_cursor_path(username: &str) -> PathBuf {
    let safe_username: String = username
        .chars()
        .map(|ch| {
            if ch.is_ascii_alphanumeric() || matches!(ch, '_' | '-' | '.') {
                ch
            } else {
                '_'
            }
        })
        .collect();
    get_data_dir().join(format!("me_cursor_{safe_username}.json"))
}

pub fn get_backup_dir(config_override: Option<&str>) -> PathBuf {
    if let Some(path) = config_override {
        return PathBuf::from(path);
    }
    get_data_dir().join("backups")
}

fn get_xdg_config_dir() -> PathBuf {
    std::env::var("XDG_CONFIG_HOME")
        .map(PathBuf::from)
        .unwrap_or_else(|_| {
            dirs::home_dir()
                .unwrap_or_else(|| PathBuf::from("."))
                .join(".config")
        })
}

fn get_xdg_data_dir() -> PathBuf {
    std::env::var("XDG_DATA_HOME")
        .map(PathBuf::from)
        .unwrap_or_else(|_| {
            dirs::home_dir()
                .unwrap_or_else(|| PathBuf::from("."))
                .join(".local")
                .join("share")
        })
}

/// Enforce restrictive permissions (0600) on the config file.
/// Warns to stderr if permissions were too open, then tightens them.
#[cfg(unix)]
pub fn ensure_config_permissions(path: &std::path::Path) {
    use std::os::unix::fs::MetadataExt;

    let Ok(meta) = std::fs::metadata(path) else {
        return;
    };
    let mode = meta.mode() & 0o777;
    if mode != 0o600 {
        eprintln!(
            "Warning: config file permissions were {mode:04o}, tightening to 0600: {}",
            path.display()
        );
        let _ = set_permissions_600(path);
    }
}

#[cfg(unix)]
fn set_permissions_600(path: &std::path::Path) -> std::io::Result<()> {
    use std::os::unix::fs::PermissionsExt;
    let perms = std::fs::Permissions::from_mode(0o600);
    std::fs::set_permissions(path, perms)
}

/// No-op on non-Unix platforms.
#[cfg(not(unix))]
pub fn ensure_config_permissions(_path: &std::path::Path) {}

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

    #[test]
    fn test_cli_override_takes_precedence() {
        let path = get_config_path(Some("/custom/path.json"));
        assert_eq!(path, PathBuf::from("/custom/path.json"));
    }
}
