// Work tracked in Asana: tasks made, changed, commented on and finished, lists past one page, and a
// webhook from its handshake on.
//
//   ASANA_ACCESS_TOKEN=... ASANA_WORKSPACE=... quillo run asana.qwe
//   then open /tasks, /lists, /webhook, /hook-check and /failures
//
// ASANA_API_URL reaches a test server. A webhook's target must be public; Asana calls it while the
// webhook is being made, and the route must echo X-Hook-Secret back.

use "asana.qwer"

let workspace = env("ASANA_WORKSPACE", "")

route GET /tasks {
    let me = asana_me()?
    let p = asana_project_create({ name: "Launch", workspace: workspace })?
    let t = asana_task_create({ name: "Write the guide", notes: "With examples", projects: [p.gid], due_on: "2026-12-01" })?
    asana_task_update(t.gid, { name: "Write the guide & the changelog" })?
    asana_comment(t.gid, "Half done")?
    let done = asana_task_complete(t.gid)?
    let few = asana_task(t.gid, ["name", "completed"])?
    {
        me: me.name, name: few.name, completed: done.completed, only_asked: contains(few, "notes"),
        comments: map(asana_comments(t.gid)?, (c) => c.text),
        in_project: map(asana_project_tasks(p.gid, {}, 0)?, (x) => x.gid == t.gid),
        no_home: asana_task_create({ name: "Lost" }).error,
        no_text: asana_comment(t.gid, " ").error,
        deleted: asana_task_delete(t.gid)?,
        gone: asana_task(t.gid, null).error,
    }
}

route GET /lists = {
    projects: len(asana_projects(workspace, { archived: false }, 0)?),
    capped: len(asana_projects(workspace, {}, 130)?),
    fields: asana_projects(workspace, { opt_fields: ["name", "color"] }, 1)?[0],
}

// Asana's handshake and its deliveries both land here.
route POST /asana/webhook {
    let got = asana_webhook_receive("tasks", request.headers, request.body)
    if is_err(got) { reply 401 got.error }
    if got.handshake { respond(200, "", { "x-hook-secret": got.secret }) } else { { seen: len(got.events) } }
}

// The webhook made for real: the stand-in calls this very server back while it is made, and then
// delivers an event signed with the secret that handshake gave.
route GET /webhook {
    let target = `http://${request.headers.host}/asana/webhook`
    let w = asana_webhook_create("tasks", "1200000000000001", target, [{ resource_type: "task", action: "changed" }])?
    { active: w.active, delivered: w.last_delivery, deleted: asana_webhook_delete(w.gid)? }
}

// A signature made outside this plugin, by node's crypto, and an imposter's second handshake.
route GET /hook-check {
    let body = "{\"events\":[{\"action\":\"changed\",\"resource\":{\"gid\":\"1\",\"resource_type\":\"task\"}}]}"
    let sig = "0f9bdbf886af2ccf15fb0e9db624e96fc013ac6fc954a86bc05f68174cc71efa"
    let first = asana_webhook_receive("check", { "x-hook-secret": "secret-one" }, "")?
    {
        handshake: first,
        good: asana_signature_valid(body, sig, "secret-one"),
        events: len(asana_webhook_receive("check", { "x-hook-signature": sig }, body)?.events),
        tampered: asana_webhook_receive("check", { "x-hook-signature": sig }, body + " ").error,
        imposter: asana_webhook_receive("check", { "x-hook-secret": "mine-now" }, "").error,
        unsigned: asana_webhook_receive("check", {}, body).error,
        unknown: asana_webhook_receive("other", { "x-hook-signature": sig }, body).error,
    }
}

route GET /failures = {
    missing: asana_project("999").error,
    expired: asana_projects("expired", {}, 0).error,
    waited: asana_project("busy")?.name,
    premium: asana_project("premium").error,
}
