package com.mosquito.project.permission;

import com.mosquito.project.permission.SysApprovalRecord;
import com.mosquito.project.permission.ApprovalRecordRepository;
import com.mosquito.project.permission.ApprovalFlowRepository;
import com.mosquito.project.permission.SysApprovalFlow;
import com.mosquito.project.permission.DepartmentRepository;
import com.mosquito.project.permission.UserRepository;
import com.mosquito.project.permission.entity.SysUserEntity;
import com.mosquito.project.service.NotificationService;
import com.mosquito.project.service.EmailService;
import com.mosquito.project.service.SmsService;
import com.mosquito.project.persistence.entity.NotificationEntity;
import com.mosquito.project.permission.SysDepartment;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;

/**
 * 审批超时任务单元测试
 * 覆盖 PRD 要求的 50/80/100 超时机制
 * PRD: 50%触发首次提醒，80%触发二次提醒(站内+邮件+短信)，100%自动升级/拒绝
 */
@ExtendWith(MockitoExtension.class)
class ApprovalTimeoutJobTest {

    @Mock
    private ApprovalRecordRepository recordRepository;

    @Mock
    private ApprovalFlowRepository flowRepository;

    @Mock
    private ApprovalFlowService approvalFlowService;

    @Mock
    private DepartmentRepository departmentRepository;

    @Mock
    private NotificationService notificationService;

    @Mock
    private ApprovalTimeoutReminderRepository reminderRepository;

    @Mock
    private UserRepository userRepository;

    @Mock
    private EmailService emailService;

    @Mock
    private SmsService smsService;

    @InjectMocks
    private ApprovalTimeoutJob approvalTimeoutJob;

    private SysApprovalRecord testRecord;
    private SysApprovalFlow testFlow;

    @BeforeEach
    void setUp() {
        // 手动注入通过setter注入的依赖（因为@InjectMocks只通过构造函数注入）
        approvalTimeoutJob.setEmailService(emailService);
        approvalTimeoutJob.setSmsService(smsService);

        // 设置测试数据
        testRecord = new SysApprovalRecord();
        testRecord.setId(1L);
        testRecord.setStatus("PROCESSING");
        testRecord.setApplicantId(100L);
        testRecord.setCurrentApproverId(200L);
        testRecord.setCreatedAt(LocalDateTime.now().minusHours(13)); // 13小时前创建
        testRecord.setFlowId(1L);
        testRecord.setBizType("ACTIVITY_CREATE");
        testRecord.setBizId(1L);

        testFlow = new SysApprovalFlow();
        testFlow.setId(1L);
        testFlow.setTimeoutHours(24); // 24小时超时
        testFlow.setTriggerEvent("ACTIVITY_CREATE");
        testFlow.setNodes("[{\"nodeName\":\"测试审批\",\"approverType\":\"ROLE\",\"approverCodes\":[\"operation_manager\"]}]");
    }

    // ==================== 50/80/100 分支测试 ====================

    /**
     * 测试 50% 首次提醒分支
     * 验证：调用sendTimeoutWarning，progressPercent=50
     */
    @Test
    void test50PercentBranch_TriggersWarning() {
        // 13小时 / 24小时 = 54%
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.singletonList(testRecord));
        when(flowRepository.findById(1L)).thenReturn(Optional.of(testFlow));
        when(reminderRepository.hasReminderBeenSent(eq(1L), eq(200L), eq(50))).thenReturn(false);
        when(notificationService.createNotification(any())).thenReturn(new NotificationEntity());

        // 执行
        approvalTimeoutJob.checkApprovalTimeout();

        // 验证：发送了50%提醒
        verify(reminderRepository).hasReminderBeenSent(1L, 200L, 50);
        verify(notificationService).createNotification(any());
        verify(emailService, never()).sendApprovalTimeoutEmail(any(), any(), anyLong(), anyInt());
        verify(smsService, never()).sendApprovalTimeoutSms(any(), any(), anyLong());
    }

    /**
     * 测试 80% 二次提醒分支
     * 验证：调用sendTimeoutWarning，progressPercent=80，且发送短信
     */
    @Test
    void test80PercentBranch_SendsSms() {
        // 22小时 / 24小时 = 91.67% (确保超过80%)
        testRecord.setCreatedAt(LocalDateTime.now().minusHours(22));
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.singletonList(testRecord));
        when(flowRepository.findById(1L)).thenReturn(Optional.of(testFlow));
        when(reminderRepository.hasReminderBeenSent(anyLong(), anyLong(), anyInt())).thenReturn(false);

        // 模拟邮件和短信服务
        SysUserEntity approver = new SysUserEntity();
        approver.setId(200L);
        approver.setEmail("test@example.com");
        approver.setPhone("13800138000");
        approver.setUsername("approver");
        when(userRepository.findById(200L)).thenReturn(Optional.of(approver));
        when(emailService.sendApprovalTimeoutEmail(any(), any(), anyLong(), anyInt())).thenReturn(true);
        when(smsService.sendApprovalTimeoutSms(any(), any(), anyLong())).thenReturn(true);
        when(notificationService.createNotification(any())).thenReturn(new NotificationEntity());

        // 执行
        approvalTimeoutJob.checkApprovalTimeout();

        // 验证：80%时发送短信
        verify(smsService).sendApprovalTimeoutSms(eq("13800138000"), any(), eq(1L));
        verify(emailService).sendApprovalTimeoutEmail(eq("test@example.com"), any(), eq(1L), eq(80));
        // 保存了80%提醒记录
        ArgumentCaptor<ApprovalTimeoutReminderRecord> captor = ArgumentCaptor.forClass(ApprovalTimeoutReminderRecord.class);
        verify(reminderRepository).save(captor.capture());
        assertEquals(80, captor.getValue().getProgressPercent());
    }

    /**
     * 测试 100% 超时处理分支 - ESCALATE 动作
     */
    @Test
    void test100PercentBranch_EscalateAction() {
        // 25小时 / 24小时 = 已超时
        testRecord.setCreatedAt(LocalDateTime.now().minusHours(25));
        testFlow.setTimeoutAction("ESCALATE");
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.singletonList(testRecord));
        when(flowRepository.findById(1L)).thenReturn(Optional.of(testFlow));

        // 模拟查找上级审批人
        SysUserEntity currentApprover = new SysUserEntity();
        currentApprover.setId(200L);
        currentApprover.setDepartmentId(10L);
        currentApprover.setUsername("current");

        SysUserEntity superior = new SysUserEntity();
        superior.setId(300L);
        superior.setDepartmentId(5L);
        superior.setUsername("superior");

        when(userRepository.findById(200L)).thenReturn(Optional.of(currentApprover));

        SysDepartment currentDept = new SysDepartment();
        currentDept.setId(10L);
        currentDept.setParentId(5L);
        when(departmentRepository.findById(10L)).thenReturn(Optional.of(currentDept));

        SysDepartment parentDept = new SysDepartment();
        parentDept.setId(5L);
        parentDept.setParentId(null);
        when(departmentRepository.findById(5L)).thenReturn(Optional.of(parentDept));
        when(userRepository.findByDepartmentIdAndStatusNot(5L, "FROZEN")).thenReturn(List.of(superior));

        // 执行
        approvalTimeoutJob.checkApprovalTimeout();

        // 验证：审批人被升级
        ArgumentCaptor<SysApprovalRecord> recordCaptor = ArgumentCaptor.forClass(SysApprovalRecord.class);
        verify(recordRepository).save(recordCaptor.capture());
        assertEquals(300L, recordCaptor.getValue().getCurrentApproverId());
    }

    /**
     * 测试 100% 超时处理分支 - AUTO_APPROVE 动作
     */
    @Test
    void test100PercentBranch_AutoApproveAction() {
        testRecord.setCreatedAt(LocalDateTime.now().minusHours(25));
        testFlow.setTimeoutAction("AUTO_APPROVE");
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.singletonList(testRecord));
        when(flowRepository.findById(1L)).thenReturn(Optional.of(testFlow));

        // 执行
        approvalTimeoutJob.checkApprovalTimeout();

        // 验证：记录被自动通过
        ArgumentCaptor<SysApprovalRecord> recordCaptor = ArgumentCaptor.forClass(SysApprovalRecord.class);
        verify(recordRepository).save(recordCaptor.capture());
        assertEquals("APPROVED", recordCaptor.getValue().getStatus());
        verify(approvalFlowService).processAfterApproval(any());
    }

    /**
     * 测试 100% 超时处理分支 - REJECT 动作
     */
    @Test
    void test100PercentBranch_RejectAction() {
        testRecord.setCreatedAt(LocalDateTime.now().minusHours(25));
        testFlow.setTimeoutAction("REJECT");
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.singletonList(testRecord));
        when(flowRepository.findById(1L)).thenReturn(Optional.of(testFlow));

        // 执行
        approvalTimeoutJob.checkApprovalTimeout();

        // 验证：记录被自动拒绝
        ArgumentCaptor<SysApprovalRecord> recordCaptor = ArgumentCaptor.forClass(SysApprovalRecord.class);
        verify(recordRepository).save(recordCaptor.capture());
        assertEquals("REJECTED", recordCaptor.getValue().getStatus());
        verify(approvalFlowService).processAfterRejection(any());
    }

    /**
     * 测试 100% 超时处理分支 - NOTIFY 动作
     */
    @Test
    void test100PercentBranch_NotifyAction() {
        testRecord.setCreatedAt(LocalDateTime.now().minusHours(25));
        testFlow.setTimeoutAction("NOTIFY");
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.singletonList(testRecord));
        when(flowRepository.findById(1L)).thenReturn(Optional.of(testFlow));
        when(notificationService.createNotification(any())).thenReturn(new NotificationEntity());

        // 执行
        approvalTimeoutJob.checkApprovalTimeout();

        // 验证：发送超时通知（审批人+申请人）
        verify(notificationService, atLeast(2)).createNotification(any());
    }

    // ==================== 去重测试 ====================

    /**
     * 测试 50% 提醒去重
     * 已发送过50%提醒时，不再发送
     */
    @Test
    void test50PercentReminder_Deduplication() {
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.singletonList(testRecord));
        when(flowRepository.findById(1L)).thenReturn(Optional.of(testFlow));
        when(reminderRepository.hasReminderBeenSent(1L, 200L, 50)).thenReturn(true); // 已发送过

        // 执行
        approvalTimeoutJob.checkApprovalTimeout();

        // 验证：不发送通知，不保存提醒记录
        verify(notificationService, never()).createNotification(any());
        verify(reminderRepository, never()).save(any());
    }

    /**
     * 测试 80% 提醒去重
     * 已发送过80%提醒时，不再发送
     */
    @Test
    void test80PercentReminder_Deduplication() {
        testRecord.setCreatedAt(LocalDateTime.now().minusHours(20));
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.singletonList(testRecord));
        when(flowRepository.findById(1L)).thenReturn(Optional.of(testFlow));
        when(reminderRepository.hasReminderBeenSent(1L, 200L, 80)).thenReturn(true); // 已发送过

        // 执行
        approvalTimeoutJob.checkApprovalTimeout();

        // 验证：不发送通知，不保存提醒记录
        verify(notificationService, never()).createNotification(any());
        verify(reminderRepository, never()).save(any());
    }

    // ==================== 边界条件测试 ====================

    /**
     * 测试无 PROCESSING 记录时跳过
     */
    @Test
    void testNoProcessingRecords_Skips() {
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.emptyList());

        approvalTimeoutJob.checkApprovalTimeout();

        verifyNoInteractions(flowRepository);
    }

    /**
     * 测试流程配置不存在时跳过
     */
    @Test
    void testFlowNotFound_Skips() {
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.singletonList(testRecord));
        when(flowRepository.findById(1L)).thenReturn(Optional.empty());

        approvalTimeoutJob.checkApprovalTimeout();

        verify(recordRepository, never()).save(any());
    }

    /**
     * 测试超时动作为空时默认ESCALATE
     */
    @Test
    void testNullTimeoutAction_DefaultsToEscalate() {
        testRecord.setCreatedAt(LocalDateTime.now().minusHours(25));
        testFlow.setTimeoutAction(null);
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.singletonList(testRecord));
        when(flowRepository.findById(1L)).thenReturn(Optional.of(testFlow));

        SysUserEntity currentApprover = new SysUserEntity();
        currentApprover.setId(200L);
        currentApprover.setDepartmentId(10L);
        when(userRepository.findById(200L)).thenReturn(Optional.of(currentApprover));

        SysDepartment dept = new SysDepartment();
        dept.setId(10L);
        dept.setParentId(null);
        when(departmentRepository.findById(10L)).thenReturn(Optional.of(dept));
        when(userRepository.findByDepartmentIdAndStatusNot(10L, "FROZEN")).thenReturn(Collections.emptyList());

        // 执行
        approvalTimeoutJob.checkApprovalTimeout();

        // 验证：执行了升级流程（会找超级管理员作为兜底）
        verify(userRepository).findByDepartmentIdAndStatusNot(10L, "FROZEN");
    }

    /**
     * 测试手动触发超时检测
     */
    @Test
    void testManualCheckTimeout() {
        when(recordRepository.findByStatus("PROCESSING")).thenReturn(Collections.emptyList());

        approvalTimeoutJob.manualCheckTimeout();

        verify(recordRepository).findByStatus("PROCESSING");
    }
}