from decimal import Decimal

from django.test import TestCase

from apps.pum.models import Supplier
from apps.pum.serializers import PuOrderSerializer
from apps.pum.serializers import PuContractRecordSerializer
from rest_framework.exceptions import ParseError


class PuContractSettlementTests(TestCase):
    def test_purchase_contract_record_updates_paid_summary(self):
        supplier = Supplier.objects.create(name='供应商A')

        from apps.pum.models import PuContract, PuContractRecord

        contract = PuContract.objects.create(
            name='采购合同A',
            number='PC-001',
            contract_amount=Decimal('2000.00'),
            supplier=supplier,
            sign_date='2026-04-20',
        )

        PuContractRecord.objects.create(
            contract=contract,
            record_date='2026-04-21',
            amount=Decimal('800.00'),
            stage_type=PuContractRecord.STAGE_FIRST,
        )

        contract.refresh_from_db()
        self.assertEqual(contract.paid_amount, Decimal('800.00'))
        self.assertEqual(contract.unpaid_amount, Decimal('1200.00'))
        self.assertEqual(contract.pay_progress, Decimal('40.00'))
        self.assertEqual(contract.status, contract.STATUS_ACTIVE)

    def test_purchase_contract_record_delete_refreshes_summary_and_is_physical(self):
        supplier = Supplier.objects.create(name='供应商C')

        from apps.pum.models import PuContract, PuContractRecord

        contract = PuContract.objects.create(
            name='采购合同C',
            number='PC-003',
            contract_amount=Decimal('2000.00'),
            supplier=supplier,
            sign_date='2026-04-20',
        )

        record = PuContractRecord.objects.create(
            contract=contract,
            record_date='2026-04-21',
            amount=Decimal('800.00'),
            stage_type=PuContractRecord.STAGE_FIRST,
        )

        record.delete()
        contract.refresh_from_db()

        self.assertEqual(contract.paid_amount, Decimal('0.00'))
        self.assertEqual(contract.unpaid_amount, Decimal('2000.00'))
        self.assertEqual(contract.pay_progress, Decimal('0.00'))
        self.assertEqual(contract.status, contract.STATUS_DRAFT)
        self.assertFalse(PuContractRecord._base_manager.filter(pk=record.pk).exists())

    def test_purchase_contract_delete_is_physical(self):
        supplier = Supplier.objects.create(name='供应商D')

        from apps.pum.models import PuContract

        contract = PuContract.objects.create(
            name='采购合同D',
            number='PC-004',
            contract_amount=Decimal('500.00'),
            supplier=supplier,
            sign_date='2026-04-20',
        )

        contract.delete()

        self.assertFalse(PuContract._base_manager.filter(pk=contract.pk).exists())

    def test_purchase_contract_status_auto_transitions_by_records(self):
        supplier = Supplier.objects.create(name='供应商E')

        from apps.pum.models import PuContract, PuContractRecord

        contract = PuContract.objects.create(
            name='采购合同E',
            number='PC-005',
            contract_amount=Decimal('2000.00'),
            supplier=supplier,
            sign_date='2026-04-20',
        )

        self.assertEqual(contract.status, PuContract.STATUS_DRAFT)

        first_record = PuContractRecord.objects.create(
            contract=contract,
            record_date='2026-04-21',
            amount=Decimal('800.00'),
            stage_type=PuContractRecord.STAGE_FIRST,
        )
        contract.refresh_from_db()
        self.assertEqual(contract.status, PuContract.STATUS_ACTIVE)

        PuContractRecord.objects.create(
            contract=contract,
            record_date='2026-04-22',
            amount=Decimal('1200.00'),
            stage_type=PuContractRecord.STAGE_FINAL,
        )
        contract.refresh_from_db()
        self.assertEqual(contract.status, PuContract.STATUS_DONE)

        first_record.delete()
        contract.refresh_from_db()
        self.assertEqual(contract.status, PuContract.STATUS_ACTIVE)

    def test_purchase_terminated_contract_forbids_record_changes(self):
        supplier = Supplier.objects.create(name='供应商F')

        from apps.pum.models import PuContract, PuContractRecord

        contract = PuContract.objects.create(
            name='采购合同F',
            number='PC-006',
            contract_amount=Decimal('1000.00'),
            supplier=supplier,
            sign_date='2026-04-20',
            status=PuContract.STATUS_TERMINATED,
        )

        serializer = PuContractRecordSerializer(data={
            'contract': contract.id,
            'record_date': '2026-04-21',
            'amount': '100.00',
            'stage_type': 10,
            'pay_method': 10,
        })
        self.assertFalse(serializer.is_valid())
        self.assertIn('合同已终止，不可操作付款流水', str(serializer.errors))

        contract.status = PuContract.STATUS_DRAFT
        contract.save(refresh_settlement=False)

        record = PuContractRecord.objects.create(
            contract=contract,
            record_date='2026-04-20',
            amount=Decimal('100.00'),
            stage_type=PuContractRecord.STAGE_OTHER,
        )
        contract.status = PuContract.STATUS_TERMINATED
        contract.save(refresh_settlement=False)

        with self.assertRaises(ParseError):
            from apps.pum.views import PuContractRecordViewSet
            viewset = PuContractRecordViewSet()
            viewset.request = None
            viewset.perform_destroy(record)

    def test_purchase_order_serializer_accepts_purchase_contract(self):
        supplier = Supplier.objects.create(name='供应商B')

        from apps.pum.models import PuContract

        contract = PuContract.objects.create(
            name='采购合同B',
            number='PC-002',
            contract_amount=Decimal('500.00'),
            supplier=supplier,
            sign_date='2026-04-20',
        )

        serializer = PuOrderSerializer(data={'supplier': supplier.id, 'contract': contract.id})

        self.assertTrue(serializer.is_valid(), serializer.errors)
