package com.reading.platform.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.reading.platform.common.enums.ErrorCode;
import com.reading.platform.common.exception.BusinessException;
import com.reading.platform.common.util.PageUtils;
import com.reading.platform.entity.Notification;
import com.reading.platform.mapper.NotificationMapper;
import com.reading.platform.service.NotificationService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;

@Service
@RequiredArgsConstructor
public class NotificationServiceImpl implements NotificationService {

    private final NotificationMapper notificationMapper;

    @Override
    @Transactional
    public Notification createNotification(Long tenantId, Long senderId, String senderRole, String title,
                                            String content, String type, String recipientType, Long recipientId) {
        Notification notification = new Notification();
        notification.setTenantId(tenantId);
        notification.setTitle(title);
        notification.setContent(content);
        notification.setType(type);
        notification.setSenderId(senderId);
        notification.setSenderRole(senderRole);
        notification.setRecipientType(recipientType);
        notification.setRecipientId(recipientId);
        notification.setIsRead(0);

        notificationMapper.insert(notification);
        return notification;
    }

    @Override
    public Notification getNotificationById(Long id) {
        Notification notification = notificationMapper.selectById(id);
        if (notification == null) {
            throw new BusinessException(ErrorCode.DATA_NOT_FOUND, "Notification not found");
        }
        return notification;
    }

    @Override
    public Page<Notification> getNotificationPage(Long tenantId, Integer pageNum, Integer pageSize, String type, Integer isRead) {
        Page<Notification> page = PageUtils.of(pageNum, pageSize);
        LambdaQueryWrapper<Notification> wrapper = new LambdaQueryWrapper<>();

        wrapper.eq(Notification::getTenantId, tenantId);

        if (type != null && !type.isEmpty()) {
            wrapper.eq(Notification::getType, type);
        }
        if (isRead != null) {
            wrapper.eq(Notification::getIsRead, isRead);
        }
        wrapper.orderByDesc(Notification::getCreatedAt);

        return notificationMapper.selectPage(page, wrapper);
    }

    @Override
    public Page<Notification> getMyNotifications(Long recipientId, String recipientType, Integer pageNum, Integer pageSize, Integer isRead) {
        Page<Notification> page = PageUtils.of(pageNum, pageSize);
        LambdaQueryWrapper<Notification> wrapper = new LambdaQueryWrapper<>();

        wrapper.and(w -> w
                .eq(Notification::getRecipientType, "all")
                .or()
                .eq(Notification::getRecipientId, recipientId)
        );

        if (isRead != null) {
            wrapper.eq(Notification::getIsRead, isRead);
        }
        wrapper.orderByDesc(Notification::getCreatedAt);

        return notificationMapper.selectPage(page, wrapper);
    }

    @Override
    @Transactional
    public void markAsRead(Long id) {
        Notification notification = getNotificationById(id);
        notification.setIsRead(1);
        notification.setReadAt(LocalDateTime.now());
        notificationMapper.updateById(notification);
    }

    @Override
    @Transactional
    public void markAllAsRead(Long recipientId, String recipientType) {
        notificationMapper.update(null,
                new LambdaUpdateWrapper<Notification>()
                        .set(Notification::getIsRead, 1)
                        .set(Notification::getReadAt, LocalDateTime.now())
                        .eq(Notification::getIsRead, 0)
                        .and(w -> w
                                .eq(Notification::getRecipientType, "all")
                                .or()
                                .eq(Notification::getRecipientId, recipientId)
                        )
        );
    }

    @Override
    @Transactional
    public void deleteNotification(Long id) {
        getNotificationById(id);
        notificationMapper.deleteById(id);
    }

    @Override
    public Long getUnreadCount(Long recipientId, String recipientType) {
        return notificationMapper.selectCount(
                new LambdaQueryWrapper<Notification>()
                        .eq(Notification::getIsRead, 0)
                        .and(w -> w
                                .eq(Notification::getRecipientType, "all")
                                .or()
                                .eq(Notification::getRecipientId, recipientId)
                        )
        );
    }

}
