// A shop's checkout through Stripe: a Checkout session for the cart, a PaymentIntent for the
// custom payment page, and the webhook that marks orders paid.
//
//   STRIPE_SECRET_KEY=sk_test_... STRIPE_WEBHOOK_SECRET=whsec_... quillo run stripe.qwe
//   then open http://localhost:8080/checkout
//
// STRIPE_API_URL (SINK_URL in tests, or stripe-mock) points it at another server.

use "stripe.qwer"

let CART = [{ name: "Kettle 1.7 L", price: "39.90", qty: 1 }, { name: "Tea, 100 g", price: "6.50", qty: 2 }]
let WEBHOOK_SECRET = env("STRIPE_WEBHOOK_SECRET", "whsec_test_quillo")
let STRIPE = { base_url: env("STRIPE_API_URL", null) ?? env("SINK_URL", null) }

fn line_items(cart) = cart | map((l) => {
    quantity: l.qty,
    price_data: { currency: "eur", unit_amount: stripe_amount(l.price, "eur")?, product_data: { name: l.name } },
})

route GET /checkout {
    let s = stripe_checkout({
        line_items: line_items(CART),
        success_url: "https://shop.example.com/thanks?session={CHECKOUT_SESSION_ID}",
        cancel_url: "https://shop.example.com/cart",
        metadata: { order: "A-1042" },
    }, { ...STRIPE, idempotency_key: "order-A-1042" })?
    if !s.ok { reply 502 s.error }
    { sent: true, status: s.status }
}

route GET /intent = stripe_payment_intent(stripe_amount("52.90", "eur")?, "eur", { metadata: { order: "A-1042" } }, { ...STRIPE, idempotency_key: "pi-A-1042" })?

// How the cart travels, and amounts in each currency's minor units.
route GET /form = {
    encoded: stripe_form({ mode: "payment", line_items: line_items(CART) }),
    eur: stripe_amount("19.99", "EUR")?,
    jpy: stripe_amount("1500", "JPY")?,
    kwd: stripe_amount("1.250", "KWD")?,
    too_precise: stripe_amount("10.5", "JPY").error,
}

route POST /stripe/webhook {
    let event = stripe_event(request.body, request.headers["stripe-signature"] ?? "", WEBHOOK_SECRET, 300)
    if is_err(event) { reply 400 event.error }
    if event.type == "checkout.session.completed" { print("paid:", event.data.object.metadata.order) }
    { received: event.type }
}

// A signed event as Stripe would send it, checked as the webhook checks it.
route GET /event {
    let body = json.stringify({ id: "evt_1", type: "checkout.session.completed", data: { object: { metadata: { order: "A-1042" } } } })
    let t = int(now() / 1000)
    let header = `t=${t},v1=${crypto.hmac(WEBHOOK_SECRET, `${t}.${body}`)}`
    {
        event: stripe_event(body, header, WEBHOOK_SECRET, 300)?.type,
        tampered: stripe_event(replace(body, "A-1042", "A-9999"), header, WEBHOOK_SECRET, 300).error,
    }
}
