//! xmodel-render — projects master/spec.md into rendered/json.md and rendered/ail.md.

use anyhow::{anyhow, Context, Result};
use std::path::{Path, PathBuf};

use xmodel_render::splitter::{self, Segment};
use xmodel_render::examples;

fn main() -> Result<()> {
    let (master_dir, rendered_dir) = parse_args()?;
    let spec_path = master_dir.join("spec.md");
    let examples_dir = master_dir.join("examples");
    let spec_text = std::fs::read_to_string(&spec_path)
        .with_context(|| format!("reading {}", spec_path.display()))?;
    let segments = splitter::split(&spec_text);

    let json_out = render_for(&segments, &examples_dir, examples::Form::Json, splitter::Form::Json)?;
    let ail_out = render_for(&segments, &examples_dir, examples::Form::Ail, splitter::Form::Ail)?;

    std::fs::create_dir_all(&rendered_dir)
        .with_context(|| format!("creating {}", rendered_dir.display()))?;
    let json_path = rendered_dir.join("json.md");
    let ail_path = rendered_dir.join("ail.md");
    std::fs::write(&json_path, json_out)
        .with_context(|| format!("writing {}", json_path.display()))?;
    std::fs::write(&ail_path, ail_out)
        .with_context(|| format!("writing {}", ail_path.display()))?;
    eprintln!("xmodel-render: wrote {} and {}", json_path.display(), ail_path.display());
    Ok(())
}

fn render_for(
    segments: &[Segment],
    examples_dir: &Path,
    example_form: examples::Form,
    keep_form: splitter::Form,
) -> Result<String> {
    let mut out = String::new();
    for seg in segments {
        match seg {
            Segment::Prose(text) => out.push_str(text),
            Segment::FormOnly { form, body } if *form == keep_form => out.push_str(body),
            Segment::FormOnly { .. } => {} // drop the other form's block
            Segment::Example(id) => {
                let rendered = examples::render_example(examples_dir, id, example_form)?;
                out.push_str(&rendered);
            }
        }
    }
    Ok(out)
}

fn parse_args() -> Result<(PathBuf, PathBuf)> {
    let mut master: Option<PathBuf> = None;
    let mut rendered: Option<PathBuf> = None;
    let mut args = std::env::args().skip(1);
    while let Some(arg) = args.next() {
        match arg.as_str() {
            "--master" => master = Some(PathBuf::from(args.next().ok_or_else(|| anyhow!("--master needs a value"))?)),
            "--rendered" => rendered = Some(PathBuf::from(args.next().ok_or_else(|| anyhow!("--rendered needs a value"))?)),
            other => return Err(anyhow!("unknown argument: {}", other)),
        }
    }
    let master = master.ok_or_else(|| anyhow!("--master <dir> is required"))?;
    let rendered = rendered.ok_or_else(|| anyhow!("--rendered <dir> is required"))?;
    Ok((master, rendered))
}
