Documentation
use crate::config::{AppConfig, SyncBackend};
use anyhow::{Context, Result};
use tokio::process::Command;

#[derive(Debug, Clone)]
pub struct SyncResult {
    pub backend: String,
    pub message: String,
}

pub async fn sync_once(cfg: &AppConfig) -> Result<SyncResult> {
    match cfg.sync.backend {
        SyncBackend::None => Ok(SyncResult {
            backend: "none".to_string(),
            message: "sync backend is none; no-op".to_string(),
        }),
        SyncBackend::Obsidian => sync_obsidian(cfg).await,
    }
}

async fn sync_obsidian(cfg: &AppConfig) -> Result<SyncResult> {
    let output = Command::new("ob")
        .args(["sync", "--path", &cfg.vault_path])
        .output()
        .await
        .context("failed to execute 'ob sync'")?;

    let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
    let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();

    if !output.status.success() {
        let mut message = String::from("ob sync failed");
        if !stderr.is_empty() {
            message.push_str(": ");
            message.push_str(&stderr);
        }
        if !stdout.is_empty() {
            message.push('\n');
            message.push_str(&stdout);
        }
        anyhow::bail!(message);
    }

    let message = if stdout.is_empty() {
        "ob sync ok".to_string()
    } else {
        stdout
    };

    Ok(SyncResult {
        backend: "obsidian".to_string(),
        message,
    })
}