use sable_vault::Note;
use tera::Context;

use crate::{IntoDiagnostic as _, Renderer, RendererError};

impl Renderer {
    /// Render all notes using [`tera`] and write then to the destination folder.
    pub fn render_notes(&self) {
        let vault = self.vault.read();

        for note in vault.notes.values() {
            tracing::debug!(path=%note.path.full, "rendering vault note");

            if note.properties.draft == Some(true) {
                continue;
            }

            if let Err(err) = self.render_note(note).into_diagnostic() {
                tracing::error!(path=%note.path.full, "failed to render vault note");
                eprint!("{err:?}");
            }

            tracing::debug!(path=%note.path.full, "rendered vault note");
        }
    }

    fn render_note(&self, note: &Note) -> Result<(), RendererError> {
        let dest_path = self
            .config
            .build
            .join(note.path.slug.with_extension("html"));

        if let Some(dir) = dest_path.parent() {
            std::fs::create_dir_all(dir).map_err(RendererError::CreateDir)?;
        }

        let template = note.template().unwrap_or("default");
        let template = format!("{template}.html");

        let mut ctx = Context::new();

        ctx.insert("meta", &self.meta_info);
        if let Some(data) = self.config.data.as_ref() {
            ctx.insert("data", data);
        }

        ctx.insert("note", &note.as_context());

        let rendered = self
            .templates
            .render(&template, &ctx)
            .map_err(RendererError::RenderTemplate)?;

        std::fs::write(dest_path, rendered).map_err(RendererError::WriteTemplate)?;

        Ok(())
    }
}
