from decimal import Decimal
from django.test import TestCase
from django.utils import timezone
from account.models import User
from shop_management.models.data.shop import Shop
from shop_management.models.data.utils import Currency, ExchangeRate
from shop_management.models.data.shop_account import Account
from shop_management.models.data.customer import Customer
from shop_management.models.data.product import Product
from shop_management.models.data.sale import Sale, SaleItem
from shop_management.serializers.data.customer_balance_payment import CustomerBalancePaymentSerializer


class MultiCurrencyCustomerPaymentTests(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(username="testuser", password="password")
        self.shop = Shop.objects.create(name="Test Shop", shop_id="SHOP1", owner=self.user, created_by=self.user)
        self.usd = Currency.objects.create(title="USD", shop=self.shop)
        self.afn = Currency.objects.create(title="Afghani", shop=self.shop)
        self.account_usd = Account.objects.create(
            name="USD Cash", shop=self.shop, currency=self.usd, opening_balance=Decimal("0")
        )
        ExchangeRate.objects.create(
            shop=self.shop,
            from_currency=self.usd,
            to_currency=self.afn,
            rate=Decimal("63.40"),
            rate_date=timezone.now().date(),
        )
        self.customer = Customer.objects.create(
            shop=self.shop,
            name="PK Demo",
            opening_balance=Decimal("1000.00"),
            opening_balance_currency=self.usd,
        )
        self.product = Product.objects.create(
            shop=self.shop,
            name="Test Product",
        )
        # USD Sale: 330.00 USD (amount is discount in legacy model, so discount=0)
        self.sale_usd = Sale.objects.create(
            shop=self.shop,
            customer=self.customer,
            currency=self.usd,
            amount=Decimal("0.00"),
            received_amount=Decimal("0.00"),
            sale_date=timezone.now().date(),
        )
        SaleItem.objects.create(
            sale=self.sale_usd,
            product=self.product,
            quantity=1,
            sale_price=Decimal("330.00"),
        )

        # AFN Sale: 17100.00 AFN
        self.sale_afn = Sale.objects.create(
            shop=self.shop,
            customer=self.customer,
            currency=self.afn,
            amount=Decimal("0.00"),
            received_amount=Decimal("0.00"),
            sale_date=timezone.now().date(),
        )
        SaleItem.objects.create(
            sale=self.sale_afn,
            product=self.product,
            quantity=1,
            sale_price=Decimal("17100.00"),
        )

    def test_payment_1900_usd_clears_usd_and_afn_and_creates_credit(self):
        owed_before = self.customer.get_total_owed_by_currency()
        self.assertEqual(owed_before, {"USD": 1330.0, "Afghani": 17100.0})
        self.assertEqual(self.customer.get_credit_by_currency(), {})

        data = {
            "customer": self.customer.id,
            "account": self.account_usd.id,
            "currency": self.usd.id,
            "settlement_currency": self.usd.id,
            "amount": Decimal("1900.00"),
            "discount": Decimal("0.00"),
            "exchange_rate": Decimal("1.0"),
            "settlement_exchange_rate": Decimal("1.0"),
            "apply_to_opening_balance": True,
            "payment_date": timezone.now(),
        }
        serializer = CustomerBalancePaymentSerializer(data=data)
        self.assertTrue(serializer.is_valid(), serializer.errors)
        payment = serializer.save()

        # Check payment record
        self.assertEqual(payment.unallocated_amount, Decimal("300.28"))
        self.assertIn("Cleared 17100.00 Afghani using 269.72 USD", payment.notes)
        self.assertIn("Credit: 300.28 USD", payment.notes)

        # Check USD sale
        self.sale_usd.refresh_from_db()
        self.assertEqual(self.sale_usd.received_amount, Decimal("330.00"))

        # Check AFN sale
        self.sale_afn.refresh_from_db()
        self.assertEqual(self.sale_afn.received_amount, Decimal("17100.00"))

        # Check customer opening balance
        self.customer.refresh_from_db()
        self.assertEqual(self.customer.opening_balance, Decimal("0.00"))

        # Check customer balances
        self.assertEqual(self.customer.get_total_owed_by_currency(), {})
        self.assertEqual(self.customer.get_credit_by_currency(), {"USD": 300.28})

    def test_payment_1800_usd_clears_both_with_200_28_credit(self):
        data = {
            "customer": self.customer.id,
            "account": self.account_usd.id,
            "currency": self.usd.id,
            "settlement_currency": self.usd.id,
            "amount": Decimal("1800.00"),
            "discount": Decimal("0.00"),
            "exchange_rate": Decimal("1.0"),
            "settlement_exchange_rate": Decimal("1.0"),
            "apply_to_opening_balance": True,
            "payment_date": timezone.now(),
        }
        serializer = CustomerBalancePaymentSerializer(data=data)
        self.assertTrue(serializer.is_valid(), serializer.errors)
        payment = serializer.save()

        self.assertEqual(payment.unallocated_amount, Decimal("200.28"))
        self.customer.refresh_from_db()
        self.assertEqual(self.customer.get_total_owed_by_currency(), {})
        self.assertEqual(self.customer.get_credit_by_currency(), {"USD": 200.28})
