#[allow(clippy::unwrap_used)]
#[cfg(test)]
mod tests {
    use std::convert::TryInto;

    use crate::eval::tests::eval_out_wo_ctx;
    use ergotree_ir::chain::address::AddressEncoder;
    use ergotree_ir::chain::address::NetworkPrefix;
    use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp;

    #[test]
    fn simplified_age_usd_bank_contract() {
        // simplified version of
        // https://github.com/Emurgo/age-usd/tree/main/ageusd-smart-contracts/v0.4
        /*

          val rcDefaultPrice = 1000000L

          val minStorageRent = 10000000L

          val feePercent = 1

          val HEIGHT = 377771

          val coolingOffHeight: Int = 377770
          val INF = 1000000000L

          val longMax = 9223372036854775807L

          val minReserveRatioPercent = 400L // percent
          val defaultMaxReserveRatioPercent = 800L // percent

            // val dataInput = CONTEXT.dataInputs(0)
            // val validDataInput = dataInput.tokens(0)._1 == oraclePoolNFT
            val validDataInput = true

            // val bankBoxIn = SELF
            // val bankBoxOut = OUTPUTS(0)

            // val rateBox = dataInput
            // val receiptBox = OUTPUTS(1)

            // val rate = rateBox.R4[Long].get / 100
            val rate = 100000000 / 100

            // val scCircIn = bankBoxIn.R4[Long].get
            val scCircIn = 100L
            // val rcCircIn = bankBoxIn.R5[Long].get
            val rcCircIn = 100L
            // val bcReserveIn = bankBoxIn.value
            val bcReserveIn = 100000000L

            // val scTokensIn = bankBoxIn.tokens(0)._2
            val scTokensIn = 100
            // val rcTokensIn = bankBoxIn.tokens(1)._2
            val rcTokensIn = 100

            // val scCircOut = bankBoxOut.R4[Long].get
            val scCircOut = 100
            // val rcCircOut = bankBoxOut.R5[Long].get
            val rcCircOut = 101

            // val scTokensOut = bankBoxOut.tokens(0)._2
            val scTokensOut = 100
            // val rcTokensOut = bankBoxOut.tokens(1)._2
            val rcTokensOut = 99

            val totalScIn = scTokensIn + scCircIn
            val totalScOut = scTokensOut + scCircOut

            val totalRcIn = rcTokensIn + rcCircIn
            val totalRcOut = rcTokensOut + rcCircOut

            val rcExchange = rcTokensIn != rcTokensOut
            val scExchange = scTokensIn != scTokensOut

            val rcExchangeXorScExchange = (rcExchange || scExchange) && !(rcExchange && scExchange)

            // val circDelta = receiptBox.R4[Long].get
            val circDelta = 1L
            // val bcReserveDelta = receiptBox.R5[Long].get
            val bcReserveDelta = 1010000L

            // val bcReserveOut = bankBoxOut.value
            val bcReserveOut = 100000000L + 1010000L

            val rcCircDelta = if (rcExchange) circDelta else 0L
            val scCircDelta = if (rcExchange) 0L else circDelta

            val validDeltas = (scCircIn + scCircDelta == scCircOut) &&
                              (rcCircIn + rcCircDelta == rcCircOut) &&
                              (bcReserveIn + bcReserveDelta == bcReserveOut)

            val coinsConserved = totalRcIn == totalRcOut && totalScIn == totalScOut

            // val tokenIdsConserved = bankBoxOut.tokens(0)._1 == bankBoxIn.tokens(0)._1 && // also ensures that at least one token exists
            //                         bankBoxOut.tokens(1)._1 == bankBoxIn.tokens(1)._1 && // also ensures that at least one token exists
            //                         bankBoxOut.tokens(2)._1 == bankBoxIn.tokens(2)._1    // also ensures that at least one token exists

            val tokenIdsConserved = true

            // val mandatoryRateConditions = rateBox.tokens(0)._1 == oraclePoolNFT
            val mandatoryRateConditions = true
            val mandatoryBankConditions = //bankBoxOut.value >= $minStorageRent &&
                                          rcExchangeXorScExchange &&
                                          coinsConserved &&
                                          validDeltas &&
                                          tokenIdsConserved

            // exchange equations
            val bcReserveNeededOut = scCircOut * rate
            val bcReserveNeededIn = scCircIn * rate
            val liabilitiesIn = max(min(bcReserveIn, bcReserveNeededIn), 0)


            val maxReserveRatioPercent = if (HEIGHT > coolingOffHeight) defaultMaxReserveRatioPercent else INF

            val reserveRatioPercentOut =
                if (bcReserveNeededOut == 0) maxReserveRatioPercent else bcReserveOut * 100 / bcReserveNeededOut

            val validReserveRatio = if (scExchange) {
              if (scCircDelta > 0) {
                reserveRatioPercentOut >= minReserveRatioPercent
              } else true
            } else {
              if (rcCircDelta > 0) {
                reserveRatioPercentOut <= maxReserveRatioPercent
              } else {
                reserveRatioPercentOut >= minReserveRatioPercent
              }
            }

            val brDeltaExpected = if (scExchange) { // sc
              val liableRate = if (scCircIn == 0) longMax else liabilitiesIn / scCircIn
              val scNominalPrice = min(rate, liableRate)
              scNominalPrice * scCircDelta
            } else { // rc
              val equityIn = bcReserveIn - liabilitiesIn
              val equityRate = if (rcCircIn == 0) rcDefaultPrice else equityIn / rcCircIn
              val rcNominalPrice = if (equityIn == 0) rcDefaultPrice else equityRate
              rcNominalPrice * rcCircDelta
            }

            val fee = brDeltaExpected * feePercent / 100

            val actualFee = if (fee < 0) {fee * -1} else fee
            // actualFee is always positive, irrespective of brDeltaExpected

            val brDeltaExpectedWithFee = brDeltaExpected + actualFee

            mandatoryRateConditions &&
            mandatoryBankConditions &&
            bcReserveDelta == brDeltaExpectedWithFee &&
            validReserveRatio &&
            validDataInput
        }
                 */
        let p2s_addr_str = "7Nq5tKsVYCgneNgEfA2BJKwGsWozezNLhCNsRBihcHVFkDTuTThd4Qt1bi7NfCK1HuuVfjksMrEftV6MEFajjuyp1TMD2PX7SYWvkg9zH4CtgpdoBjekCNXs5XawxXnW6FT7GCqXTpJUP2TkkuqBh1df99PTigehys36uZz9wQnkrJXrv3mw3Yy4CM622qe5wdqLtpEonjazEmsw8weqEYegDyfJnswDvDkLPXtcCB86i19jik4fnSTtCcYj3jpWCQ7WL5dZn1ivs5JGRsR2ioNCRiZd3Gu1zJBgbHkMg41Z6VeCRWXjGY99BUtgtQiepSHGHajFCVcFAHhVxccdVUPCxGeEL6c2dNx6qzEkVfTfHs5qBgJewR8KCZTCVTurNBHeqCSVdxnfFvhW3f72cNrae5E1UhTAXU2iX4LZMHQsKyefY24Aq1b1srTyRWLpixjbcezFqA2TKjGSn1p1ruxbR7AQpW24ByPKT9sFE9ii4qNeXDnLcGtAAGS9FC5SD1s516a4NCu6v9zZfTvRKGkCwt78J8DEVnhTbttjcsvqFsUXQrvAv7TGVsaT4mL6B7F5BhRoZwFkgRXqFUVCWvgqJrwwjFRtbc5aZz";
        let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
        let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
        let script = addr.script().unwrap().proposition().unwrap();
        // dbg!(&script);
        let res: bool = eval_out_wo_ctx::<SigmaProp>(&script).try_into().unwrap();
        assert!(res);
    }

    #[test]
    fn ageusd_bank_full() {
        // from eip-15 https://github.com/ergoplatform/eips/pull/27/files
        let p2s_addr_str = "MUbV38YgqHy7XbsoXWF5z7EZm524Ybdwe5p9WDrbhruZRtehkRPT92imXer2eTkjwPDfboa1pR3zb3deVKVq3H7Xt98qcTqLuSBSbHb7izzo5jphEpcnqyKJ2xhmpNPVvmtbdJNdvdopPrHHDBbAGGeW7XYTQwEeoRfosXzcDtiGgw97b2aqjTsNFmZk7khBEQywjYfmoDc9nUCJMZ3vbSspnYo3LarLe55mh2Np8MNJqUN9APA6XkhZCrTTDRZb1B4krgFY1sVMswg2ceqguZRvC9pqt3tUUxmSnB24N6dowfVJKhLXwHPbrkHViBv1AKAJTmEaQW2DN1fRmD9ypXxZk8GXmYtxTtrj3BiunQ4qzUCu1eGzxSREjpkFSi2ATLSSDqUwxtRz639sHM6Lav4axoJNPCHbY8pvuBKUxgnGRex8LEGM8DeEJwaJCaoy8dBw9Lz49nq5mSsXLeoC4xpTUmp47Bh7GAZtwkaNreCu74m9rcZ8Di4w1cmdsiK1NWuDh9pJ2Bv7u3EfcurHFVqCkT3P86JUbKnXeNxCypfrWsFuYNKYqmjsix82g9vWcGMmAcu5nagxD4iET86iE2tMMfZZ5vqZNvntQswJyQqv2Wc6MTh4jQx1q2qJZCQe4QdEK63meTGbZNNKMctHQbp3gRkZYNrBtxQyVtNLR8xEY8zGp85GeQKbb37vqLXxRpGiigAdMe3XZA4hhYPmAAU5hpSMYaRAjtvvMT3bNiHRACGrfjvSsEG9G2zY5in2YWz5X9zXQLGTYRsQ4uNFkYoQRCBdjNxGv6R58Xq74zCgt19TxYZ87gPWxkXpWwTaHogG1eps8WXt8QzwJ9rVx6Vu9a5GjtcGsQxHovWmYixgBU8X9fPNJ9UQhYyAWbjtRSuVBtDAmoV1gCBEPwnYVP5GCGhCocbwoYhZkZjFZy6ws4uxVLid3FxuvhWvQrVEDYp7WRvGXbNdCbcSXnbeTrPMey1WPaXX";
        let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
        let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
        let _script = addr.script().unwrap().proposition().unwrap();
        // dbg!(&script);
        // let res: bool = eval_out_wo_ctx::<SigmaProp>(script.as_ref())
        //     .try_into()
        //     .unwrap();
        // assert!(!res);
    }

    #[test]
    fn ageusd_update() {
        // from eip-15 https://github.com/ergoplatform/eips/pull/27/files
        let p2s_addr_str = "VLyjpv3dse3PbatT83GnDkBQasGqY52dAEdi9XpXhuSUn1FS1Tm7XxtAgmBiqY9pJXtEAsDKwX9ygSjrFu7vnUQZudhC2sSmxhxqgD3ZxJ2VsGwmPG77F6EiEZhcq71oqEq31y9XvCCXL5nqqszdENPAVhu7xT296qZ7w1x6hmwdh9ZE89bjfgbhfNYopoqsCaNLWYHJ12TDSY93kaGqCVKSu6gEF1gLpXBfRCnAPPxYswJPmK8oWDn8PKrUGs3MjVsj6bGXiW3VTGP4VsNH8YSSkjyj1FZ9azLsyfnNJ3zah2zUHdCCqY6PjH9JfHf9joCPf6TusvXgr71XWvh5e2HPEPQr4eJMD4S96cGTiSs3J5XcRd1tCDYoiis8nxv99zFFhHgpqXHgeqjhJ5sPot9eRYTsmm4cRTVLXYAiuKPS2qW5";
        let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
        let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
        let _script = addr.script().unwrap().proposition().unwrap();
        // dbg!(&script);
        // let res: bool = eval_out_wo_ctx::<SigmaProp>(script.as_ref())
        //     .try_into()
        //     .unwrap();
        // assert!(!res);
    }

    #[test]
    fn ageusd_ballot() {
        // from eip-15 https://github.com/ergoplatform/eips/pull/27/files
        let p2s_addr_str = "22ELWBHzyWGjPRE48ZJDfFmD24myYdG3vHz8CipSS7rgE65ABmEj9QJiy3rG2PTJeCaZw9VX56GY6uoA3hQch7i5BfFU3AprUWTABi4X1VWtRdK9yrYJkmN6fq8hGfvmWTrsyh4fXZoGETpLuXQViYo194ajej2h7dr3oqNATdMskSXzxJi83bFdAvQ";
        let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
        let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
        let _script = addr.script().unwrap().proposition().unwrap();
        // dbg!(&script);
        // let res: bool = eval_out_wo_ctx::<SigmaProp>(script.as_ref())
        //     .try_into()
        //     .unwrap();
        // assert!(!res);
    }

    #[test]
    fn amm_simple_pool() {
        // from eip-14 https://github.com/ergoplatform/eips/pull/27/files
        let p2s_addr_str = "k6fD5ht5e1itDejPFV2VzAoHv478KQCbDnLAL6XUVeEu8KDaboCVZAoFz2AtMoLqM3CgQfr2TZhpwz7K96AgwTXDvBVeTchJ31jjD46Di1W67H8wwFcivnY62UB6L7HWzCkbYuiZaAq2qSJta5Twt4A2Aaoy7xViWcyLUVNAyQYDJXKhVBAGwp76i2too5yWUmEU4zt9XnjJAUt1FFfurNtTNHNPDbqmTRE4crz347q6rfbvkMmg9Jtk9rSiPCQpKjdbZVzUnP4CUw6AvQH6rZXxgNMktAtjQdHhCnrCmf78FwCKqYS54asKd1MFgYNT4NzPwmdZF6JtQt1vvkjZXqpGkjy33xxDNYy8JZS8eeqVgZErPeJ1aj4aaK8gvmApUgGStMDFeFYjuQqZiZxEAHNdAXDg7hyGnmfzA6Hj9zcB7p9nKCDNhEQEMPL1kMG5aXvt2HUPXqiCkLrv596DaGmRMN3gMJaj1T1AfMYNwZozcJ9uUSK4i6Xham28HWAekTtDPhobnmjvkubwLVTtvUumWHtDWFxYSJPF7vqzgZqg6Y5unMF";
        let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
        let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
        assert!(addr.script().unwrap().proposition().is_ok());
        let _script = addr.script().unwrap().proposition().unwrap();
        // dbg!(&script);
        // let res: bool = eval_out_wo_ctx::<SigmaProp>(script.as_ref())
        //     .try_into()
        //     .unwrap();
        // assert!(!res);
    }

    #[test]
    fn amm_simple_swap() {
        // from eip-14 https://github.com/ergoplatform/eips/pull/27/files
        let p2s_addr_str = "cLPHJ3MHuKAHoCUwGhcEFw5sWJqvPwFyKxTRj1aUoMwgAz78Fg3zLXRhBup9Te1WLau1gZXNmXvUmeXGCd7QLeqB7ArrT3v5cg26piEtqymM6j2SkgYVCobgoAGKeTf6nMLxv1uVrLdjt1GnPxG1MuWj7Es7Dfumotbx9YEaxwqtTUC5SKsJc9LCpAmNWRAQbU6tVVEvmfwWivrGoZ3L5C4DMisxN3U";
        let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
        let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
        let _script = addr.script().unwrap().proposition().unwrap();
        // dbg!(&script);
        // let res: bool = eval_out_wo_ctx::<SigmaProp>(script.as_ref())
        //     .try_into()
        //     .unwrap();
        // assert!(!res);
    }

    #[test]
    fn amm_conc_pool_root() {
        // from eip-14 https://github.com/ergoplatform/eips/pull/27/files
        let p2s_addr_str = "3STRfQWC9Xb5wAxBiEQ74uTFSemk1oHn43mwj9tMCeu2a3A4kie1bY2qsCdRaEmdQoq3B4tXQuzq9nm84A8PmBgCzgGDEZf2pgYoAUc6krZxUY3rvKWW44ZpzN3u5bFRpKDo6rxKtxX2tw99xmfyfaVBejgDaTfsib2PSVsu9hrLQ3SouECWHQMjDA3Pi8ZuCvQeW8GDkZfHPr3SgwaxY1jpY2njsmf3JBASMoVZ6Mfpg63Q6mBno7mKUSCE7vNHHUZe2V7JEikwjPkaxSWxnwy3J17faGtiEHZLKiNQ9WNtsJLbdVp56dQGfC2zaiXjhx1XJK6m4Nh2M8yEvSuBzanRBAJqrNseGS97tk2iLqqfHrqqmmDsHY3mujCURky4SLr7YLk4B";
        let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
        let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
        let _script = addr.script().unwrap().proposition().unwrap();
        // dbg!(&script);
        // let res: bool = eval_out_wo_ctx::<SigmaProp>(script.as_ref())
        //     .try_into()
        //     .unwrap();
        // assert!(!res);
    }

    #[test]
    fn amm_conc_pool_boot() {
        // from eip-14 https://github.com/ergoplatform/eips/pull/27/files
        let p2s_addr_str = "6Mv73vd1MnJp6AQg5vHGP9nujFc3Y1PL5gzeUt9PzCaUiQug7ueQGU1bDkmFkCspq4LU8j3T8yY6UyJQKSfah5qEDzjx8QCJF47NBG5jxgPxmBHkM6cUgnYa5ngzn9jrpAn379UC7o5nugTg3HYWZGk3APMcRftkrC3EgroiVMEmSkDcDwaebkNWKfKe3JXgewoTrgZ2YLMafr3JfX47C1zddoWDhS8TWryQYEprkP334eisuh1Fr2iNTW9ruV6m38cRkfRfzSBHYq45mvNLH7JQo6uQZ4NFPx4t27Q5A3mSqCpk7ATThFcQmc2w3Pp2F6xL87c94gxk83G8UEqkAhmaNfoj19zji9rxqRzq9gJeTLBraHR2DchKtahH8HhFPg5DZ4SjwJ4MHqTDF";
        let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
        let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
        let _script = addr.script().unwrap().proposition().unwrap();
        // dbg!(&script);
        // let res: bool = eval_out_wo_ctx::<SigmaProp>(script.as_ref())
        //     .try_into()
        //     .unwrap();
        // assert!(!res);
    }

    #[test]
    fn amm_conc_pool() {
        // from eip-14 https://github.com/ergoplatform/eips/pull/27/files
        let p2s_addr_str = "AhCu1UkNT4c9q3B2Lb7gNgvZWCdXL8iYgmNxTYiy4S3wgKWFFW6kz9v7pvY8NqC7g4wgXXwzJY1fQVn2xrLkiyiQWsorq5dR7d5KnDAY43H4GvSVjaDciadXCSHCb8jgk8mFSQCwoZHweLmMJ25312wT85AySJgYUuzdUxMz4EnQpiwZR2XVZq3M81gycuqP9gUryryjN4J1cAF3yL3kZR3rREubBvJ2CY5hF74Xaj2jwajivkESkqq22ieWWG2sK7dk1A7KHr1MmiXGcUBAMMGPAu3mVCeFW9SongxP9hodnJThLknjWRBBBC6wq5jNkSdHrMbdaQM3XesXqGTk9KwWpnSL92E96muU2k8FQbo5isps1r5ciYVrFptfEAC3tWbwcVmRKtrgxtCex6bP5aBZYjaH6L9QQbkYriDAcQ1iZcpf3hHCqURjRXL7i72C3aGBwzzspQvhLof6x4f4gPxTCtF1bNUxddUL6DJ1PbQWzVH8taivjhHohis6sRn3Akvv4xaZRJdKZ8rDuiounRKNXi8VoNgVEZbSFYtfweRSdsiXJCkhtehLWdtFTk1eg7djASdBGKaguvtEBcGaAALVDUoH479VskPUQ6hrfS7KcWrATBdb8sf4W5MFpx7UNitzq2fzSKC96mQRUzy5uELe7Y7vexm5ArNEyr6ARkypZypSzJ2CEifjVxxRBEWVtbdqHrwP4gWv6cMdbqFWwuXAw2BZQnWpZFtKAGQ9m";
        let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
        let addr = encoder.parse_address_from_str(p2s_addr_str).unwrap();
        let _script = addr.script().unwrap().proposition().unwrap();
        // dbg!(&script);
        // let res: bool = eval_out_wo_ctx::<SigmaProp>(script.as_ref())
        //     .try_into()
        //     .unwrap();
        // assert!(!res);
    }

    #[test]
    fn eip_22_auction() {
        // from https://github.com/ergoplatform/eips/blob/adbe21512cadf51a2d9af8406cfd418f95335899/eip-0022.md
        let p2s_str = "GE68RH3VEgW6b4kN3GhYigrLxoXr9jMgMpmm3KnXJaYq1PzHieYhz7Uka86idxvBWLRLmpiA3HrxHPsX1jzQZEv5yaRDueiJqks1keM7iB1eYWMEVRUUq1MLFzdA1FHQwCfSakM3Uc8uBPqk2icxhoXvw1CVbUVtFCzcPrZzf8Jjf8gS5bCFpWQscHo14HTsdBxyV3dwL6wKu8LP8FuWJE7qCEgX9ToEiztH4ZLmFwBejnUFrCQqjLVLWpdgdnAXVyewiX9DxXKJKL4wNqhPUrYjmHEVvpZAezXjzfVMr7gKupTqAgx2AJYGh4winEDeYq9MVshX8xjJweGhbAm2RXN1euQpoepFaKqfrT2mQBTmr6edbbzYg6VJ7DoSCDzmcUupFAmZMjMiaUbgtyz2VEbPEKsmAFrZ6zdB5EUxhiYZMd6KdstsJwZCgKJSSCShTgpfqNLCdpR9JbZFQpA1uhUkuLMPvGi74V5EwijTEEtjmTVcWcVhJKv4GDr1Lqe2bMPq4jfEfqvemaY8FcrCsCSi2LZoQUeJ9VrBeotGTKccq8JhwnvNGhLUUrrm32v3bhU82jbtVBVFRD3FSv5hhS6pKHtTevjwuG7JWoR3LN7279A7zQGJWmkSWDoEhHjgxseqZ2G5bLB7ZVEzKM261QhwMwmXA1eWgq8zdBH1u9kFC9bMQ812q2DPZTuhzpBWJh74UGwaEgZLhnUrDKT58cEa4R3kfWyGCMoNw78q1E3a2eKDz8Va5wnixzT2SZFHU8DfHjPSz5rm8Mr3YxgRC6GzaasPDxTrZjuMJHU2exhqsoFvur7Q";

        let encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
        let addr = encoder.parse_address_from_str(p2s_str).unwrap();
        let _script = addr.script().unwrap().proposition().unwrap();
    }
}
