package com.tourism.webadmin.app.website.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.page.PageMethod;
import com.tourism.common.additional.config.ApplicationConfig;
import com.tourism.common.core.annotation.DisableDataFilter;
import com.tourism.common.core.annotation.MyRequestBody;
import com.tourism.common.core.constant.ErrorCodeEnum;
import com.tourism.common.core.object.*;
import com.tourism.common.core.upload.BaseUpDownloader;
import com.tourism.common.core.upload.UpDownloaderFactory;
import com.tourism.common.core.upload.UploadResponseInfo;
import com.tourism.common.core.upload.UploadStoreInfo;
import com.tourism.common.core.util.MyModelUtil;
import com.tourism.common.core.util.MyPageUtil;
import com.tourism.common.log.annotation.OperationLog;
import com.tourism.common.log.model.constant.SysOperationLogType;
import com.tourism.common.redis.cache.SessionCacheHelper;
import com.tourism.webadmin.app.website.dto.DelMessageDto;
import com.tourism.webadmin.app.website.dto.SystemMessageDTO;
import com.tourism.webadmin.app.website.service.TourGroupService;
import com.tourism.webadmin.app.website.service.TourMessageService;
import com.tourism.webadmin.app.website.vo.GroupMessageVo;
import com.tourism.webadmin.app.website.vo.InteractionListVo;
import com.tourism.webadmin.back.dto.TourImMessageDto;
import com.tourism.webadmin.back.model.TourFans;
import com.tourism.webadmin.back.model.TourImComplait;
import com.tourism.webadmin.back.model.TourImGroup;
import com.tourism.webadmin.back.model.TourImMessage;import com.tourism.webadmin.back.model.constant.NoticeType;
import com.tourism.webadmin.back.service.TourFansService;
import com.tourism.webadmin.back.service.TourImMessageService;
import com.tourism.webadmin.back.vo.TourImMessageVo;
import com.tourism.webadmin.back.vo.TourUserVo;
import com.tourism.webadmin.enums.MyAttentionStatus;
import com.tourism.webadmin.enums.SystemDefaultHead;
import com.tourism.webadmin.strategy.dto.FocusDTO;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static cn.dev33.satoken.log.SaLogForConsole.info;

/**
 *聊天群聊消息操作
 * @author 大春
 * @date 2025/01/04
 */
@Tag(name = "聊天群聊消息操作")
@RestController
@DisableDataFilter
@Slf4j
@RequestMapping("/website/tourMessage")
public class TourMessageController {

    @Autowired
    private TourMessageService tourMessageService;
    @Autowired
    private  TourImMessageService tourImMessageService;
    @Autowired
    private UpDownloaderFactory upDownloaderFactory;
    @Autowired
    private ApplicationConfig appConfig;
    @Autowired
    private SessionCacheHelper cacheHelper;
    @Autowired
    private TourGroupService tourGroupService;
    @Autowired
    private TourFansService tourFansService;

    /**
     * 是否有未读消息。
     *
     * @return 应答结果对象，包含查询结果集。
     */
    @GetMapping("/hasUnreadMessage")
    public ResponseResult<Boolean> hasUnreadMessage() {

        Long userId = TokenData.takeFromRequest().getUserId();
        QueryWrapper<TourImMessage> tourImMessageQueryWrapper = new QueryWrapper<>();
        tourImMessageQueryWrapper.notInSql("id","select id from  tour_im_message where read_by_users not like concat('%',"+userId+",'%')");
        tourImMessageQueryWrapper.inSql("group_id", "select group_id from tour_im_member where user_id = " + userId);
        tourImMessageQueryWrapper.lambda()
                .eq(TourImMessage::getNoticeType, NoticeType.NOTICE_GROUP)
                .last("limit 1");
        List<TourImMessage> list = tourMessageService.list(tourImMessageQueryWrapper);
        Boolean b = null;
        if (list!=null && !list.isEmpty()) b=true;
        if (list!=null && list.isEmpty()) b=false;
        return ResponseResult.success(b);
    }


    /**
     *  根据群ID查询群聊消息
     * @param groupId
     * @return {@link ResponseResult }<{@link List }<{@link GroupMessageVo }>>
     */
    @GetMapping("/getMessageByGroupId")
    public ResponseResult<Map<String,Object>> getMessageByGroupId(Long messageId, Long groupId, Integer pageSize, String searchMessage){
        TourImGroup group = tourGroupService.getById(groupId);
        if(ObjectUtil.isEmpty(group)){
            return ResponseResult.error("500","该群组不存在");
        }
        HashMap<String, Object> messageByGroupId = tourMessageService.getMessageByGroupId(messageId, group, pageSize, searchMessage);
        return ResponseResult.success(messageByGroupId);
    }
    /**
     *  根据群ID查询群聊消息历史
     * @param groupId
     * @return {@link ResponseResult }<{@link List }<{@link GroupMessageVo }>>
     */
    @GetMapping("/getMessageByGroupIdPage")
    public ResponseResult<MyPageData> getMessageByGroupIdPage( Long groupId,Integer pageNum ,Integer pageSize, String searchMessage,Integer messageType){
        TourImGroup group = tourGroupService.getById(groupId);
        if(ObjectUtil.isEmpty(group)){
            return ResponseResult.error("500","该群组不存在");
        }
        MyPageData messageByGroupId = tourMessageService.getMessageByGroupIdPage(group,pageNum,pageSize,searchMessage,messageType);
        return ResponseResult.success(messageByGroupId);
    }

    /**
     * 用户删除消息
     */
    @PostMapping("/delMessage")
    public ResponseResult<Void> delMessage(@RequestBody DelMessageDto params){
        tourMessageService.delMessage(params);
        return ResponseResult.success();
    }
    /**
     * 撤回消息
     */
    @PostMapping("/withdrawMessage")
    public ResponseResult<Void> withdrawMessage(@RequestBody DelMessageDto params){
        tourMessageService.withdrawMessage(params);
        return ResponseResult.success();
    }

    /**
     * 修改当前群聊消息为已读
     */
    @GetMapping("/updateRead")
    public ResponseResult<Void> updateRead(Long groupId){
        tourMessageService.updateRead(groupId);
        return ResponseResult.success();
    }

    /**设置群消息置顶*/
    @GetMapping("/topUpGroupMessage")
    public ResponseResult<Void> topUpGroupMessage(Long messageId){
        tourMessageService.topUpGroupMessage(messageId);
        return ResponseResult.success();
    }

    /**清空聊天记录*/
    @GetMapping("/clearGroupMessage")
    public ResponseResult<Void> clearGroupMessage(Long groupId){
        tourMessageService.clearGroupMessage(groupId);
        return ResponseResult.success();
    }


    /**
     * 列出符合过滤条件的聊天群聊消息列表。
     *
     * @param tourImMessageDtoFilter 过滤对象。
     * @param pageParam 分页参数。
     * @return 应答结果对象，包含查询结果集。
     */
    @SaCheckPermission("tourImMessage.view")
    @PostMapping("/list")
    public ResponseResult<MyPageData<TourImMessageVo>> list(
            @MyRequestBody TourImMessageDto tourImMessageDtoFilter,
            @MyRequestBody MyPageParam pageParam) {
        if (pageParam != null) {
            PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize(), pageParam.getCount());
        }
        TourImMessage tourImMessageFilter = MyModelUtil.copyTo(tourImMessageDtoFilter, TourImMessage.class);
        MyOrderParam orderInfos = new MyOrderParam();
        orderInfos.add(new MyOrderParam.OrderInfo("create_time",false,null));
        String orderBy = MyOrderParam.buildOrderBy(orderInfos, TourImMessage.class);
        List<TourImMessage> tourImMessageList =
                tourImMessageService.getTourImMessageListWithRelation(tourImMessageFilter, orderBy);
        return ResponseResult.success(MyPageUtil.makeResponseData(tourImMessageList, TourImMessageVo.class));
    }

    /**
     * 文件上传操作。
     *
     * @param fieldName  上传文件名。
     * @param asImage    是否作为图片上传。如果是图片，今后下载的时候无需权限验证。否则就是附件上传，下载时需要权限验证。
     * @param uploadFile 上传文件对象。
     */
    @OperationLog(type = SysOperationLogType.UPLOAD, saveResponse = false)
    @PostMapping("/upload")
    public void upload(
            @RequestParam String fieldName,
            @RequestParam Boolean asImage,
            @RequestParam("uploadFile") MultipartFile uploadFile) throws IOException {
        long size = 0;
        String remark = "";
        if (asImage){
            size=1024*1024*10;
            remark="图片大小不能超过10M";
        }else {
            size=1024*1024*20;
            remark="文件大小不能超过20M";
        }
        if(uploadFile.getSize()>size){
            ResponseResult.output(HttpServletResponse.SC_FORBIDDEN,
                    ResponseResult.error(ErrorCodeEnum.INVALID_UPLOAD_FILE_IOERROR, remark));
            return;
        }
        String type = FileTypeUtil.getType(uploadFile.getInputStream());
        if(!"jpg".equals(type)&&!"png".equals(type)){

        }
        UploadStoreInfo storeInfo = MyModelUtil.getUploadStoreInfo(TourImMessage.class, fieldName);
        // 根据字段注解中的存储类型，通过工厂方法获取匹配的上传下载实现类，从而解耦。
        BaseUpDownloader upDownloader = upDownloaderFactory.get(storeInfo.getStoreType());
        UploadResponseInfo responseInfo = upDownloader.doUpload(null,
                appConfig.getUploadFileBaseDir(), TourImComplait.class.getSimpleName(), fieldName, asImage, uploadFile);
        if (Boolean.TRUE.equals(responseInfo.getUploadFailed())) {
            ResponseResult.output(HttpServletResponse.SC_FORBIDDEN,
                    ResponseResult.error(ErrorCodeEnum.UPLOAD_FAILED, responseInfo.getErrorMessage()));
            return;
        }
        cacheHelper.putSessionUploadFile(responseInfo.getFilename());
        ResponseResult.output(ResponseResult.success(responseInfo));
    }

    /**
     *  编辑公告
     * @return {@link ResponseResult }<{@link Boolean }>
     */
    @PostMapping("/updateAnnouncement")
    public ResponseResult<Boolean> updateAnnouncement(@RequestBody TourImMessage tourImMessage){
        Long userId = TokenData.takeFromRequest().getUserId();
        boolean admin = tourGroupService.isAdmin(tourImMessage.getGroupId(),userId);
        //不是管理员
        if(!admin) return ResponseResult.error("500","您不是管理员新增失败");
        boolean b=tourMessageService.updateAnnouncement(tourImMessage,userId);
        return ResponseResult.success(b);
    }


    /**
     * 获取系统或者关注消息列表
     * @param noticeType   3系统消息 4关注信息
     * @return {@link ResponseResult }<{@link List }<{@link TourImMessageVo }>>
     *     1.单聊消息 2 群聊消息 3系统消息 4关注信息 5点赞 6评论 7评论区艾特 8文章内艾特 9访问
     */
    @GetMapping("/getsListSystemAndFocusMessages")
    public ResponseResult<MyPageData<TourImMessageVo>> getsListSystemAndFocusMessages(Long noticeType,Integer pageNum,Integer pageSize){
        Long userId = TokenData.takeFromRequest().getUserId();
        ArrayList<Long> types = new ArrayList<>();
        types.add(noticeType);

        //分页
        if (pageNum==null) pageNum=1;
        if (pageSize==null) pageSize=10;
        PageHelper.startPage(pageNum, pageSize);

        //查询全部系统消息
        List<TourImMessage> messageList = tourMessageService.lambdaQuery()
                .in(TourImMessage::getNoticeType,types)
                .like(TourImMessage::getMessageContent, "\""+"getUserId"+"\""+":"+"\""+userId.toString()+"\"")
                .orderByDesc(TourImMessage::getCreateTime)
                .list();
        MyPageData<TourImMessageVo> pageData = MyPageUtil.makeResponseData(messageList, TourImMessageVo.class);
        List<TourImMessageVo> vo = pageData.getDataList();
        ArrayList<TourImMessageVo> messageVo = new ArrayList<>();
        ArrayList<Long> userIds = new ArrayList<>();

        //封装结果集合
        for (TourImMessageVo info : vo) {
            String messageContent = info.getMessageContent();
            //系统消息
            if (info.getNoticeType() == NoticeType.NOTICE_SYSTEM){
                SystemMessageDTO bean = JSONUtil.toBean(messageContent, SystemMessageDTO.class);
                //接收人是登录用户的
                if (userId.toString().equals(bean.getGetUserId())) {
                    messageVo.add(info);
                }
                info.setAvatar(SystemDefaultHead.SYSTEM_USERID_OR_GROUPID.getHead());
            }
            //关注消息
            if (info.getNoticeType() == NoticeType.NOTICE_FOCUS){

                FocusDTO bean = JSON.parseObject(info.getMessageContent(), FocusDTO.class);
                TourUserVo tourUserVo = bean.getTourUserVo();
                if (tourUserVo != null) {
                    userIds.add(Long.parseLong(tourUserVo.getUserId()));
                }
                //接收人是登录用户的
                if (userId.toString().equals(bean.getGetUserId())) {
                    messageVo.add(info);
                }
                info.setAvatar(SystemDefaultHead.FOCUS_USERID_OR_GROUPID.getHead());
            }
        }
        //填充每个用户的关注状态
        List<Long> status =null;
        if (noticeType==NoticeType.NOTICE_FOCUS){
            status = this.attentionStatus(userIds);
        }
        for (int i = 0; i < messageVo.size(); i++) {
            TourImMessageVo tour = messageVo.get(i);
            FocusDTO bean = JSON.parseObject(tour.getMessageContent(), FocusDTO.class);
            if (userId.toString().equals(bean.getGetUserId())){
               if (status!=null) tour.setFocusStatus(status.get(i).intValue());
            }
            String messageContent = tour.getMessageContent();
            tour.setMessagePO(JSON.parseObject(messageContent));
        }
        pageData.setTotalCount(Long.valueOf(messageList.size()));
        return ResponseResult.success(pageData);
    }


    public List<Long> attentionStatus(List<Long> userIds) {
        //用户id
        Long myId = TokenData.takeFromRequest().getUserId();
        // 我的粉丝列表  attentionId = currentUserId
        List<TourFans> myFansList = tourFansService.list(
                new LambdaQueryWrapper<TourFans>().eq(TourFans::getAttentionId, myId).eq(TourFans::getDeleteFlag, 1)
        );
        //我的关注列表  createUserId = currentUserId
        List<TourFans> myFocusList = tourFansService.list(
                new LambdaQueryWrapper<TourFans>().eq(TourFans::getCreateUserId, myId).eq(TourFans::getDeleteFlag, 1)
        );
        //关注列表用户ids
        Set<Long> myFocusIds = myFocusList.stream()
                .map(TourFans::getAttentionId)
                .collect(Collectors.toSet());
        //粉丝列表用户ids
        Set<Long> myFansIds = myFansList.stream()
                .map(TourFans::getCreateUserId)
                .collect(Collectors.toSet());
        // 关注状态填充

        ArrayList<Long> longs = new ArrayList<>();
        userIds.forEach(userId->{
            Long status = null;
            if (userId.toString().equals(myId.toString())){
                status = MyAttentionStatus.MYSELF;// 自己
            }else if(myFocusIds.contains(userId) && myFansIds.contains(userId)) {
                status =MyAttentionStatus.FOCUS_EACH; // 互关
            } else if (myFansIds.contains(userId)&& !myFocusIds.contains(userId)) {
                status =MyAttentionStatus.BE_FOCUSED; // 他关注了我
            }else if (myFocusIds.contains(userId)) {
                status =MyAttentionStatus.FOCUS_EACH;// 已关注
            } else {
                status =MyAttentionStatus.UN_FOCUS;  // 未关注
            }
            longs.add(status);
        });

        return longs;
    }


    /**
     *  互动消息列表
     * @param noticeType -1全部 5赞与收藏 6提及  7收到的评论 8发出的评论
     * @return {@link ResponseResult }<{@link Boolean }>
     */
    @GetMapping("/getInteractionList")
    public ResponseResult<MyPageData<InteractionListVo>> getInteractionList(String noticeType,Integer pageNum,Integer pageSize){
        //登录ID
        Long userId = TokenData.takeFromRequest().getUserId();
        MyPageData<InteractionListVo> list=tourMessageService.getInteractionList(noticeType,userId,pageNum,pageSize);
        if (list.getTotalCount()==null) list.setTotalCount(0L);
        return ResponseResult.success(list);
    }


    /**
     *  获取最新的消息
     * @param groupId 群ID
     * @param messageId 消息ID
     * @return {@link ResponseResult }<{@link TourImMessageVo }>
     */
    @GetMapping("/getLatestMessage")
    public ResponseResult<List<GroupMessageVo>> getLatestMessage(String groupId,String messageId){
        List<GroupMessageVo> tourImMessageVo = tourMessageService.getLatestMessage(groupId,messageId);
        return ResponseResult.success(tourImMessageVo);
    }

}
