"""
Tests for printing services
"""
from django.test import TestCase
from django.contrib.auth.models import User
from django.conf import settings
from basic_info.models import Merchant, MerchantTypeEnum, Employee, Customer, Product
from stateflow.models import State, Process
from printing.models import PrintingOrder, PrintingJob
from printing.signals import printing_job_production_completed
from api_v1.views.printing.services import PrintingOrderService, PrintingJobService


class PrintingOrderServiceTest(TestCase):
    """测试 PrintingOrderService"""
    
    def setUp(self):
        """设置测试数据"""
        self.user = User.objects.create_user(username='testuser', password='testpass')
        
        # 创建商户
        self.merchant = Merchant.objects.create(
            name='测试印染工厂',
            type=MerchantTypeEnum.FACTORY,
        )
        
        # 创建员工
        self.employee = Employee.objects.create(
            sys_user=self.user,
            name='测试员工',
            merchant=self.merchant,
        )
        
        # 创建客户
        self.customer = Customer.objects.create(
            name='测试客户',
            mobile='13800138000',
            merchant=self.merchant,
        )
        
        # 创建产品类别
        from basic_info.models import ProductCategory
        self.category = ProductCategory.objects.create(
            name='测试类别',
            merchant=self.merchant,
        )
        
        # 创建产品
        self.product = Product.objects.create(
            name='测试产品',
            category=self.category,
            merchant=self.merchant,
        )
        
        # 创建流程
        self.state1 = State.objects.create(name='待印染')
        self.state2 = State.objects.create(name='印染中')
        self.state3 = State.objects.create(name='已完成')
        
        self.process = Process.objects.create(name='印染流程')
        self.process.replace_nodes([self.state1, self.state2, self.state3])
        
        # 设置默认流程
        settings.PRINTING_DEFAULT_PROCESS_ID = self.process.id
    
    def test_get_default_process(self):
        """测试获取默认流程"""
        default_process = PrintingOrderService.get_default_process()
        self.assertIsNotNone(default_process)
        self.assertEqual(default_process.id, self.process.id)
    
    def test_create_printing_order_with_default_process(self):
        """测试创建订单使用默认流程"""
        data = {
            'customer': self.customer,
            'fabric': '棉布',
            'width': '150cm',
        }
        
        order = PrintingOrderService.create_printing_order(data, self.user)
        
        self.assertIsNotNone(order)
        self.assertEqual(order.process.id, self.process.id)
        self.assertEqual(order.customer, self.customer)
    
    def test_create_printing_order_with_custom_process(self):
        """测试创建订单指定自定义流程"""
        custom_process = Process.objects.create(name='自定义流程')
        
        data = {
            'customer': self.customer,
            'fabric': '棉布',
            'width': '150cm',
            'process': custom_process,
        }
        
        order = PrintingOrderService.create_printing_order(data, self.user)
        
        self.assertEqual(order.process, custom_process)
    
    def test_update_printing_order_success(self):
        """测试更新订单成功"""
        order = PrintingOrder.objects.create(
            customer=self.customer,
            fabric='棉布',
            width='150cm',
            process=self.process,
        )
        
        update_data = {
            'fabric': '真丝',
            'is_urgent': True,
        }
        
        success, message, updated_order = PrintingOrderService.update_printing_order(
            order, update_data, self.user
        )
        
        self.assertTrue(success)
        self.assertEqual(updated_order.fabric, '真丝')
        self.assertTrue(updated_order.is_urgent)
    
    def test_update_printing_order_change_process_when_no_jobs(self):
        """测试没有任务时可以修改流程"""
        order = PrintingOrder.objects.create(
            customer=self.customer,
            fabric='棉布',
            width='150cm',
            process=self.process,
        )
        
        new_process = Process.objects.create(name='新流程')
        
        success, message, updated_order = PrintingOrderService.update_printing_order(
            order, {'process': new_process}, self.user
        )
        
        self.assertTrue(success)
        self.assertEqual(updated_order.process, new_process)
    
    def test_update_printing_order_cannot_change_process_when_job_started(self):
        """测试有已开始的任务时不能修改流程"""
        order = PrintingOrder.objects.create(
            customer=self.customer,
            fabric='棉布',
            width='150cm',
            process=self.process,
        )
        
        # 创建任务并开始流程
        job = PrintingJob.objects.create(
            printing_order=order,
            product=self.product,
            quantity=10,
            unit='件',
            size='100x200',
            pieces=5,
        )
        
        # 使用 service 创建 BusinessObject
        from stateflow.models import BusinessObject
        business_object = BusinessObject.objects.create(
            name=f'PrintingJob-{job.id}',
            process=self.process,
        )
        job.business_object = business_object
        job.save()
        
        # 推进状态（模拟开始）
        from stateflow.services import advance_to_next_state
        advance_to_next_state(business_object, self.user)
        
        # 尝试修改流程
        new_process = Process.objects.create(name='新流程')
        success, message, _ = PrintingOrderService.update_printing_order(
            order, {'process': new_process}, self.user
        )
        
        self.assertFalse(success)
        self.assertIn('已开始', message)
    
    def test_can_change_process(self):
        """测试判断是否可以修改流程"""
        order = PrintingOrder.objects.create(
            customer=self.customer,
            fabric='棉布',
            width='150cm',
            process=self.process,
        )
        
        # 没有任务时可以修改
        self.assertTrue(PrintingOrderService.can_change_process(order))
        
        # 有任务但未开始时可以修改
        job = PrintingJob.objects.create(
            printing_order=order,
            product=self.product,
            quantity=10,
            unit='件',
            size='100x200',
            pieces=5,
        )
        self.assertTrue(PrintingOrderService.can_change_process(order))
    
    def test_get_order_progress(self):
        """测试计算订单进度"""
        order = PrintingOrder.objects.create(
            customer=self.customer,
            fabric='棉布',
            width='150cm',
            process=self.process,
        )
        
        # 没有任务时进度为0
        self.assertEqual(PrintingOrderService.get_order_progress(order), 0)
        
        # 创建3个任务（使用 service 以便自动创建 business_object）
        from .services import PrintingJobService
        jobs = []
        for i in range(3):
            job = PrintingJobService.create_printing_job({
                'printing_order': order,
                'product': self.product,
                'quantity': 10,
                'unit': '件',
                'size': '100x200',
                'pieces': 5,
            }, self.user)
            jobs.append(job)
        
        # 没有开始时进度为0（0/3 = 0%）
        self.assertEqual(PrintingOrderService.get_order_progress(order), 0)
        
        # 推进第一个任务到部分完成（还没完成）
        from stateflow.services import advance_to_next_state
        advance_to_next_state(jobs[0].business_object, self.user)
        advance_to_next_state(jobs[0].business_object, self.user)
        
        # 订单进度仍然是0，因为没有任务完全完成（0/3 = 0%）
        self.assertEqual(PrintingOrderService.get_order_progress(order), 0)
        
        # 完成第一个任务
        advance_to_next_state(jobs[0].business_object, self.user)
        
        # 订单进度应该是 1/3 = 33%
        self.assertEqual(PrintingOrderService.get_order_progress(order), 33)
        
        # 完成第二个任务
        advance_to_next_state(jobs[1].business_object, self.user)
        advance_to_next_state(jobs[1].business_object, self.user)
        advance_to_next_state(jobs[1].business_object, self.user)
        
        # 订单进度应该是 2/3 = 66%
        self.assertEqual(PrintingOrderService.get_order_progress(order), 66)
        
        # 完成所有任务
        advance_to_next_state(jobs[2].business_object, self.user)
        advance_to_next_state(jobs[2].business_object, self.user)
        advance_to_next_state(jobs[2].business_object, self.user)
        
        # 订单进度应该是 3/3 = 100%
        self.assertEqual(PrintingOrderService.get_order_progress(order), 100)


class PrintingJobServiceTest(TestCase):
    """测试 PrintingJobService"""
    
    def setUp(self):
        """设置测试数据"""
        self.user = User.objects.create_user(username='testuser', password='testpass')
        
        # 创建商户
        self.merchant = Merchant.objects.create(
            name='测试印染工厂',
            type=MerchantTypeEnum.FACTORY,
        )
        
        # 创建员工
        self.employee = Employee.objects.create(
            sys_user=self.user,
            name='测试员工',
            merchant=self.merchant,
        )
        
        # 创建客户
        self.customer = Customer.objects.create(
            name='测试客户',
            mobile='13800138000',
            merchant=self.merchant,
        )
        
        # 创建产品类别
        from basic_info.models import ProductCategory
        self.category = ProductCategory.objects.create(
            name='测试类别',
            merchant=self.merchant,
        )
        
        # 创建产品
        self.product = Product.objects.create(
            name='测试产品',
            category=self.category,
            merchant=self.merchant,
        )
        
        # 创建流程
        self.state1 = State.objects.create(name='待印染')
        self.state2 = State.objects.create(name='印染中')
        self.state3 = State.objects.create(name='已完成')
        
        self.process = Process.objects.create(name='印染流程')
        self.process.replace_nodes([self.state1, self.state2, self.state3])
        
        # 创建订单
        self.order = PrintingOrder.objects.create(
            customer=self.customer,
            fabric='棉布',
            width='150cm',
            process=self.process,
        )
    
    def test_create_printing_job_with_business_object(self):
        """测试创建任务自动创建 BusinessObject"""
        data = {
            'printing_order': self.order,
            'product': self.product,
            'quantity': 10,
            'unit': '件',
            'size': '100x200',
            'pieces': 5,
        }
        
        job = PrintingJobService.create_printing_job(data, self.user)
        
        self.assertIsNotNone(job)
        self.assertIsNotNone(job.business_object)
        self.assertEqual(job.business_object.process, self.process)
    
    def test_create_printing_job_without_process(self):
        """测试创建任务时订单没有流程"""
        order_no_process = PrintingOrder.objects.create(
            customer=self.customer,
            fabric='棉布',
            width='150cm',
        )
        
        data = {
            'printing_order': order_no_process,
            'product': self.product,
            'quantity': 10,
            'unit': '件',
            'size': '100x200',
            'pieces': 5,
        }
        
        job = PrintingJobService.create_printing_job(data, self.user)
        
        self.assertIsNotNone(job)
        self.assertIsNone(job.business_object)
    
    def test_update_printing_job(self):
        """测试更新任务"""
        job = PrintingJob.objects.create(
            printing_order=self.order,
            product=self.product,
            quantity=10,
            unit='件',
            size='100x200',
            pieces=5,
        )
        
        update_data = {
            'quantity': 20,
            'pieces': 10,
        }
        
        success, message, updated_job = PrintingJobService.update_printing_job(
            job, update_data, self.user
        )
        
        self.assertTrue(success)
        self.assertEqual(updated_job.quantity, 20)
        self.assertEqual(updated_job.pieces, 10)

    def test_create_printing_job_ignores_is_production_completed(self):
        """测试创建任务时忽略 is_production_completed 输入"""
        data = {
            'printing_order': self.order,
            'product': self.product,
            'quantity': 10,
            'unit': '件',
            'is_production_completed': True,
        }

        job = PrintingJobService.create_printing_job(data, self.user)

        self.assertFalse(job.is_production_completed)

    def test_update_printing_job_ignores_is_production_completed(self):
        """测试更新任务时忽略 is_production_completed 输入"""
        job = PrintingJob.objects.create(
            printing_order=self.order,
            product=self.product,
            quantity=10,
            unit='件',
            is_production_completed=False,
        )

        success, _, updated_job = PrintingJobService.update_printing_job(
            job,
            {'is_production_completed': True, 'quantity': 20},
            self.user,
        )

        updated_job.refresh_from_db()
        self.assertTrue(success)
        self.assertEqual(updated_job.quantity, 20)
        self.assertFalse(updated_job.is_production_completed)

    def test_make_printing_job_production_completed_sets_flag_and_sends_signal(self):
        """测试显式完成生产会更新字段并触发 signal"""
        job = PrintingJob.objects.create(
            printing_order=self.order,
            product=self.product,
            quantity=10,
            unit='件',
        )

        received = {}
        uid = 'test.printing_job_production_completed'

        def _receiver(sender, **kwargs):
            received['sender'] = sender
            received['instance_id'] = kwargs['instance'].id
            received['triggered_by'] = kwargs.get('triggered_by')

        printing_job_production_completed.connect(_receiver, dispatch_uid=uid, weak=False)
        try:
            updated_job = PrintingJobService.make_printing_job_production_completed(job, self.user)
        finally:
            printing_job_production_completed.disconnect(dispatch_uid=uid)

        updated_job.refresh_from_db()
        self.assertTrue(updated_job.is_production_completed)
        self.assertEqual(received['sender'], PrintingJob)
        self.assertEqual(received['instance_id'], job.id)
        self.assertEqual(received['triggered_by'], self.user)

    def test_get_job_status(self):
        """测试获取任务状态"""
        job = PrintingJob.objects.create(
            printing_order=self.order,
            product=self.product,
            quantity=10,
            unit='件',
            size='100x200',
            pieces=5,
        )
        
        status_info = PrintingJobService.get_job_status(job)
        
        self.assertIn('status', status_info)
        self.assertIn('status_id', status_info)
        self.assertIn('is_completed', status_info)
        self.assertIn('is_production_completed', status_info)
        self.assertIn('has_started', status_info)
        
        # 未开始状态（现在返回空字符串或第一个状态名称）
        self.assertIn(status_info['status'], ['', self.state1.name])
        self.assertFalse(status_info['is_completed'])
        self.assertFalse(status_info['is_production_completed'])
        self.assertFalse(status_info['has_started'])
