"""
测试参数管理功能
包括必填参数验证、参数记录创建、回退后参数可见性等
"""
from django.test import TestCase
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from stateflow import models, services

User = get_user_model()


class ParameterManagementTestCase(TestCase):
    """测试参数管理功能"""
    
    def setUp(self):
        """设置测试数据"""
        # 创建测试用户
        self.user = User.objects.create_user(username='testuser', password='testpass')
        
        # 创建状态
        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.required_param = models.StateParameter.objects.create(
            key='temperature', 
            value='', 
            is_required=True,
            description='温度（必填）'
        )
        self.optional_param = models.StateParameter.objects.create(
            key='humidity', 
            value='', 
            is_required=False,
            description='湿度（可选）'
        )
        self.state1.parameters.add(self.required_param, self.optional_param)
        
        # 为状态2添加必填参数
        self.required_param2 = models.StateParameter.objects.create(
            key='pressure', 
            value='', 
            is_required=True,
            description='压力（必填）'
        )
        self.state2.parameters.add(self.required_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)
        
        self.process_content_type = ContentType.objects.get_for_model(models.Process)
        
        # 创建业务对象
        self.business_object = models.BusinessObject.objects.create(
            name='测试业务对象',
            process=self.process,
            content_type=self.process_content_type,
            object_id=self.process.id,
        )
    
    def test_advance_without_required_parameter_fails(self):
        """测试不提供必填参数时推进失败"""
        # 尝试推进但不提供必填参数
        success, message, state_log = services.advance_to_next_state(
            self.business_object, 
            self.user
        )
        
        # 应该失败
        self.assertFalse(success)
        self.assertIn('缺失必填参数', message)
        self.assertIn('temperature', message)
        self.assertIsNone(state_log)
        
        # 验证状态未改变（仍然是第一个待执行的节点）
        current_state = services.get_business_object_current_state(self.business_object)
        self.assertEqual(current_state.name, self.state1.name)
        
        # 验证没有创建状态流转记录
        self.assertEqual(self.business_object.state_logs.count(), 0)
    
    def test_advance_with_only_required_parameter_succeeds(self):
        """测试只提供必填参数时推进成功"""
        # 只提供必填参数
        success, message, state_log = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='25.5'  # 只提供必填的
        )
        
        # 应该成功
        self.assertTrue(success)
        self.assertIsNotNone(state_log)
        
        # 验证状态已推进（下一个待执行的是 state2）
        current_state = services.get_business_object_current_state(self.business_object)
        self.assertEqual(current_state.name, self.state2.name)
        
        # 验证参数记录已创建
        self.assertEqual(state_log.parameter_records.count(), 1)
        param_record = state_log.parameter_records.first()
        self.assertEqual(param_record.parameters['temperature'], '25.5')
        self.assertNotIn('humidity', param_record.parameters)
    
    def test_advance_with_all_parameters(self):
        """测试提供所有参数时推进成功"""
        success, message, state_log = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='25.5',
            humidity='60%'
        )
        
        # 应该成功
        self.assertTrue(success)
        self.assertIsNotNone(state_log)
        
        # 验证参数记录包含所有提供的参数
        param_record = state_log.parameter_records.first()
        self.assertEqual(param_record.parameters['temperature'], '25.5')
        self.assertEqual(param_record.parameters['humidity'], '60%')
    
    def test_advance_with_extra_parameters(self):
        """测试提供额外参数时也能成功（不做验证）"""
        success, message, state_log = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='25.5',
            humidity='60%',
            operator='张三',  # 额外参数
            notes='测试备注'  # 额外参数
        )
        
        # 应该成功（不验证参数是否在定义中）
        self.assertTrue(success)
        
        # 验证所有参数都被保存
        param_record = state_log.parameter_records.first()
        self.assertEqual(len(param_record.parameters), 4)
        self.assertEqual(param_record.parameters['operator'], '张三')
        self.assertEqual(param_record.parameters['notes'], '测试备注')
    
    def test_add_parameters_after_advance(self):
        """测试推进后补充参数"""
        # 先推进
        success, message, state_log = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='25.5'
        )
        self.assertTrue(success)
        
        # 补充参数
        new_record = services.add_parameters_to_state_log(
            state_log,
            remark='补充测量',
            humidity='65%',
            inspector='李四'
        )
        
        # 验证创建了新的参数记录
        self.assertEqual(state_log.parameter_records.count(), 2)
        self.assertEqual(new_record.parameters['humidity'], '65%')
        self.assertEqual(new_record.parameters['inspector'], '李四')
        self.assertEqual(new_record.remark, '补充测量')
    
    def test_parameter_summary_with_updates(self):
        """测试参数汇总（包含更新的值）"""
        # 推进并提供初始参数
        success, message, state_log = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='25.5',
            humidity='60%'
        )
        
        # 补充参数（更新 temperature）
        services.add_parameters_to_state_log(
            state_log,
            temperature='26.0',  # 重新测量
            remark='温度重新测量'
        )
        
        # 获取参数汇总
        summary = state_log.get_all_parameters_summary()
        
        # 验证最新值
        self.assertEqual(summary['temperature'], '26.0')  # 应该是更新后的值
        self.assertEqual(summary['humidity'], '60%')  # 保持原值
    
    def test_parameter_history(self):
        """测试参数历史记录"""
        # 推进
        success, message, state_log = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='25.5'
        )
        
        # 多次更新同一个参数
        services.add_parameters_to_state_log(
            state_log,
            temperature='26.0',
            remark='第一次重测'
        )
        services.add_parameters_to_state_log(
            state_log,
            temperature='26.5',
            remark='第二次重测'
        )
        
        # 获取历史
        history = state_log.get_parameter_history('temperature')
        
        # 验证历史记录
        self.assertEqual(len(history), 3)
        self.assertEqual(history[0]['value'], '25.5')
        self.assertEqual(history[1]['value'], '26.0')
        self.assertEqual(history[1]['remark'], '第一次重测')
        self.assertEqual(history[2]['value'], '26.5')
        self.assertEqual(history[2]['remark'], '第二次重测')
    
    def test_step_back_excludes_cancelled_state_parameters(self):
        """测试回退后，默认情况下查询参数时应排除已撤销状态的参数"""
        # 推进两次，每次都提供参数
        success, msg, state_log1 = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='25.5',
            humidity='60%'
        )
        self.assertTrue(success)
        
        success, msg, state_log2 = services.advance_to_next_state(
            self.business_object, 
            self.user,
            pressure='1013'
        )
        self.assertTrue(success)
        
        # 验证两个状态都有参数记录
        self.assertEqual(state_log1.parameter_records.count(), 1)
        self.assertEqual(state_log2.parameter_records.count(), 1)
        
        # 回退一步（撤销 state2）
        success, message = services.step_back_one_state(self.business_object, self.user)
        self.assertTrue(success)
        
        # 刷新 state_log2
        state_log2.refresh_from_db()
        self.assertTrue(state_log2.is_cancelled)
        
        # 默认情况下，已撤销状态的参数不可见
        summary = state_log2.get_all_parameters_summary()
        self.assertEqual(len(summary), 0)  # 应该返回空字典
        
        # 使用 include_cancelled=True 可以查看已撤销状态的参数
        summary_with_cancelled = state_log2.get_all_parameters_summary(include_cancelled=True)
        self.assertEqual(len(summary_with_cancelled), 1)
        self.assertEqual(summary_with_cancelled['pressure'], '1013')
        
        # 验证 state_log1 的参数仍然可见（未撤销）
        summary1 = state_log1.get_all_parameters_summary()
        self.assertEqual(len(summary1), 2)
        self.assertEqual(summary1['temperature'], '25.5')
        self.assertEqual(summary1['humidity'], '60%')
    
    def test_cancelled_state_parameter_history(self):
        """测试已撤销状态的参数历史记录不可见"""
        # 推进并提供参数
        success, msg, state_log = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='25.5'
        )
        self.assertTrue(success)
        
        # 补充参数
        services.add_parameters_to_state_log(
            state_log,
            temperature='26.0',
            remark='重新测量'
        )
        
        # 验证参数历史存在
        history = state_log.get_parameter_history('temperature')
        self.assertEqual(len(history), 2)
        
        # 回退（撤销状态）
        services.step_back_one_state(self.business_object, self.user)
        state_log.refresh_from_db()
        
        # 默认情况下，已撤销状态的参数历史不可见
        history = state_log.get_parameter_history('temperature')
        self.assertEqual(len(history), 0)
        
        # 使用 include_cancelled=True 可以查看
        history_with_cancelled = state_log.get_parameter_history('temperature', include_cancelled=True)
        self.assertEqual(len(history_with_cancelled), 2)
    
    def test_cancelled_state_get_latest_parameter(self):
        """测试已撤销状态无法获取最新参数值"""
        # 推进并提供参数
        success, msg, state_log = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='25.5'
        )
        self.assertTrue(success)
        
        # 验证可以获取参数
        temp = state_log.get_latest_parameter('temperature')
        self.assertEqual(temp, '25.5')
        
        # 回退（撤销状态）
        services.step_back_one_state(self.business_object, self.user)
        state_log.refresh_from_db()
        
        # 默认情况下返回默认值
        temp = state_log.get_latest_parameter('temperature', default='N/A')
        self.assertEqual(temp, 'N/A')
        
        # 使用 include_cancelled=True 可以获取
        temp_with_cancelled = state_log.get_latest_parameter('temperature', include_cancelled=True)
        self.assertEqual(temp_with_cancelled, '25.5')
    
    def test_multiple_states_with_different_required_parameters(self):
        """测试多个状态各自的必填参数验证"""
        # 推进到 state1（需要 temperature）
        success, msg, _ = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='25.5'
        )
        self.assertTrue(success)
        
        # 尝试推进到 state2 但不提供 pressure
        success, msg, _ = services.advance_to_next_state(
            self.business_object, 
            self.user,
            temperature='26.0'  # 提供了 state1 的参数，但这是 state2
        )
        
        # 应该失败（缺少 state2 的必填参数 pressure）
        self.assertFalse(success)
        self.assertIn('缺失必填参数', msg)
        self.assertIn('pressure', msg)
        
        # 提供正确的必填参数
        success, msg, _ = services.advance_to_next_state(
            self.business_object, 
            self.user,
            pressure='1013'
        )
        self.assertTrue(success)
    
    def test_state_without_required_parameters_allows_advance_without_params(self):
        """测试没有必填参数的状态允许不提供参数推进"""
        # 先推进两次到达 state3（没有任何参数要求）
        services.advance_to_next_state(self.business_object, self.user, temperature='25')
        services.advance_to_next_state(self.business_object, self.user, pressure='1013')
        
        # 推进到 state3，不提供任何参数
        success, msg, state_log = services.advance_to_next_state(
            self.business_object, 
            self.user
        )
        
        # 应该成功
        self.assertTrue(success)
        self.assertIsNotNone(state_log)
        
        # 验证没有创建参数记录
        self.assertEqual(state_log.parameter_records.count(), 0)
