package com.zsc.edu.gateway.modules.notice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zsc.edu.gateway.framework.message.email.EmailSender;
import com.zsc.edu.gateway.framework.message.sms.SmsSender;
import com.zsc.edu.gateway.framework.security.UserDetailsImpl;
import com.zsc.edu.gateway.modules.attachment.service.AttachmentService;
import com.zsc.edu.gateway.modules.notice.dto.UserMessageDto;
import com.zsc.edu.gateway.modules.notice.entity.*;
import com.zsc.edu.gateway.modules.notice.query.UserMessageQuery;
import com.zsc.edu.gateway.modules.notice.repo.MessageRepository;
import com.zsc.edu.gateway.modules.notice.repo.MessageSettingRepository;
import com.zsc.edu.gateway.modules.notice.repo.UserMessageRepository;
import com.zsc.edu.gateway.modules.notice.service.MessageAttachmentService;
import com.zsc.edu.gateway.modules.notice.service.UserMessageService;
import com.zsc.edu.gateway.modules.notice.vo.UserMessageVo;
import com.zsc.edu.gateway.modules.system.entity.User;
import com.zsc.edu.gateway.modules.system.service.UserService;
import lombok.AllArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;


/**
 * 用户消息Service
 *
 * @author harry_yao
 */
@AllArgsConstructor
@Service
public class UserMessageServiceImpl extends ServiceImpl<UserMessageRepository, UserMessage> implements UserMessageService {

    private final MessageRepository messageRepo;
    private final MessageSettingRepository messageSettingRepo;
    private final UserService userService;
    private final AttachmentService attachmentService;
    private final EmailSender emailSender;
    private final SmsSender smsSender;
    private final UserMessageRepository userMessageRepository;
    private final MessageAttachmentService messageAttachmentService;

    /**
     * 查询消息详情
     *
     * @param messageId 消息ID
     * @param userId    用户ID
     * @return 查询详情
     */

    @Override
    public UserMessageVo detail(Long messageId, Long userId) {
        return userMessageRepository.selectByMessageIdAndUserId(messageId, userId);
    }

    /**
     * 分页查询用户消息
     *
     * @param query 查询表单
     * @param page  分页参数
     * @return 页面数据
     */
    @Override
    public IPage<UserMessageVo> page(Page<UserMessageVo> page, UserMessageQuery query) {
        return userMessageRepository.query(page, query);
    }

    /**
     * 统计用户未读消息数量
     *
     * @param userDetails 操作用户
     * @return 未读消息数量
     */
    @Override
    public Integer countUnread(UserDetailsImpl userDetails) {
        QueryWrapper<UserMessage> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userDetails.getId()).eq("is_read", true);
        return Math.toIntExact(userMessageRepository.selectCount(queryWrapper));
    }

    /**
     * 设为已读
     *
     * @param userDetails 操作用户
     * @param messageIds  消息ID集合，如为空，则将该用户的所有未读消息设为已读
     * @return 修改记录数量
     */
    @Override
    public Integer markAsRead(UserDetailsImpl userDetails, List<Long> messageIds) {
        if (CollectionUtils.isEmpty(messageIds)) {
            throw new RuntimeException("messageIds is NULL!");
        }
        UpdateWrapper<UserMessage> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("user_id", userDetails.getId()).in("message_id", messageIds);
        updateWrapper.set("is_read", false);
        updateWrapper.set("read_time", LocalDateTime.now());
        return userMessageRepository.update(updateWrapper);
    }


    /**
     * 管理员手动创建用户消息并发送
     *
     * @param dto 表单数据
     * @return 创建的用户消息列表
     */
    @Transactional
    @Override
    public Boolean createByAdmin(UserMessageDto dto) {
        Set<User> users = dto.userIds.stream()
                .map(userService::getById)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());
        if (users.isEmpty()) {
            throw new RuntimeException("No valid users found for the provided userIds.");
        }
        Message message = new Message(dto.type, false, dto.email, dto.sms, dto.html,
                dto.title, dto.content, null);
        messageRepo.insert(message);
        Set<UserMessage> userMessages = users.stream()
                .map(user -> new UserMessage(null, user.getId(), message.getId(), false, null))
                .collect(Collectors.toSet());
        send(users, message);
        return saveBatch(userMessages);
    }


    /**
     * 将附件关联信息插入数据库
     *
     * @param messageId     消息ID，用于关联消息和附件
     * @param attachmentIds 附件ID列表，表示需要插入的附件
     * @return 返回一个布尔值，表示批量插入是否成功
     */
    @Override
    public Boolean insertInto(Long messageId, List<String> attachmentIds) {
        List<MessageAttachment> messageAttachments = attachmentIds.stream()
                .map(attachmentId -> new MessageAttachment(messageId, attachmentId))
                .collect(Collectors.toList());
        return messageAttachmentService.saveBatch(messageAttachments);
    }

    /**
     * 获取所有消息推送方式
     *
     * @return 消息设置列表
     */
    @Override
    public List<MessageSetting> getSetting() {
        return messageSettingRepo.findAll();
    }

    /**
     * 设置消息推送方式
     *
     * @param settings 消息设置集合
     * @return 消息设置列表
     */
    @Transactional
    @Override
    public List<MessageSetting> saveSetting(List<MessageSetting> settings) {
        if (CollectionUtils.isEmpty(settings)) {
            throw new RuntimeException("settings is NULL!");
        }
        for (MessageSetting setting : settings) {
            try {
                messageSettingRepo.insert(setting);
            } catch (Exception e) {
                throw new RuntimeException("设置失败" + e.getMessage());
            }
        }
        return settings;
    }


    /**
     * 以邮件、短信等形式发送消息，只有非html格式的消息才能以短信方式发送
     *
     * @param users   接收者
     * @param message 消息
     */
    @Async
    void send(Set<User> users, Message message) {
        if (message.email) {
            emailSender.send(users.stream().map(User::getEmail).collect(Collectors.toSet()), message);
        }
        if (message.sms && !message.html) {
            smsSender.send(users.stream().map(User::getPhone).collect(Collectors.toSet()), message.content);
        }
    }


    /**
     * 系统自动创建用户消息并发送
     *
     * @param receivers 接收者
     * @param payload   消息内容
     */
    @Transactional
    public Boolean createBySystem(Set<User> receivers, MessagePayload payload) {
        AtomicBoolean email = new AtomicBoolean(false);
        AtomicBoolean sms = new AtomicBoolean(false);
        Optional.of(messageSettingRepo.selectById(payload.type)).ifPresent(messageSetting -> {
            email.set(messageSetting.email);
            sms.set(messageSetting.sms);
        });
        Message message = new Message(payload.type, true, email.get(), sms.get(),
                payload.html, payload.type.name(), payload.content, null);
        messageRepo.insert(message);
        Set<UserMessage> userMessages = receivers.stream().map(user ->
                new UserMessage(null, user.getId(), message.getId(), false, null)).collect(Collectors.toSet());
        send(receivers, message);
        return saveBatch(userMessages);
    }

}
