package cn.meowrain.aioj.backend.blogservice.service.impl;

import cn.meowrain.aioj.backend.blogservice.dao.entity.Notification;
import cn.meowrain.aioj.backend.blogservice.dto.req.NotificationQueryRequestDTO;
import cn.meowrain.aioj.backend.blogservice.dto.resp.NotificationResponseDTO;
import cn.meowrain.aioj.backend.blogservice.service.NotificationService;
import cn.meowrain.aioj.backend.framework.core.utils.ContextHolderUtils;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 通知服务实现类
 *
 * @author AIOJ
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class NotificationServiceImpl extends ServiceImpl<Notification, Notification> implements NotificationService {

    @Override
    public IPage<NotificationResponseDTO> getNotificationList(NotificationQueryRequestDTO request) {
        Long currentUserId = ContextHolderUtils.getCurrentUserId();

        Page<Notification> page = new Page<>(request.getCurrent(), request.getSize());

        LambdaQueryWrapper<Notification> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Notification::getUserId, currentUserId);

        if (request.getType() != null) {
            queryWrapper.eq(Notification::getType, request.getType());
        }
        if (request.getIsRead() != null) {
            queryWrapper.eq(Notification::getIsRead, request.getIsRead());
        }

        queryWrapper.orderByDesc(Notification::getCreateTime);

        IPage<Notification> notificationPage = this.page(page, queryWrapper);

        Page<NotificationResponseDTO> resultPage = new Page<>(notificationPage.getCurrent(), notificationPage.getSize(), notificationPage.getTotal());
        List<NotificationResponseDTO> records = notificationPage.getRecords().stream()
                .map(notification -> BeanUtil.copyProperties(notification, NotificationResponseDTO.class))
                .collect(Collectors.toList());
        resultPage.setRecords(records);

        return resultPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean markAsRead(Long notificationId) {
        Long currentUserId = ContextHolderUtils.getCurrentUserId();

        Notification notification = this.getById(notificationId);
        if (notification == null || !notification.getUserId().equals(currentUserId)) {
            return false;
        }

        notification.setIsRead(1);
        this.updateById(notification);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchMarkAsRead(List<Long> notificationIds) {
        Long currentUserId = ContextHolderUtils.getCurrentUserId();

        List<Notification> notifications = this.listByIds(notificationIds);
        for (Notification notification : notifications) {
            if (notification.getUserId().equals(currentUserId)) {
                notification.setIsRead(1);
                this.updateById(notification);
            }
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean markAllAsRead() {
        Long currentUserId = ContextHolderUtils.getCurrentUserId();

        this.lambdaUpdate()
                .eq(Notification::getUserId, currentUserId)
                .eq(Notification::getIsRead, 0)
                .set(Notification::getIsRead, 1)
                .update();

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean clearAllNotifications() {
        Long currentUserId = ContextHolderUtils.getCurrentUserId();

        this.lambdaUpdate()
                .eq(Notification::getUserId, currentUserId)
                .remove();

        return true;
    }

    @Override
    public Long getUnreadCount() {
        Long currentUserId = ContextHolderUtils.getCurrentUserId();

        return this.lambdaQuery()
                .eq(Notification::getUserId, currentUserId)
                .eq(Notification::getIsRead, 0)
                .count();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createNotification(Long userId, Integer type, String title, String content,
                                   String linkUrl, Long senderId, Long targetId) {
        Notification notification = new Notification()
                .setUserId(userId)
                .setType(type)
                .setTitle(title)
                .setContent(content)
                .setLinkUrl(linkUrl)
                .setSenderId(senderId)
                .setTargetId(targetId)
                .setIsRead(0);
        this.save(notification);

        return notification.getId();
    }
}
