# frozen_string_literal: true

require "test_helper"
require "customer"
require "transaction"

Transaction::DB = Minitest::Mock.new
Transaction::BRAINTREE = Minitest::Mock.new
Transaction::REDIS = Minitest::Mock.new

class TransactionTest < Minitest::Test
	FAKE_BRAINTREE_TRANSACTION =
		OpenStruct.new(
			customer_details: OpenStruct.new(id: "customer"),
			id: "transaction",
			created_at: Time.at(0),
			amount: 12
		)

	def test_sale_fails
		Transaction::REDIS.expect(
			:get,
			EMPromise.resolve("1"),
			["jmp_pay_decline-test"]
		)
		Transaction::REDIS.expect(
			:incr,
			EMPromise.resolve(nil),
			["jmp_pay_decline-test"]
		)
		Transaction::REDIS.expect(
			:expire,
			EMPromise.resolve(nil),
			["jmp_pay_decline-test", 60 * 60 * 24]
		)
		braintree_transaction = Minitest::Mock.new
		Transaction::BRAINTREE.expect(:transaction, braintree_transaction)
		braintree_transaction.expect(
			:sale,
			EMPromise.resolve(
				OpenStruct.new(success?: false, message: "declined")
			),
			[Hash]
		)
		assert_raises("declined") do
			Transaction.sale(
				customer(plan_name: "test_usd"),
				amount: 123,
				payment_method: OpenStruct.new(token: "token")
			).sync
		end
	end
	em :test_sale_fails

	def test_sale
		Transaction::REDIS.expect(
			:get,
			EMPromise.resolve("1"),
			["jmp_pay_decline-test"]
		)
		braintree_transaction = Minitest::Mock.new
		Transaction::BRAINTREE.expect(:transaction, braintree_transaction)
		braintree_transaction.expect(
			:sale,
			EMPromise.resolve(
				OpenStruct.new(
					success?: true,
					transaction: FAKE_BRAINTREE_TRANSACTION
				)
			),
			[{
				amount: 123,
				payment_method_token: "token",
				merchant_account_id: "merchant_usd",
				options: { submit_for_settlement: true }
			}]
		)
		result = Transaction.sale(
			customer(plan_name: "test_usd"),
			amount: 123,
			payment_method: OpenStruct.new(token: "token")
		).sync
		assert_kind_of Transaction, result
	end
	em :test_sale

	def test_insert
		Transaction::DB.expect(:transaction, []) do |&block|
			block.call
			true
		end
		Transaction::DB.expect(
			:exec,
			EMPromise.resolve(nil),
			[
				String,
				["customer", "transaction", Time.at(0), 12]
			]
		)
		Transaction.new(FAKE_BRAINTREE_TRANSACTION).insert.sync
		Transaction::DB.verify
	end
	em :test_insert

	def test_insert_with_bonus
		Transaction::DB.expect(:transaction, []) do |&block|
			block.call
			true
		end
		Transaction::DB.expect(
			:exec,
			EMPromise.resolve(nil),
			[
				String,
				["customer", "transaction", Time.at(0), 100]
			]
		)
		Transaction::DB.expect(
			:exec,
			EMPromise.resolve(nil),
			[
				String,
				["customer", "bonus_for_transaction", Time.at(0), 3]
			]
		)
		tx = FAKE_BRAINTREE_TRANSACTION.dup
		tx.amount = 100
		Transaction.new(tx).insert.sync
		Transaction::DB.verify
	end
	em :test_insert_with_bonus
end
