package com.aegis.notification.service.impl;

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

import java.util.HashSet;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import com.aegis.common.core.domain.entity.SysUser;
import com.aegis.common.core.domain.model.LoginUser;
import com.aegis.common.exception.ServiceException;
import com.aegis.notification.domain.Notification;
import com.aegis.notification.mapper.NotificationMapper;
import com.aegis.notification.mapper.NotificationTemplateMapper;
import com.aegis.notification.service.channel.INotificationChannel;
import com.aegis.system.service.ISysUserService;

/**
 * 通知服务实现类单元测试
 * 重点测试批量删除功能
 * 
 * @author aegis
 */
@ExtendWith(MockitoExtension.class)
class NotificationServiceImplTest {

    @Mock
    private NotificationMapper notificationMapper;

    @Mock
    private NotificationTemplateMapper templateMapper;

    @Mock
    private ISysUserService userService;

    @Mock
    private java.util.List<INotificationChannel> channels;

    @InjectMocks
    private NotificationServiceImpl notificationService;

    private Long testReceiverId = 100L;
    private Long testOtherUserId = 200L;

    @BeforeEach
    void setUp() {
        // 配置 SecurityContext，模拟用户登录
        setupSecurityContext();
    }

    /**
     * 配置 SecurityContext，模拟用户登录
     */
    private void setupSecurityContext() {
        // 创建模拟用户
        SysUser sysUser = new SysUser();
        sysUser.setUserId(testReceiverId);
        sysUser.setUserName("testUser");
        sysUser.setNickName("测试用户");

        // 创建 LoginUser
        LoginUser loginUser = new LoginUser(testReceiverId, testReceiverId, sysUser, new HashSet<>());

        // 设置到 SecurityContext
        UsernamePasswordAuthenticationToken authentication = 
            new UsernamePasswordAuthenticationToken(loginUser, null, null);
        SecurityContextHolder.getContext().setAuthentication(authentication);
    }

    // ========== 批量删除通知测试 ==========

    /**
     * 测试批量删除通知 - 成功场景
     */
    @Test
    void testDeleteBatchNotification_Success() {
        // Given
        Long[] notificationIds = {1L, 2L, 3L};
        
        // 创建模拟通知，都属于当前用户
        Notification notification1 = createMockNotification(1L, testReceiverId);
        Notification notification2 = createMockNotification(2L, testReceiverId);
        Notification notification3 = createMockNotification(3L, testReceiverId);
        
        when(notificationMapper.selectNotificationById(1L)).thenReturn(notification1);
        when(notificationMapper.selectNotificationById(2L)).thenReturn(notification2);
        when(notificationMapper.selectNotificationById(3L)).thenReturn(notification3);
        when(notificationMapper.deleteNotificationByIds(notificationIds)).thenReturn(3);

        // When
        int result = notificationService.deleteBatchNotification(notificationIds, testReceiverId);

        // Then
        assertEquals(3, result);
        verify(notificationMapper, times(1)).selectNotificationById(1L);
        verify(notificationMapper, times(1)).selectNotificationById(2L);
        verify(notificationMapper, times(1)).selectNotificationById(3L);
        verify(notificationMapper, times(1)).deleteNotificationByIds(notificationIds);
    }

    /**
     * 测试批量删除通知 - 通知不存在
     */
    @Test
    void testDeleteBatchNotification_NotificationNotFound() {
        // Given
        Long[] notificationIds = {1L, 2L};
        
        Notification notification1 = createMockNotification(1L, testReceiverId);
        
        when(notificationMapper.selectNotificationById(1L)).thenReturn(notification1);
        when(notificationMapper.selectNotificationById(2L)).thenReturn(null); // 通知不存在

        // When & Then
        ServiceException exception = assertThrows(ServiceException.class, () -> {
            notificationService.deleteBatchNotification(notificationIds, testReceiverId);
        });
        
        assertTrue(exception.getMessage().contains("通知ID=2不存在或无权删除"));
        verify(notificationMapper, times(1)).selectNotificationById(1L);
        verify(notificationMapper, times(1)).selectNotificationById(2L);
        verify(notificationMapper, never()).deleteNotificationByIds(any());
    }

    /**
     * 测试批量删除通知 - 无权删除（通知属于其他用户）
     */
    @Test
    void testDeleteBatchNotification_Unauthorized() {
        // Given
        Long[] notificationIds = {1L, 2L};
        
        Notification notification1 = createMockNotification(1L, testReceiverId);
        Notification notification2 = createMockNotification(2L, testOtherUserId); // 属于其他用户
        
        when(notificationMapper.selectNotificationById(1L)).thenReturn(notification1);
        when(notificationMapper.selectNotificationById(2L)).thenReturn(notification2);

        // When & Then
        ServiceException exception = assertThrows(ServiceException.class, () -> {
            notificationService.deleteBatchNotification(notificationIds, testReceiverId);
        });
        
        assertTrue(exception.getMessage().contains("通知ID=2不存在或无权删除"));
        verify(notificationMapper, times(1)).selectNotificationById(1L);
        verify(notificationMapper, times(1)).selectNotificationById(2L);
        verify(notificationMapper, never()).deleteNotificationByIds(any());
    }

    /**
     * 测试批量删除通知 - 部分通知不存在，部分无权删除
     */
    @Test
    void testDeleteBatchNotification_MixedErrors() {
        // Given
        Long[] notificationIds = {1L, 2L, 3L};
        
        Notification notification1 = createMockNotification(1L, testReceiverId); // 正常
        Notification notification2 = createMockNotification(2L, testOtherUserId); // 无权删除
        
        when(notificationMapper.selectNotificationById(1L)).thenReturn(notification1);
        when(notificationMapper.selectNotificationById(2L)).thenReturn(notification2);
        // notification3 不存在，会返回null

        // When & Then
        // 应该先检查到 notification2 的错误（因为循环顺序）
        ServiceException exception = assertThrows(ServiceException.class, () -> {
            notificationService.deleteBatchNotification(notificationIds, testReceiverId);
        });
        
        assertTrue(exception.getMessage().contains("通知ID=2不存在或无权删除"));
        verify(notificationMapper, times(1)).selectNotificationById(1L);
        verify(notificationMapper, times(1)).selectNotificationById(2L);
        verify(notificationMapper, never()).selectNotificationById(3L); // 因为前面已经抛异常了
        verify(notificationMapper, never()).deleteNotificationByIds(any());
    }

    /**
     * 测试批量删除通知 - 空数组（边界情况）
     */
    @Test
    void testDeleteBatchNotification_EmptyArray() {
        // Given
        Long[] notificationIds = {};

        // When
        int result = notificationService.deleteBatchNotification(notificationIds, testReceiverId);

        // Then
        assertEquals(0, result);
        verify(notificationMapper, never()).selectNotificationById(any());
        verify(notificationMapper, times(1)).deleteNotificationByIds(notificationIds);
    }

    /**
     * 测试批量删除通知 - 单个通知
     */
    @Test
    void testDeleteBatchNotification_SingleNotification() {
        // Given
        Long[] notificationIds = {1L};
        
        Notification notification1 = createMockNotification(1L, testReceiverId);
        
        when(notificationMapper.selectNotificationById(1L)).thenReturn(notification1);
        when(notificationMapper.deleteNotificationByIds(notificationIds)).thenReturn(1);

        // When
        int result = notificationService.deleteBatchNotification(notificationIds, testReceiverId);

        // Then
        assertEquals(1, result);
        verify(notificationMapper, times(1)).selectNotificationById(1L);
        verify(notificationMapper, times(1)).deleteNotificationByIds(notificationIds);
    }

    /**
     * 测试批量删除通知 - 大量通知（性能测试）
     */
    @Test
    void testDeleteBatchNotification_LargeBatch() {
        // Given
        Long[] notificationIds = new Long[100];
        for (int i = 0; i < 100; i++) {
            notificationIds[i] = (long) (i + 1);
            Notification notification = createMockNotification((long) (i + 1), testReceiverId);
            when(notificationMapper.selectNotificationById((long) (i + 1))).thenReturn(notification);
        }
        
        when(notificationMapper.deleteNotificationByIds(notificationIds)).thenReturn(100);

        // When
        int result = notificationService.deleteBatchNotification(notificationIds, testReceiverId);

        // Then
        assertEquals(100, result);
        verify(notificationMapper, times(100)).selectNotificationById(any());
        verify(notificationMapper, times(1)).deleteNotificationByIds(notificationIds);
    }

    /**
     * 创建模拟通知对象
     */
    private Notification createMockNotification(Long id, Long receiverId) {
        Notification notification = new Notification();
        notification.setId(id);
        notification.setReceiverId(receiverId);
        notification.setTitle("测试通知" + id);
        notification.setContent("测试内容");
        notification.setChannel("station");
        notification.setStatus("sent");
        notification.setDelFlag("0");
        return notification;
    }
}