package shop.alien.store.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import shop.alien.entity.store.*;
import shop.alien.entity.store.dto.LifeUserViolationDto;
import shop.alien.entity.store.excelVo.LifeUserOrderExcelVo;
import shop.alien.entity.store.excelVo.LifeUserViolationExcelVO;
import shop.alien.entity.store.excelVo.util.ExcelGenerator;
import shop.alien.entity.store.vo.LifeUserViolationVo;
import shop.alien.entity.store.vo.WebSocketVo;
import shop.alien.mapper.*;
import shop.alien.store.config.WebSocketProcess;
import shop.alien.store.service.*;
import shop.alien.store.util.FunctionMagic;
import shop.alien.util.ali.AliOSSUtil;
import shop.alien.util.common.JwtUtil;

import java.io.File;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static shop.alien.util.common.constant.Constant.*;


/**
 * <p>
 * 用户举报 服务实现类
 * </p>
 *
 * @author ssk
 * @since 2025-04-29
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class LifeUserViolationServiceImpl extends ServiceImpl<LifeUserViolationMapper, LifeUserViolation> implements LifeUserViolationService {

    private final LifeUserViolationMapper lifeUserViolationMapper;

    private final LifeUserMapper lifeUserMapper;

    private final StoreUserMapper storeUserMapper;

    private final LifeUserService lifeUserService;

    private final StoreUserService storeUserService;

    private final LifeUserDynamicsService lifeUserDynamicsService;

    private final StoreCommentService storeCommentService;

    private final LifeCommentMapper lifeCommentMapper;

    private final LifeNoticeMapper lifeNoticeMapper;

    private final WebSocketProcess webSocketProcess;

    private final AliOSSUtil aliOSSUtil;

    @Value("${spring.web.resources.excel-path}")
    private String excelPath;

    @Value("${spring.web.resources.excel-generate-path}")
    private String excelGeneratePath;

    @Override
    public int reporting(LifeUserViolation lifeuserViolation) throws Exception {
        try {
            int result = lifeUserViolationMapper.insert(lifeuserViolation);
            if (result > 0) {
                if (lifeuserViolation.getReportContextType().equals("4") || lifeuserViolation.getReportContextType().equals("5")) {
                    String phoneId = Objects.requireNonNull(JwtUtil.getCurrentUserInfo()).getString("userType") + "_" + JwtUtil.getCurrentUserInfo().getString("phone");

                    LifeNotice lifeNotice = getLifeNotice(lifeuserViolation);
                    lifeNoticeMapper.insert(lifeNotice);

                    WebSocketVo websocketVo = new WebSocketVo();
                    websocketVo.setSenderId("system");
                    websocketVo.setReceiverId(phoneId);
                    websocketVo.setCategory("notice");
                    websocketVo.setNoticeType("1");
                    websocketVo.setIsRead(0);
                    websocketVo.setText(com.alibaba.fastjson2.JSONObject.from(lifeNotice).toJSONString());
                    webSocketProcess.sendMessage(phoneId, com.alibaba.fastjson2.JSONObject.from(websocketVo).toJSONString());
                }
                return result;
            }
        } catch (Exception e) {
            log.error("LifeUserViolationServiceImpl_reporting Error Stack={}", e.getMessage());
            throw new Exception(e);
        }
        return 0;
    }

    private static LifeNotice getLifeNotice(LifeUserViolation lifeuserViolation) {
        JSONObject data = JwtUtil.getCurrentUserInfo();
        String phoneId = null;
        if (data != null) {
            phoneId = data.getString("phone");
        }
        LifeNotice lifeNotice = new LifeNotice();
        lifeNotice.setSenderId("system");
        lifeNotice.setReceiverId("user_" + phoneId);
        lifeNotice.setBusinessId(lifeuserViolation.getId());
        lifeNotice.setTitle("举报通知");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("title", "平台已受理");
        jsonObject.put("message", "平台已受理，感谢您的反馈！");
        lifeNotice.setContext(jsonObject.toJSONString());
        lifeNotice.setNoticeType(1);
        return lifeNotice;
    }

    @Override
    public Map<String, Object> reportListByUserId(String userId) {
        Map<String, Object> resultMap = new HashMap<String, Object>();
        LambdaUpdateWrapper<LifeUserViolation> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(LifeUserViolation::getReportingUserId, userId).orderByDesc(LifeUserViolation::getCreatedTime);
        List<LifeUserViolation> lifeUserViolations = lifeUserViolationMapper.selectList(wrapper);
        List<LifeUserViolation> filteredViolations = lifeUserViolations.stream().filter(violation -> !"0".equals(violation.getProcessingStatus())).collect(Collectors.toList());
        List<LifeUserViolationVo> lifeUserViolationsVo = new ArrayList<>();
        for (LifeUserViolation violation : filteredViolations) {
            LifeUserViolationVo vo = new LifeUserViolationVo();
            BeanUtils.copyProperties(violation, vo);
            lifeUserViolationsVo.add(vo);
        }
        lifeUserViolationsVo.forEach(lifeUserViolationVo -> {
            lifeUserViolationVo.setReportResultNotification("举报结果通知");
        });
        if (!lifeUserViolations.isEmpty()) {
            resultMap.put("createTime", lifeUserViolations.get(0).getCreatedTime());
            resultMap.put("data", lifeUserViolationsVo);
        }
        return resultMap;
    }

    @Override
    public Map<String, Object> reportListById(String id) {
        Map<String, Object> resultMap = new HashMap<String, Object>();
        LifeUserViolationVo lifeUserViolationVo = new LifeUserViolationVo();
        LifeUserViolation lifeUserViolation = lifeUserViolationMapper.selectById(id);
        //商户或者用户名称
        String storeOrUserName;
        if ("1".equals(lifeUserViolation.getReportedUserType())) {
            StoreUser storeUser = storeUserMapper.selectById(lifeUserViolation.getReportedUserId());
            storeOrUserName = storeUser.getName();
        } else {
            LifeUser lifeUser = lifeUserMapper.selectById(lifeUserViolation.getReportedUserId());
            storeOrUserName = lifeUser.getUserName();
        }
        resultMap.put("message", lifeUserViolation.getProcessingStatus() != null ? lifeUserViolation.getProcessingStatus() : "");
        lifeUserViolationVo.setReportObject(storeOrUserName);
        lifeUserViolationVo.setViolationType(lifeUserViolation.getViolationType());
        lifeUserViolationVo.setReportEvidenceImg(lifeUserViolation.getReportEvidenceImg());
        lifeUserViolationVo.setCreatedTime(lifeUserViolation.getCreatedTime());
        resultMap.put("reportDetail", lifeUserViolationVo);
        LifeUserViolationVo lifeUserViolationVo2 = new LifeUserViolationVo();
        lifeUserViolationVo2.setProcessingStatus(lifeUserViolation.getProcessingStatus());
        lifeUserViolationVo2.setProcessingTime(lifeUserViolation.getProcessingTime());
        resultMap.put("processStatus", lifeUserViolationVo);
        return resultMap;
    }

    @Override
    public IPage<LifeUserViolationDto> getViolationPage(int page, int size, String nickName, String phone, String processingStatus) {
        List<String> MIDs = storeUserService.getIds(nickName, phone);
        List<String> UIDs = lifeUserService.getIds(nickName, phone);
        boolean flag = FunctionMagic.isListFlag(MIDs, UIDs);
        IPage<LifeUserViolation> iPage = new Page<>(page, size);
        QueryWrapper<LifeUserViolation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotEmpty(processingStatus), PROCESSING_STATUS, processingStatus).and(flag, wrapper -> wrapper.nested(wq -> wq.eq(REPORTING_USER_TYPE, "1").in(!MIDs.isEmpty(), REPORTING_USER_ID, MIDs)).or(wq -> wq.eq(REPORTING_USER_TYPE, "2").in(!UIDs.isEmpty(), REPORTING_USER_ID, UIDs))).orderByDesc("updated_time");
        IPage<LifeUserViolation> resultPage = lifeUserViolationMapper.selectPage(iPage, queryWrapper);
        return resultPage.convert(e -> {
            LifeUserViolationDto dto = new LifeUserViolationDto();
            BeanUtils.copyProperties(e, dto);
            if (Objects.nonNull(e.getReportEvidenceImg())) {
                List<String> list = Arrays.stream(e.getReportEvidenceImg().split(",")).map(String::trim).collect(Collectors.toList());
                dto.setImage(list.get(0));
                dto.setImageList(list);
            }
            if (e.getReportingUserType().equals("1")) {
                // M
                StoreUser storeUser = storeUserService.getOne(new QueryWrapper<StoreUser>().eq("id", e.getReportingUserId()));
                if (storeUser == null) {
                    storeUser = storeUserMapper.getRemoveUser(e.getReportingUserId());
                }
                dto.setNickname(Objects.isNull(storeUser.getName()) ? "" : storeUser.getName());
                dto.setPhone(Objects.isNull(storeUser.getPhone()) ? "" : storeUser.getPhone());
            } else {
                // U
                LifeUser lifeUser = lifeUserService.getOne(new QueryWrapper<LifeUser>().eq("id", e.getReportingUserId()));
                if (lifeUser == null) {
                    lifeUser = lifeUserMapper.getRemoveUser(e.getReportingUserId());
                }
                dto.setNickname(Objects.isNull(lifeUser.getUserName()) ? "" : lifeUser.getUserName());
                dto.setPhone(Objects.isNull(lifeUser.getUserPhone()) ? "" : lifeUser.getUserPhone());
            }
            return dto;
        });
    }

    @Override
    public void approve(int id, String processingStatus, String reportResult) {
        LifeUserViolation v = lifeUserViolationMapper.selectById(id);
        v.setProcessingStatus(processingStatus);
        v.setProcessingTime(new Date());
        v.setReportResult(reportResult);
        StringBuilder b = new StringBuilder();
        if (processingStatus.equals("1")) {
            // 通过
            if (v.getReportContextType().equals("1")) {
                // 用户
                b.append("处理结果: 你的举报通过，已被处理 经核实，您举报的用户确实存在违规行为");
            }
            if (v.getReportContextType().equals("2")) {
                // 动态
                LifeUserDynamics dynamics = lifeUserDynamicsService.getById(v.getDynamicsId());
                b.append("处理结果: 你的举报通过，已被处理 经核实，您举报的动态'").append(dynamics.getContext()).append("' 确实存在违规行为，感谢您为社区环境做出的贡献。");
                lifeUserDynamicsService.removeById(v.getDynamicsId());
            }
            if (v.getReportContextType().equals("3")) {
                // 评论
                if (v.getReportedUserType().equals("1")) {
                    // 商户
                    StoreComment storeComment = storeCommentService.getById(v.getCommentId());
                    b.append("处理结果: 你的举报通过，已被处理 经核实，您举报的评论'").append(storeComment.getCommentContent()).append("'确实存在违规行为感谢您为社区环境做出的贡献。");
                    storeCommentService.removeById(v.getCommentId());
                } else {
                    // 用户
                    LifeComment lifeComment = lifeCommentMapper.selectById(v.getCommentId());
                    b.append("处理结果: 你的举报通过，已被处理 经核实，您举报的评论'").append(lifeComment.getGudingPinglun()).append(" ").append(lifeComment.getShoudaPinglun()).append("'确实存在违规行为感谢您为社区环境做出的贡献。");
                    lifeCommentMapper.deleteById(v.getCommentId());
                }
            }
        } else {
            // 驳回
            switch (v.getReportContextType()) {
                case "1":
                    b.append("处理结果: 未检测到有违规行为经核实，该用户未存在违规行为，我们将会对该用户重点关注，感谢您为社区做出的贡献。");
                    break;
                case "2":
                    b.append("处理结果: 未检测到有违规行为经核实，该动态未存在违规行为，我们将会对该动态重点关注，感谢您为社区做出的贡献。");
                    break;
                case "3":
                    b.append("处理结果: 未检测到有违规行为经核实，该评论未存在违规行为，我们将会对该评论重点关注，感谢您为社区做出的贡献。");
                    break;
            }
        }
        lifeUserViolationMapper.updateById(v);
        LifeNotice LifeMessage = new LifeNotice();
        LifeMessage.setContext(b.toString());
        LifeMessage.setSenderId("system");
        LifeMessage.setIsRead(0);
        LifeMessage.setNoticeType(1);
        LifeMessage.setBusinessId(id);
        if (v.getReportingUserType().equals("1")) {
            // M
            StoreUser storeUser = storeUserService.getOne(new QueryWrapper<StoreUser>().eq("id", v.getReportingUserId()));
            LifeMessage.setReceiverId("store_" + storeUser.getPhone());
        } else {
            // U
            LifeUser lifeUser = lifeUserService.getOne(new QueryWrapper<LifeUser>().eq("id", v.getReportingUserId()));
            LifeMessage.setReceiverId("user_" + lifeUser.getUserPhone());

        }
        lifeNoticeMapper.insert(LifeMessage);
    }

    @Override
    public LifeUserViolationDto byId(Integer id) {
        LifeUserViolation entity = lifeUserViolationMapper.selectById(id);
        if (entity == null) return null;
        LifeUserViolationDto dto = new LifeUserViolationDto();
        BeanUtils.copyProperties(entity, dto);
        if (Objects.nonNull(entity.getReportEvidenceImg())) {
            List<String> list = Arrays.stream(entity.getReportEvidenceImg().split(",")).map(String::trim).collect(Collectors.toList());
            dto.setImageList(list);
        }
        // 处理举报人信息
        FunctionMagic.handleUserInfo(dto.getReportingUserType(), dto.getReportingUserId(), storeId -> storeUserService.getOne(FunctionMagic.idQueryWrapper(storeId)), lifeId -> lifeUserService.getOne(FunctionMagic.idQueryWrapper(lifeId)), user -> {
            if (user instanceof StoreUser) {
                StoreUser su = (StoreUser) user;
                dto.setNickname(su.getName());
                dto.setPhone(su.getPhone());
            } else if (user instanceof LifeUser) {
                LifeUser lu = (LifeUser) user;
                dto.setNickname(lu.getUserName());
                dto.setPhone(lu.getUserPhone());
            }
        });
        // 处理被举报人信息
        FunctionMagic.handleUserInfo(dto.getReportedUserType(), dto.getReportedUserId(), storeId -> storeUserService.getOne(FunctionMagic.idQueryWrapper(storeId)), lifeId -> lifeUserService.getOne(FunctionMagic.idQueryWrapper(lifeId)), user -> {
            if (user instanceof StoreUser) {
                dto.setAccount(((StoreUser) user).getPhone());
            } else if (user instanceof LifeUser) {
                dto.setAccount(((LifeUser) user).getUserPhone());
            }
        });
        return dto;
    }

    @Override
    public LifeUserViolationDto byIdNotice(Integer id) {
        LifeNotice lifeNotice = lifeNoticeMapper.selectById(id);
        LifeUserViolationDto dto = byId(lifeNotice.getBusinessId());
        dto.setLifeNotice(lifeNotice.getContext());
        return dto;
    }

    @Override
    public String exportExcel(String nickName, String phone, String processingStatus) throws IOException {
        // 定义格式化模式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        List<String> MIDs = storeUserService.getIds(nickName, phone);
        List<String> UIDs = lifeUserService.getIds(nickName, phone);
        boolean flag = FunctionMagic.isListFlag(MIDs, UIDs);
        QueryWrapper<LifeUserViolation> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotEmpty(processingStatus), PROCESSING_STATUS, processingStatus).and(flag, wrapper -> wrapper.nested(wq -> wq.eq(REPORTING_USER_TYPE, "1").in(!MIDs.isEmpty(), REPORTING_USER_ID, MIDs)).or(wq -> wq.eq(REPORTING_USER_TYPE, "2").in(!UIDs.isEmpty(), REPORTING_USER_ID, UIDs))).orderByDesc("updated_time");
        List<LifeUserViolation> resultPage = lifeUserViolationMapper.selectList(queryWrapper);
        List<LifeUserViolationExcelVO> res = Lists.newArrayList();
        AtomicInteger serialNumber = new AtomicInteger(1);
        resultPage.forEach(e -> {
            LifeUserViolationExcelVO dto = new LifeUserViolationExcelVO();
            BeanUtils.copyProperties(e, dto);
            dto.setId(serialNumber.getAndIncrement());
            // 图片
            if (Objects.nonNull(e.getReportEvidenceImg())) {
                String firstPart = e.getReportEvidenceImg().split(",")[0];
                dto.setReportEvidenceImg(firstPart);
            }
            // 举报内容
            dto.setReportContextType(FunctionMagic.getContext(e.getReportContextType()));
            // 举报理由
            dto.setViolationType(FunctionMagic.violation(e.getViolationType()));
            // 状态
            dto.setProcessingStatus(FunctionMagic.status(e.getProcessingStatus()));
            // 时间
            Instant instant = e.getCreatedTime().toInstant();
            String formattedTime = instant.atZone(ZoneId.systemDefault()).toLocalDateTime().format(formatter);
            dto.setCreatedTime(formattedTime);
            if (Objects.nonNull(e.getProcessingTime())) {
                Instant processing = e.getProcessingTime().toInstant();
                String processingTime = processing.atZone(ZoneId.systemDefault()).toLocalDateTime().format(formatter);
                dto.setProcessingTime(processingTime);
            }
            if (e.getReportingUserType().equals("1")) {
                // M
                // 举报人
                StoreUser storeUser = storeUserService.getOne(new QueryWrapper<StoreUser>().eq("id", e.getReportingUserId()));
                dto.setNickname(storeUser.getName());
                dto.setPhone(storeUser.getPhone());
                // 被举报人
                StoreUser reportedUser = storeUserService.getOne(new QueryWrapper<StoreUser>().eq("id", e.getReportedUserId()));
                if (Objects.nonNull(reportedUser)) {
                    dto.setReportedAcc(reportedUser.getPhone());
                }
            } else {
                // U
                LifeUser lifeUser = lifeUserService.getOne(new QueryWrapper<LifeUser>().eq("id", e.getReportingUserId()));
                dto.setNickname(lifeUser.getUserName());
                dto.setPhone(lifeUser.getUserPhone());
                LifeUser reportedUser = lifeUserService.getOne(new QueryWrapper<LifeUser>().eq("id", e.getReportedUserId()));
                if (Objects.nonNull(reportedUser)) {
                    dto.setReportedAcc(reportedUser.getUserPhone());
                }
            }
            res.add(dto);
        });
        String fileName = UUID.randomUUID().toString().replace("-", "");
        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", res, LifeUserViolationExcelVO.class);
        return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
    }

    @Override
    public String level(UserLoginInfo userLoginInfo) {
        if (null == userLoginInfo) {
            return "O";
        }
        String type = userLoginInfo.getType();
        LambdaQueryWrapper<LifeUserViolation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(LifeUserViolation::getReportContextType, "1").eq(LifeUserViolation::getReportedUserId, userLoginInfo.getUserId());
        if (Objects.equals(type, "store")) {
            // 商户
            wrapper.eq(LifeUserViolation::getReportedUserType, 1);
        } else if (Objects.equals(type, "user")) {
            // 用户
            wrapper.eq(LifeUserViolation::getReportedUserType, 2);
        }
        int count = Optional.ofNullable(lifeUserViolationMapper.selectList(wrapper)).map(List::size).orElse(0);
        if (count == 0) return "O";
        if (count >= 15) return "E";
        if (count >= 10) return "D";
        if (count >= 6) return "C";
        if (count >= 3) return "B";
        return "A";
    }
}
