# Copyright (c) 2022, JINGROW
# See license.txt

from unittest.mock import Mock, patch

import jingrow
from jingrow.tests.utils import JingrowTestCase

from jcloud.jcloud.pagetype.app.test_app import create_test_app
from jcloud.jcloud.pagetype.invoice.invoice import Invoice
from jcloud.jcloud.pagetype.marketplace_app.test_marketplace_app import (
	create_test_marketplace_app,
)
from jcloud.jcloud.pagetype.payout_order.payout_order import (
	create_marketplace_payout_orders_monthly,
	create_payout_order_from_invoice_items,
)
from jcloud.jcloud.pagetype.team.test_team import create_test_team


@patch.object(Invoice, "create_invoice_on_jingrowio", new=Mock())
class TestPayoutOrder(JingrowTestCase):
	def tearDown(self):
		jingrow.db.rollback()

	def test_net_amount_calculations_cny(self):
		self.create_test_cny_invoice()
		# Create a PO for this period
		today = jingrow.utils.today()
		period_start = jingrow.utils.data.get_first_day(today)
		period_end = jingrow.utils.data.get_last_day(today)

		po = create_payout_order_from_invoice_items(
			self.test_invoice.items,
			self.test_team.name,
			period_start=period_start,
			period_end=period_end,
			mode_of_payment="Internal",
			save=True,
		)

		self.assertEqual(len(po.items), 1)
		self.assertEqual(po.items[0].invoice, self.test_invoice.name)
		self.assertEqual(po.items[0].total_amount, 40.0)
		self.assertEqual(po.items[0].net_amount, 40.0)
		self.assertEqual(po.items[0].currency, "CNY")

		self.assertEqual(po.net_total_cny, 40.0)
		self.assertEqual(po.net_total_usd, 0)

	def test_net_amount_calculations_usd(self):
		self.create_test_usd_invoice()

		# Create a PO for this period
		today = jingrow.utils.today()
		period_start = jingrow.utils.data.get_first_day(today)
		period_end = jingrow.utils.data.get_last_day(today)

		po = create_payout_order_from_invoice_items(
			self.test_invoice.items,
			self.test_team.name,
			period_start=period_start,
			period_end=period_end,
			mode_of_payment="Internal",
			save=True,
		)

		self.assertEqual(len(po.items), 1)
		self.assertEqual(po.items[0].invoice, self.test_invoice.name)
		self.assertEqual(po.items[0].total_amount, 20.0)

		self.assertEqual(po.items[0].net_amount, 20.0)
		self.assertEqual(po.items[0].currency, "USD")

		self.assertEqual(po.net_total_cny, 0)
		self.assertEqual(po.net_total_usd, 20.0)

	def create_test_cny_invoice(self):
		self.test_team = create_test_team()

		self.test_invoice = jingrow.get_pg(
			pagetype="Invoice",
			team=self.test_team.name,
			transaction_amount=1000,
			transaction_fee=200,
			amount_paid=1000,
			status="Paid",
		).insert()

		# create test marketplace app
		test_app = create_test_app("test_app")
		test_mp_app = create_test_marketplace_app(test_app.name, self.test_team.name)

		self.test_invoice.append(
			"items",
			{
				"document_type": "Marketplace App",
				"document_name": test_mp_app.name,
				"rate": 20,
				"plan": "CNY 100",
				"quantity": 2,
			},
		)

		self.test_invoice.save()
		self.test_invoice.submit()

	def create_test_usd_invoice(self):
		self.test_team = create_test_team(country="United States")

		self.test_invoice = jingrow.get_pg(
			pagetype="Invoice",
			team=self.test_team.name,
			transaction_amount=1800,
			transaction_fee=1260,
			amount_paid=25,
			status="Paid",
			exchange_rate=70,
		).insert()

		# create test marketplace app
		test_app = create_test_app("test_app")
		test_mp_app = create_test_marketplace_app(test_app.name, self.test_team.name)

		self.test_invoice.append(
			"items",
			{
				"document_type": "Marketplace App",
				"document_name": test_mp_app.name,
				"rate": 10,
				"plan": "USD 25",
				"quantity": 2,
			},
		)

		self.test_invoice.save()
		self.test_invoice.submit()

	def test_create_marketplace_monthly_payout_order(self):
		self.create_test_usd_invoice()

		# No payout order before running the job
		self.assertFalse(jingrow.db.exists("Payout Order", {"team": self.test_team.name}))

		# Run the monthly job
		create_marketplace_payout_orders_monthly()

		# The Payout Order should have been created
		self.assertTrue(jingrow.db.exists("Payout Order", {"team": self.test_team.name}))

		po = jingrow.get_pg("Payout Order", {"team": self.test_team.name})
		self.assertEqual(len(po.items), 1)

		# The invoice item must be marked as paid out
		marked_completed = jingrow.db.get_value(
			"Invoice Item", po.items[0].invoice_item, "has_marketplace_payout_completed"
		)
		self.assertTrue(marked_completed)

		# Re-run should not create a new PO
		# Since all items are already accounted for
		create_marketplace_payout_orders_monthly()
		po_count = jingrow.db.count("Payout Order", {"team": self.test_team.name})
		self.assertEqual(po_count, 1)

	def test_does_not_create_duplicate_monthly_payout_order(self):
		self.create_test_usd_invoice()

		# Create a PO for this period
		today = jingrow.utils.today()
		period_start = jingrow.utils.data.get_first_day(today)
		period_end = jingrow.utils.data.get_last_day(today)

		# No POs initially
		num_payout_orders = jingrow.db.count("Payout Order", {"team": self.test_team.name})
		self.assertEqual(num_payout_orders, 0)

		po = create_payout_order_from_invoice_items(
			[], self.test_team.name, period_start=period_start, period_end=period_end
		)

		create_marketplace_payout_orders_monthly()

		num_payout_orders = jingrow.db.count("Payout Order", {"team": self.test_team.name})
		self.assertEqual(num_payout_orders, 1)

		# The original PO must now contain the invoice item
		po.reload()
		self.assertEqual(len(po.items), 1)

		# The item should be the one in the invoice
		# The invoice item must be marked as paid out
		marked_completed = jingrow.db.get_value(
			"Invoice Item", po.items[0].invoice_item, "has_marketplace_payout_completed"
		)
		self.assertTrue(marked_completed)
