// Taking payments with Adyen: a session for Drop-in, a card payment with its result read, one
// refused, one that goes through 3-D Secure, a capture and a refund, and notifications checked.
//
//   ADYEN_API_KEY=... ADYEN_MERCHANT_ACCOUNT=... ADYEN_HMAC_KEY=... quillo run adyen.qwe
//   then open /session, /pay, /three-ds, /modify, /amounts, /notification-check and /failures
//
// ADYEN_API_URL is https://checkout-test.adyen.com/v71 unless set. Point a Standard webhook at
// POST /adyen/webhook, with HMAC signing on.

use "adyen.qwer"

route GET /session {
    let s = adyen_session(adyen_amount("11.30", "EUR")?, "order-1001", "https://shop.example/back", { countryCode: "NL" })?
    { id: s.id, data: s.sessionData != null, status: adyen_session_result(s.id, "res-completed")?.status, missing: adyen_session(adyen_amount("1", "EUR")?, "", "https://x", {}).error }
}

route GET /pay {
    let card = { type: "scheme", encryptedCardNumber: "test_4111111111111111", encryptedSecurityCode: "test_737" }
    let paid = adyen_payment(adyen_amount("25", "EUR")?, "order-1002", card, { returnUrl: "https://shop.example/back" })?
    let refused = adyen_payment(adyen_amount("25", "EUR")?, "order-1003", { type: "scheme", encryptedCardNumber: "test_declined" }, {})?
    { paid: [paid.resultCode, paid.outcome, paid.pspReference != null], refused: [refused.resultCode, refused.outcome, refused.refusalReason] }
}

route GET /three-ds {
    let card = { type: "scheme", encryptedCardNumber: "test_3ds" }
    let step = adyen_payment(adyen_amount("30", "EUR")?, "order-1004", card, { returnUrl: "https://shop.example/back" })?
    let done = adyen_payment_details({ redirectResult: step.action.url })?
    { first: [step.resultCode, step.outcome], last: [done.resultCode, done.outcome], stale: adyen_payment_details({ redirectResult: "old" }).error }
}

route GET /modify {
    let paid = adyen_payment(adyen_amount("50", "EUR")?, "order-1005", { type: "scheme", encryptedCardNumber: "test_4111111111111111" }, {})?
    let psp = paid.pspReference
    let cap = adyen_capture(psp, adyen_amount("50", "EUR")?, "cap-1", "cap-key-1")?
    let again = adyen_capture(psp, adyen_amount("50", "EUR")?, "cap-1", "cap-key-1")?
    let back = adyen_refund(psp, adyen_amount("20", "EUR")?, "ref-1", "")?
    let other = adyen_payment(adyen_amount("9", "EUR")?, "order-1006", { type: "scheme", encryptedCardNumber: "test_4111111111111111" }, {})?
    {
        capture: cap.status,
        same: cap.pspReference == again.pspReference,
        refund: back.status,
        original: back.paymentPspReference == psp,
        cancel: adyen_cancel(other.pspReference, "c-1", "")?.status,
        reverse: adyen_reverse(psp, "rev-1", "")?.status,
        too_much: adyen_refund(psp, adyen_amount("2000", "EUR")?, "ref-2", "").error,
    }
}

route GET /amounts = {
    euros: adyen_amount("11.30", "eur")?,
    rupiah: adyen_amount("15000", "IDR")?,
    pesos: adyen_amount("990.50", "CLP")?,
    dinars: adyen_amount("1.250", "KWD")?,
    text: [adyen_amount_text({ currency: "KWD", value: 1250 })?, adyen_amount_text({ currency: "JPY", value: 500 })?, adyen_amount_text({ currency: "EUR", value: 5 })?],
    too_fine: adyen_amount("1.5", "IDR").error,
}

route POST /adyen/webhook {
    let hook = adyen_webhook(request.body, env("ADYEN_HMAC_KEY", ""))
    if is_err(hook) { reply 401 hook.error }
    // Adyen wants these exact words, and keeps trying until it gets them.
    "[accepted]"
}

// The sample in Adyen's "Verify HMAC signatures": its key, its payload and its signature.
let key = "44782DEF547AAA06C910C43932B1EB0C71FC68D9D0C057550C48EC2ACF6BA056"
let signed = "{\"live\":\"false\",\"notificationItems\":[{\"NotificationRequestItem\":{\"additionalData\":{\"hmacSignature\":\"coqCmt/IZ4E3CzPvMY8zTjQVL5hYJUiBRg8UU+iCWo0=\"},\"amount\":{\"currency\":\"EUR\",\"value\":1130},\"pspReference\":\"7914073381342284\",\"eventCode\":\"AUTHORISATION\",\"merchantAccountCode\":\"TestMerchant\",\"merchantReference\":\"TestPayment-1407325143704\",\"success\":\"true\"}}]}"

route GET /notification-check {
    let hook = adyen_webhook(signed, key)?
    {
        event: hook.items[0].eventCode,
        success: hook.items[0].success,
        live: hook.live,
        text: adyen_signing_text({ pspReference: "7914073381342284", merchantAccountCode: "TestMerchant", merchantReference: "TestPayment-1407325143704", amount: { value: 1130, currency: "EUR" }, eventCode: "AUTHORISATION", success: "true" }),
        changed: adyen_webhook(replace(signed, "1130", "9130"), key).error,
        other_key: adyen_webhook(signed, "00" + slice(key, 2)).error,
        short: adyen_webhook(replace(signed, "coqCmt/IZ4E3CzPvMY8zTjQVL5hYJUiBRg8UU+iCWo0=", "AAAA"), key).error,
        unsigned: adyen_webhook("{\"notificationItems\":[{\"NotificationRequestItem\":{\"additionalData\":{}}}]}", key).error,
        bad_key: adyen_webhook(signed, "not hex").error,
    }
}

route GET /failures = {
    bad_method: adyen_payment(adyen_amount("1", "EUR")?, "x", { type: "nosuch" }, {}).error,
    no_type: adyen_payment(adyen_amount("1", "EUR")?, "x", {}, {}).error,
    missing: adyen_capture("NOSUCH", adyen_amount("1", "EUR")?, "x", "").error,
    waited: adyen_payment(adyen_amount("3", "EUR")?, "busy", { type: "scheme", encryptedCardNumber: "test_4111111111111111" }, { idempotency_key: "busy-1" })?.outcome,
    amount: adyen_session({ value: "1" }, "x", "y", {}).error,
}
