"""
Stateflow API 测试
"""
from django.test import TestCase
from django.core.files.uploadedfile import SimpleUploadedFile
from rest_framework.test import APIClient
from rest_framework import status
from django.contrib.auth import get_user_model
from stateflow import models
import tempfile
import os

User = get_user_model()


class StateAPITestCase(TestCase):
    """测试 State API"""
    
    def setUp(self):
        """设置测试数据"""
        self.client = APIClient()
        self.user = User.objects.create_user(username='testuser', password='testpass')
        self.client.force_authenticate(user=self.user)
        
        # 创建基础参数供测试使用
        self.param1 = models.StateParameter.objects.create(
            key='param1', value='value1', description='参数1'
        )
        self.param2 = models.StateParameter.objects.create(
            key='param2', value='value2', description='参数2'
        )
        
        # 创建基础状态供测试使用
        self.state1 = models.State.objects.create(name='状态1', description='描述1')
        self.state2 = models.State.objects.create(name='状态2', description='描述2')
    
    def test_create_state(self):
        """测试创建状态"""
        data = {
            'name': '测试状态',
            'description': '这是一个测试状态',
            'parameter_ids': [self.param1.id, self.param2.id]
        }
        
        response = self.client.post('/api/v1/stateflow/states/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data['name'], '测试状态')
        
        # 验证参数已关联
        state = models.State.objects.get(name='测试状态')
        self.assertEqual(state.parameters.count(), 2)
    
    def test_list_states(self):
        """测试获取状态列表"""
        response = self.client.get('/api/v1/stateflow/states/?limit=10&offset=0')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['count'], 2)
        self.assertEqual(len(response.data['results']), 2)
    
    def test_retrieve_state(self):
        """测试获取状态详情"""
        self.state1.parameters.add(self.param1)
        
        response = self.client.get(f'/api/v1/stateflow/states/{self.state1.id}/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['name'], '状态1')
        self.assertEqual(len(response.data['parameters']), 1)
    
    def test_update_state(self):
        """测试更新状态"""
        data = {
            'name': '新名称',
            'description': '新描述',
            'parameter_ids': [self.param1.id]
        }
        
        response = self.client.put(f'/api/v1/stateflow/states/{self.state1.id}/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        self.state1.refresh_from_db()
        self.assertEqual(self.state1.name, '新名称')
        self.assertEqual(self.state1.parameters.count(), 1)
    
    def test_delete_state(self):
        """测试删除状态"""
        response = self.client.delete(f'/api/v1/stateflow/states/{self.state2.id}/')
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertFalse(models.State.objects.filter(id=self.state2.id).exists())
    
    def test_search_states(self):
        """测试搜索状态"""
        # 创建特定名称的状态用于搜索测试
        models.State.objects.create(name='审核状态', description='需要审核')
        models.State.objects.create(name='发货状态', description='已经发货')
        
        response = self.client.get('/api/v1/stateflow/states/?search=审核&limit=10&offset=0')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['count'], 1)
    
    def test_create_state_parameter_with_attachment(self):
        """测试创建带附件的状态参数"""
        # 创建一个测试文件
        test_file = SimpleUploadedFile(
            "test_doc.txt",
            b"This is a test document content",
            content_type="text/plain"
        )
        
        # 创建带附件的参数
        param = models.StateParameter.objects.create(
            key='document',
            value='测试文档',
            attachment=test_file,
            description='这是一个测试文档'
        )
        
        # 创建状态并关联参数
        state = models.State.objects.create(name='测试状态', description='带附件')
        state.parameters.add(param)
        
        # 验证附件已保存
        self.assertIsNotNone(param.attachment)
        self.assertIn('test_doc', param.attachment.name)  # 文件名可能有哈希前缀
        
        # 通过 API 获取状态详情，验证附件字段
        response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        # 验证参数中包含附件信息
        parameters = response.data['parameters']
        self.assertEqual(len(parameters), 1)
        self.assertIn('attachment', parameters[0])
        self.assertIn('attachment_url', parameters[0])
        self.assertIsNotNone(parameters[0]['attachment_url'])
        
        # 清理测试文件
        if param.attachment:
            param.attachment.delete()
    
    def test_state_parameter_without_attachment(self):
        """测试创建不带附件的状态参数"""
        param = models.StateParameter.objects.create(
            key='simple_param',
            value='简单值',
            description='简单参数'
        )
        state = models.State.objects.create(name='测试状态2', description='不带附件')
        state.parameters.add(param)
        
        # 验证附件字段为空
        self.assertFalse(param.attachment)
        
        # 通过 API 获取状态详情
        response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        # 验证附件字段为 null
        parameters = response.data['parameters']
        self.assertEqual(len(parameters), 1)
        self.assertIsNone(parameters[0]['attachment'])
        self.assertIsNone(parameters[0]['attachment_url'])
    
    def test_update_state_parameter_with_attachment(self):
        """测试更新状态参数时添加附件"""
        # 创建初始参数（不带附件）
        param = models.StateParameter.objects.create(
            key='updatable_param',
            value='初始值',
            description='可更新参数'
        )
        state = models.State.objects.create(name='测试状态3', description='更新附件')
        state.parameters.add(param)
        
        # 验证初始无附件
        self.assertFalse(param.attachment)
        
        # 添加附件
        test_file = SimpleUploadedFile(
            "updated_doc.pdf",
            b"Updated document content",
            content_type="application/pdf"
        )
        param.attachment = test_file
        param.save()
        
        # 验证附件已添加
        param.refresh_from_db()
        self.assertIsNotNone(param.attachment)
        self.assertIn('updated_doc', param.attachment.name)  # 文件名可能有哈希前缀
        
        # 通过 API 验证
        response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        parameters = response.data['parameters']
        self.assertIsNotNone(parameters[0]['attachment'])
        self.assertIsNotNone(parameters[0]['attachment_url'])
        
        # 清理
        if param.attachment:
            param.attachment.delete()
    
    def test_state_parameter_attachment_url_format(self):
        """测试附件 URL 格式正确"""
        test_file = SimpleUploadedFile(
            "test_image.jpg",
            b"fake image content",
            content_type="image/jpeg"
        )
        
        param = models.StateParameter.objects.create(
            key='image',
            value='测试图片',
            attachment=test_file
        )
        state = models.State.objects.create(name='图片状态', description='带图片')
        state.parameters.add(param)
        
        # 通过 API 获取
        response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        parameters = response.data['parameters']
        attachment_url = parameters[0]['attachment_url']
        
        # 验证 URL 格式
        self.assertIsNotNone(attachment_url)
        self.assertIn('http', attachment_url)  # 应该是完整 URL
        self.assertIn('state_parameters/', attachment_url)  # 包含上传路径
        
        # 清理
        if param.attachment:
            param.attachment.delete()
    
    def test_state_parameter_is_required(self):
        """测试参数必填字段"""
        # 创建必填参数
        required_param = models.StateParameter.objects.create(
            key='required_param',
            value='必填参数',
            is_required=True
        )
        
        # 创建可选参数
        optional_param = models.StateParameter.objects.create(
            key='optional_param',
            value='可选参数',
            is_required=False
        )
        
        # 创建状态并关联参数
        state = models.State.objects.create(name='测试状态', description='测试必填参数')
        state.parameters.add(required_param, optional_param)
        
        # 通过 API 验证
        response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        parameters = response.data['parameters']
        self.assertEqual(len(parameters), 2)
        
        # 验证必填字段正确返回
        required_params = [p for p in parameters if p['is_required']]
        optional_params = [p for p in parameters if not p['is_required']]
        
        self.assertEqual(len(required_params), 1)
        self.assertEqual(len(optional_params), 1)
        self.assertEqual(required_params[0]['key'], 'required_param')
    
    def test_state_get_parameters_method(self):
        """测试 State.get_parameters() 方法"""
        # 创建必填和可选参数
        required_param = models.StateParameter.objects.create(
            key='required1',
            value='必填',
            is_required=True
        )
        optional_param = models.StateParameter.objects.create(
            key='optional1',
            value='可选',
            is_required=False
        )
        
        state = models.State.objects.create(name='测试状态')
        state.parameters.add(required_param, optional_param)
        
        # 测试获取所有参数
        all_params = state.get_parameters(required_only=False)
        self.assertEqual(len(all_params), 2)
        
        # 测试只获取必填参数
        required_params = state.get_parameters(required_only=True)
        self.assertEqual(len(required_params), 1)
        self.assertEqual(required_params[0].key, 'required1')
        self.assertTrue(required_params[0].is_required)
    
    def test_state_parameter_is_image_path(self):
        """测试参数图片路径字段"""
        # 创建普通参数
        normal_param = models.StateParameter.objects.create(
            key='normal_param',
            value='普通文本值',
            is_image_path=False
        )
        
        # 创建图片路径参数
        image_param = models.StateParameter.objects.create(
            key='image_param',
            value='https://example.com/image.jpg',
            is_image_path=True
        )
        
        # 创建状态并关联参数
        state = models.State.objects.create(name='测试图片参数', description='测试is_image_path字段')
        state.parameters.add(normal_param, image_param)
        
        # 通过 API 验证
        response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        parameters = response.data['parameters']
        self.assertEqual(len(parameters), 2)
        
        # 验证 is_image_path 字段正确返回
        image_params = [p for p in parameters if p['is_image_path']]
        normal_params = [p for p in parameters if not p['is_image_path']]
        
        self.assertEqual(len(image_params), 1)
        self.assertEqual(len(normal_params), 1)
        self.assertEqual(image_params[0]['key'], 'image_param')
        self.assertEqual(image_params[0]['value'], 'https://example.com/image.jpg')
    
    def test_create_parameter_with_image_path_flag(self):
        """测试创建带图片路径标记的参数"""
        param = models.StateParameter.objects.create(
            key='product_image',
            value='https://cdn.example.com/products/abc123.png',
            is_image_path=True,
            description='产品图片URL'
        )
        
        # 验证字段已保存
        self.assertTrue(param.is_image_path)
        self.assertIn('https://', param.value)
        
        # 创建状态并关联
        state = models.State.objects.create(name='产品展示')
        state.parameters.add(param)
        
        # API 验证
        response = self.client.get(f'/api/v1/stateflow/states/{state.id}/')
        params = response.data['parameters']
        
        self.assertEqual(len(params), 1)
        self.assertTrue(params[0]['is_image_path'])
        self.assertEqual(params[0]['key'], 'product_image')


class ProcessAPITestCase(TestCase):
    """测试 Process API"""
    
    def setUp(self):
        self.client = APIClient()
        self.user = User.objects.create_user(username='testuser', password='testpass')
        self.client.force_authenticate(user=self.user)
        
        # 创建测试状态
        self.state1 = models.State.objects.create(name='状态1')
        self.state2 = models.State.objects.create(name='状态2')
        self.state3 = models.State.objects.create(name='状态3')
    
    def test_create_process(self):
        """测试创建流程"""
        data = {
            'name': '测试流程',
            'description': '这是一个测试流程',
            'nodes': [
                {'state_id': self.state1.id, 'order': 0},
                {'state_id': self.state2.id, 'order': 1},
                {'state_id': self.state3.id, 'order': 2},
            ]
        }
        
        response = self.client.post('/api/v1/stateflow/processes/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(response.data['name'], '测试流程')
        
        # 验证节点已创建
        process = models.Process.objects.get(name='测试流程')
        self.assertEqual(process.process_nodes.count(), 3)
    
    def test_list_processes(self):
        """测试获取流程列表"""
        models.Process.objects.create(name='流程1', description='描述1')
        models.Process.objects.create(name='流程2', description='描述2')
        
        response = self.client.get('/api/v1/stateflow/processes/?limit=10&offset=0')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['count'], 2)
        self.assertEqual(len(response.data['results']), 2)
    
    def test_retrieve_process(self):
        """测试获取流程详情"""
        process = models.Process.objects.create(name='测试流程', description='描述')
        models.ProcessNode.objects.create(process=process, state=self.state1, order=0)
        models.ProcessNode.objects.create(process=process, state=self.state2, order=1)
        
        response = self.client.get(f'/api/v1/stateflow/processes/{process.id}/')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['name'], '测试流程')
        self.assertEqual(len(response.data['nodes']), 2)
    
    def test_update_process(self):
        """测试更新流程"""
        process = models.Process.objects.create(name='旧名称', description='旧描述')
        models.ProcessNode.objects.create(process=process, state=self.state1, order=0)
        
        data = {
            'name': '新名称',
            'description': '新描述',
            'nodes': [
                {'state_id': self.state2.id, 'order': 0},
                {'state_id': self.state3.id, 'order': 1},
            ]
        }
        
        response = self.client.put(f'/api/v1/stateflow/processes/{process.id}/', data, format='json')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        
        process.refresh_from_db()
        self.assertEqual(process.name, '新名称')
        self.assertEqual(process.process_nodes.count(), 2)
    
    def test_delete_process(self):
        """测试删除流程"""
        process = models.Process.objects.create(name='待删除流程')
        
        response = self.client.delete(f'/api/v1/stateflow/processes/{process.id}/')
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertFalse(models.Process.objects.filter(id=process.id).exists())
    
    def test_search_processes(self):
        """测试搜索流程"""
        models.Process.objects.create(name='订单流程', description='处理订单')
        models.Process.objects.create(name='退货流程', description='处理退货')
        
        response = self.client.get('/api/v1/stateflow/processes/?search=订单&limit=10&offset=0')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['count'], 1)


class BusinessObjectNewAPITestCase(TestCase):
    """测试 BusinessObject 新增的 API"""
    
    def setUp(self):
        self.client = APIClient()
        self.user = User.objects.create_user(username='testuser', password='testpass')
        self.client.force_authenticate(user=self.user)
        
        # 创建状态和参数
        self.state1 = models.State.objects.create(name='状态1', description='第一个状态')
        self.state2 = models.State.objects.create(name='状态2', description='第二个状态')
        self.state3 = models.State.objects.create(name='状态3', description='第三个状态')
        
        # 为状态1添加参数
        self.param1 = models.StateParameter.objects.create(
            key='param1', value='value1', is_required=True, description='必填参数'
        )
        self.param2 = models.StateParameter.objects.create(
            key='param2', value='value2', is_required=False, description='可选参数'
        )
        self.state1.parameters.add(self.param1, self.param2)
        
        # 创建流程
        self.process = models.Process.objects.create(name='测试流程')
        models.ProcessNode.objects.create(process=self.process, state=self.state1, order=0)
        models.ProcessNode.objects.create(process=self.process, state=self.state2, order=1)
        models.ProcessNode.objects.create(process=self.process, state=self.state3, order=2)
        
        # 创建关联对象（使用 State 作为示例，因为它是 stateflow 模块内的模型）
        from django.contrib.contenttypes.models import ContentType
        self.linked_object = models.State.objects.create(name='关联对象')
        content_type = ContentType.objects.get_for_model(self.linked_object)
        
        # 创建业务对象并绑定关联对象
        self.business_object = models.BusinessObject.objects.create(
            name='测试业务对象',
            process=self.process,
            content_type=content_type,
            object_id=self.linked_object.id
        )
    
    def test_next_pending_state_api(self):
        """测试获取下一个待执行节点 API"""
        # 未开始时应返回第一个节点
        response = self.client.get(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/next_pending_state/'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['state']['id'], self.state1.id)
        self.assertEqual(response.data['order'], 0)
        self.assertIn('parameters', response.data)
        self.assertEqual(len(response.data['parameters']), 2)
        
        # 测试不包含参数
        response = self.client.get(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/next_pending_state/?include_parameters=false'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertNotIn('parameters', response.data)
        
        # 推进一步（提供必填参数）
        advance_response = self.client.post(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/',
            {'parameters': {'param1': 'test_value'}},
            format='json'
        )
        # 确保推进成功
        self.assertEqual(advance_response.status_code, status.HTTP_200_OK, 
                        f"Advance failed: {advance_response.data}")
        
        # 应返回第二个节点
        response = self.client.get(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/next_pending_state/'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['state']['id'], self.state2.id,
                        f"Expected state2 (id={self.state2.id}), got {response.data['state']['id']}")
        
        # 完成所有节点
        self.client.post(f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/')
        self.client.post(f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/')
        
        # 应返回 None
        response = self.client.get(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/next_pending_state/'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertIsNone(response.data['next_state'])
    
    def test_pending_states_api(self):
        """测试获取所有待执行节点 API"""
        # 初始状态应返回所有节点
        response = self.client.get(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/pending_states/'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['count'], 3)
        self.assertEqual(len(response.data['pending_states']), 3)
        
        # 验证不包含 parameters
        self.assertNotIn('parameters', response.data['pending_states'][0])
        
        # 推进一步（提供必填参数）
        self.client.post(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/',
            {'parameters': {'param1': 'test_value'}},
            format='json'
        )
        
        # 应只剩两个待执行节点
        response = self.client.get(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/pending_states/'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['count'], 2)
        
        # 完成所有节点
        self.client.post(f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/')
        self.client.post(f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/')
        
        # 应没有待执行节点
        response = self.client.get(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/pending_states/'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['count'], 0)
    
    def test_current_state_parameters_api(self):
        """测试获取当前状态（下一个待执行状态）参数 API"""
        # 未开始时，current_state 为 state1（第一个待执行的），应返回 state1 的参数
        response = self.client.get(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/current_state_parameters/'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['state']['id'], self.state1.id)
        self.assertEqual(len(response.data['parameters']), 2)
        
        # 推进（完成第一个状态），current_state 变为 state2（下一个待执行的状态）
        self.client.post(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/advance/',
            {'parameters': {'param1': 'test_value'}},
            format='json'
        )
        
        # 现在 current_state 是 state2（无参数）
        response = self.client.get(
            f'/api/v1/stateflow/business-objects/{self.business_object.id}/current_state_parameters/'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['state']['id'], self.state2.id)
        self.assertEqual(response.data['count'], 0)
        self.assertEqual(len(response.data['parameters']), 0)
    
    def test_state_parameters_api(self):
        """测试 State 的参数 API"""
        # 获取状态1的所有参数
        response = self.client.get(
            f'/api/v1/stateflow/states/{self.state1.id}/parameters/'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['state_id'], self.state1.id)
        self.assertEqual(response.data['count'], 2)
        self.assertEqual(len(response.data['parameters']), 2)
        
        # 只获取必填参数
        response = self.client.get(
            f'/api/v1/stateflow/states/{self.state1.id}/parameters/?required_only=true'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['count'], 1)
        
        # 测试没有参数的状态
        response = self.client.get(
            f'/api/v1/stateflow/states/{self.state2.id}/parameters/'
        )
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertEqual(response.data['count'], 0)
