//! The `app` toolset: Create's operations (`app.guide`, `app.check`, `app.stream`,
//! `app.export`) through `wai-app`. A program streams into the person's open Create page
//! through the bridge this server runs on 127.0.0.1 (`wai_app::bridge`), which a page reads only
//! with the pairing code the bridge makes at start; an export is `wai create --from app.oui`'s,
//! inside the project directory.

use super::tools::str_arg;
use super::Server;
use serde_json::{json, Value};
use std::path::Path;

fn bridge_facts(server: &Server) -> Value {
    match &server.bridge {
        Some(b) => json!({"bridge": format!("http://127.0.0.1:{}", b.port), "code": b.code, "pages_connected": b.listening()}),
        None => json!({"bridge": null, "note": "this server runs no bridge (it was started read-only)"}),
    }
}

pub(crate) fn guide(server: &mut Server, _: &Value) -> Result<Value, String> {
    let mut v = json!({"guide": wai_app::guide::guide()});
    if let (Some(o), Value::Object(b)) = (v.as_object_mut(), bridge_facts(server)) {
        o.extend(b);
    }
    if let Some(b) = &server.bridge {
        v["connect"] = json!(format!(
            "In Create, choose \"Your coding agent\" and enter the bridge http://127.0.0.1:{} and the code {}.",
            b.port, b.code
        ));
    }
    Ok(v)
}

pub(crate) fn check(_: &mut Server, args: &Value) -> Result<Value, String> {
    let c = wai_app::check(str_arg(args, "program")?);
    let bad: Vec<String> = c.errors.iter().filter(|e| !e.warning).map(|e| format!("line {}: {}: {}", e.line, e.code, e.message)).collect();
    let mut v = serde_json::to_value(&c).map_err(|e| e.to_string())?;
    v["ok"] = json!(bad.is_empty() && c.room.is_some());
    v["problems"] = json!(bad);
    Ok(v)
}

pub(crate) fn stream(server: &mut Server, args: &Value) -> Result<Value, String> {
    let program = str_arg(args, "program")?;
    let b = server.bridge.as_ref().ok_or("this server runs no bridge (it was started read-only)")?;
    if b.listening() == 0 {
        return Err(format!(
            "No Create page is connected. Ask the person to open Create, choose \"Your coding agent\", and enter the bridge http://127.0.0.1:{} and the code {}.",
            b.port, b.code
        ));
    }
    let chunk = args.get("chunk").and_then(Value::as_u64).unwrap_or(24).clamp(1, 4096) as usize;
    let pace = args.get("pace_ms").and_then(Value::as_u64).unwrap_or(30).min(2000);
    let (chunks, delivered) = b.stream(program, chunk, pace);
    let c = wai_app::check(program);
    Ok(json!({"delivered": delivered, "chunks": chunks, "errors": c.errors}))
}

pub(crate) fn export(server: &mut Server, args: &Value) -> Result<Value, String> {
    let program = str_arg(args, "program")?;
    let dir = server.inside_project(Path::new(str_arg(args, "dir")?))?;
    let runtime = args.get("runtime_dir").and_then(Value::as_str).map(Path::new);
    let files = crate::dx::create::export_app(program, &dir, runtime)?;
    Ok(json!({"dir": dir.display().to_string(), "files": files, "next": "wai app check, then wai dev, in that directory"}))
}
