// A bot on Matrix: log in, join a room, post a message and a notice, then read what came in with
// /sync and page back through the history.
//
//   MATRIX_API_URL=https://matrix.org MATRIX_USER=bot MATRIX_PASSWORD=... quillo run matrix_chat.qwe
//   then open http://localhost:8080/login, /send, /sync, /history and /failures
//
// With an access token already, set MATRIX_ACCESS_TOKEN and leave out the password.

use "matrix_chat.qwer"

let ALIAS = "#ops:example.org"

fn sign_in() {
    let login = matrix_login(env("MATRIX_USER", ""), env("MATRIX_PASSWORD", ""), { device_name: "quillo bot" })?
    { token: login.access_token }
}

route GET /login {
    let s = sign_in()
    { whoami: matrix_whoami(s)?.user_id }
}

route GET /send {
    let s = sign_in()
    let room = matrix_join(ALIAS, s)?
    {
        room: room,
        resolved: matrix_resolve(ALIAS, s)? == room,
        text: matrix_send(room, "Deploy finished", s)?,
        html: matrix_send(room, "Deploy *finished*", { ...s, html: "Deploy <b>finished</b>" })?,
        notice: matrix_notice(room, "Nightly backup done", s)?,
        kept_once: same_txn(room, s),
    }
}

// The same transaction id sent twice is one event: a retry after a timeout cannot post twice.
fn same_txn(room, s) {
    let o = { ...s, txn_id: "retry-1" }
    matrix_send(room, "Once only", o)? == matrix_send(room, "Once only", o)?
}

route GET /sync {
    let s = sign_in()
    let room = matrix_join(ALIAS, s)?
    let first = matrix_sync("", 0, { ...s, limit: 10 })?
    matrix_send(room, "ping", s)?
    let next = matrix_sync(first.next_batch, 1000, s)?
    { first: map(first.events, (e) => e.body), invited: first.invited, next: map(next.events, (e) => e.body), kind: next.events[0].msgtype }
}

route GET /history {
    let s = sign_in()
    let room = matrix_join(ALIAS, s)?
    let one = matrix_messages(room, "", 2, s)?
    let two = matrix_messages(room, one.end, 2, s)?
    { newest: map(one.events, (e) => e.body), older: map(two.events, (e) => e.body), last_page_end: two.end }
}

route GET /failures {
    let s = sign_in()
    {
        wrong_password: matrix_login("bot", "wrong", {}).error,
        expired: matrix_whoami({ token: "old" }).error,
        no_room: matrix_send("!nowhere:example.org", "Hi", s).error,
        alias_as_id: matrix_send("#ops:example.org", "Hi", s).error,
        unknown_alias: matrix_resolve("#none:example.org", s).error,
        waited: matrix_send(matrix_join(ALIAS, s)?, "limit me", s)? != "",
    }
}
