use chrono::NaiveDate;
use rmcp::model::ErrorCode;
use schemars::JsonSchema;
use serde::Deserialize;
use crate::models::NotePeriod;
use crate::vault::Vault;
fn parse_date(date_str: &str) -> Result<NaiveDate, rmcp::ErrorData> {
NaiveDate::parse_from_str(date_str, "%Y-%m-%d").map_err(|_| {
rmcp::ErrorData::new(
ErrorCode::INVALID_PARAMS,
format!("Invalid date '{date_str}'; expected YYYY-MM-DD"),
None,
)
})
}
#[derive(Deserialize, JsonSchema, Default)]
pub struct PeriodicGetParams {
pub period: NotePeriod,
#[serde(default)]
pub date: Option<String>,
}
pub async fn periodic_get(
vault: &Vault,
params: PeriodicGetParams,
) -> Result<String, rmcp::ErrorData> {
let date = params.date.map(|s| parse_date(&s)).transpose()?;
Ok(vault.get_periodic_note(¶ms.period, date)?)
}
#[derive(Deserialize, JsonSchema, Default)]
pub struct PeriodicCreateParams {
pub period: NotePeriod,
#[serde(default)]
pub date: Option<String>,
#[serde(default)]
pub content: Option<String>,
}
pub async fn periodic_create(
vault: &Vault,
params: PeriodicCreateParams,
) -> Result<String, rmcp::ErrorData> {
let date = params.date.map(|s| parse_date(&s)).transpose()?;
let path = vault.create_periodic_note(¶ms.period, date, params.content.as_deref())?;
Ok(format!("Created: {}", path.display()))
}
#[derive(Deserialize, JsonSchema, Default)]
pub struct PeriodicListRecentParams {
pub period: NotePeriod,
#[serde(default)]
pub limit: Option<usize>,
}
pub async fn periodic_list_recent(
vault: &Vault,
params: PeriodicListRecentParams,
) -> Result<String, rmcp::ErrorData> {
let limit = params.limit.unwrap_or(10);
let paths = vault.list_recent_periodic_notes(¶ms.period, limit)?;
let items: Vec<serde_json::Value> = paths
.into_iter()
.map(|p| {
let date = p
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or_default()
.to_string();
serde_json::json!({ "path": p.to_string_lossy(), "date": date })
})
.collect();
serde_json::to_string_pretty(&items)
.map_err(|e| rmcp::ErrorData::new(ErrorCode::INTERNAL_ERROR, e.to_string(), None))
}