use anyhow::{Context, Result};
use serde_json::Value;
use std::fs;
use std::path::Path;

pub fn read_json(path: &Path) -> Result<Value> {
    let raw = fs::read_to_string(path)
        .with_context(|| format!("failed to read json: {}", path.display()))?;
    let value: Value =
        serde_json::from_str(&raw).with_context(|| format!("invalid json: {}", path.display()))?;
    Ok(value)
}

pub fn string_at(value: &Value, path: &[&str]) -> Option<String> {
    let mut cursor = value;
    for key in path {
        cursor = cursor.get(*key)?;
    }
    cursor.as_str().map(strip_newlines)
}

pub fn i64_at(value: &Value, path: &[&str]) -> Option<i64> {
    let mut cursor = value;
    for key in path {
        cursor = cursor.get(*key)?;
    }
    match cursor {
        Value::Number(value) => value.as_i64(),
        Value::String(value) => value.trim().parse::<i64>().ok(),
        _ => None,
    }
}

pub fn strip_newlines(raw: &str) -> String {
    raw.split(&['\n', '\r'][..])
        .next()
        .unwrap_or("")
        .to_string()
}
