from decimal import Decimal

from django.test import TestCase

from apps.sam.models import Contract, Customer
from apps.sam.serializers import ContractRecordSerializer
from rest_framework.exceptions import ParseError


class ContractSettlementTests(TestCase):
    def test_sales_contract_record_updates_received_summary(self):
        customer = Customer.objects.create(
            name='客户A',
            contact='张三',
            contact_phone='13800000001',
        )
        contract = Contract.objects.create(
            name='销售合同A',
            number='SC-001',
            amount=1000,
            customer=customer,
            sign_date='2026-04-20',
        )

        from apps.sam.models import ContractRecord

        ContractRecord.objects.create(
            contract=contract,
            record_date='2026-04-21',
            amount=Decimal('300.00'),
            stage_type=ContractRecord.STAGE_FIRST,
        )
        ContractRecord.objects.create(
            contract=contract,
            record_date='2026-04-22',
            amount=Decimal('200.00'),
            stage_type=ContractRecord.STAGE_MIDDLE,
        )

        contract.refresh_from_db()
        self.assertEqual(contract.received_amount, Decimal('500.00'))
        self.assertEqual(contract.unreceived_amount, Decimal('500.00'))
        self.assertEqual(contract.receive_progress, Decimal('50.00'))
        self.assertEqual(contract.status, Contract.STATUS_ACTIVE)

    def test_sales_contract_record_delete_refreshes_summary_and_is_physical(self):
        customer = Customer.objects.create(
            name='客户B',
            contact='李四',
            contact_phone='13800000002',
        )
        contract = Contract.objects.create(
            name='销售合同B',
            number='SC-002',
            amount=1000,
            customer=customer,
            sign_date='2026-04-20',
        )

        from apps.sam.models import ContractRecord

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

        record.delete()
        contract.refresh_from_db()

        self.assertEqual(contract.received_amount, Decimal('0.00'))
        self.assertEqual(contract.unreceived_amount, Decimal('1000.00'))
        self.assertEqual(contract.receive_progress, Decimal('0.00'))
        self.assertEqual(contract.status, Contract.STATUS_DRAFT)
        self.assertFalse(ContractRecord._base_manager.filter(pk=record.pk).exists())

    def test_sales_contract_delete_is_physical(self):
        customer = Customer.objects.create(
            name='客户C',
            contact='王五',
            contact_phone='13800000003',
        )
        contract = Contract.objects.create(
            name='销售合同C',
            number='SC-003',
            amount=500,
            customer=customer,
            sign_date='2026-04-20',
        )

        contract.delete()

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

    def test_sales_contract_status_auto_transitions_by_records(self):
        customer = Customer.objects.create(
            name='客户D',
            contact='赵六',
            contact_phone='13800000004',
        )
        contract = Contract.objects.create(
            name='销售合同D',
            number='SC-004',
            amount=1000,
            customer=customer,
            sign_date='2026-04-20',
        )

        from apps.sam.models import ContractRecord

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

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

        ContractRecord.objects.create(
            contract=contract,
            record_date='2026-04-22',
            amount=Decimal('700.00'),
            stage_type=ContractRecord.STAGE_FINAL,
        )
        contract.refresh_from_db()
        self.assertEqual(contract.status, Contract.STATUS_DONE)

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

    def test_sales_terminated_contract_forbids_record_changes(self):
        customer = Customer.objects.create(
            name='客户E',
            contact='孙七',
            contact_phone='13800000005',
        )
        contract = Contract.objects.create(
            name='销售合同E',
            number='SC-005',
            amount=1000,
            customer=customer,
            sign_date='2026-04-20',
            status=Contract.STATUS_TERMINATED,
        )

        serializer = ContractRecordSerializer(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 = Contract.STATUS_DRAFT
        contract.save(refresh_settlement=False)

        from apps.sam.models import ContractRecord
        record = ContractRecord.objects.create(
            contract=contract,
            record_date='2026-04-20',
            amount=Decimal('100.00'),
            stage_type=ContractRecord.STAGE_OTHER,
        )
        contract.status = Contract.STATUS_TERMINATED
        contract.save(refresh_settlement=False)

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