package shop.alien.store.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import shop.alien.entity.store.*;
import shop.alien.entity.store.dto.StoreRenovationRequirementDto;
import shop.alien.entity.store.vo.WebSocketVo;
import shop.alien.mapper.*;
import shop.alien.store.config.WebSocketProcess;
import shop.alien.store.service.StoreRenovationRequirementService;
import shop.alien.store.util.ai.AiContentModerationUtil;
import shop.alien.store.util.ai.AiVideoModerationUtil;
import shop.alien.util.common.JwtUtil;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;

/**
 * 装修需求动态表 服务实现类
 *
 * @author auto-generated
 * @since 2025-01-15
 */
@Slf4j
@Service
@RequiredArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class StoreRenovationRequirementServiceImpl extends ServiceImpl<StoreRenovationRequirementMapper, StoreRenovationRequirement> implements StoreRenovationRequirementService {

    // 1. 自定义视频审核线程池（全局复用，避免频繁创建线程）
    private ExecutorService videoAuditExecutor;

    private final StoreInfoMapper storeInfoMapper;

    private final LifeMessageMapper lifeMessageMapper;

    private final LifeNoticeMapper lifeNoticeMapper;

    private final WebSocketProcess webSocketProcess;

    private final StoreUserMapper storeUserMapper;

    private final AiContentModerationUtil aiContentModerationUtil;
    private final AiVideoModerationUtil aiVideoModerationUtil;
    // 定义图片后缀常量（不可修改，保证线程安全）
    private static final Set<String> IMAGE_SUFFIXES = Collections.unmodifiableSet(
            new HashSet<>(Arrays.asList(".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp"))
    );

    // 定义视频后缀常量
    private static final Set<String> VIDEO_SUFFIXES = Collections.unmodifiableSet(
            new HashSet<>(Arrays.asList(".mp4", ".avi", ".mov", ".flv", ".mkv", ".wmv", ".mpeg"))
    );

    // 初始化线程池
    @PostConstruct
    public void initExecutor() {
        // 核心参数根据业务调整，IO密集型任务线程数可设为CPU核心数*2~4
        int corePoolSize = Runtime.getRuntime().availableProcessors() * 2;
        int maxPoolSize = Runtime.getRuntime().availableProcessors() * 4;
        videoAuditExecutor = new ThreadPoolExecutor(
                corePoolSize,
                maxPoolSize,
                60L,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(500), // 任务队列，避免无界队列溢出
                new ThreadFactory() {
                    private int count = 0;
                    @Override
                    public Thread newThread(Runnable r) {
                        Thread t = new Thread(r);
                        t.setName("video-audit-" + count++); // 自定义线程名，便于排查
                        return t;
                    }
                },
                // 任务拒绝策略：记录日志+调用者线程兜底（避免任务丢失）
                new ThreadPoolExecutor.CallerRunsPolicy() {
                    @Override
                    public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
                        log.error("视频审核任务被拒绝，队列已满！当前队列大小：{}，活跃线程数：{}",
                                e.getQueue().size(), e.getActiveCount());
                        super.rejectedExecution(r, e);
                    }
                }
        );
    }

    // 优雅关闭线程池
    @PreDestroy
    public void destroyExecutor() {
        if (Objects.nonNull(videoAuditExecutor)) {
            videoAuditExecutor.shutdown();
            try {
                if (!videoAuditExecutor.awaitTermination(30, TimeUnit.SECONDS)) {
                    videoAuditExecutor.shutdownNow();
                }
            } catch (InterruptedException e) {
                videoAuditExecutor.shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }

    @Override
    public boolean saveOrUpdateRequirement(StoreRenovationRequirementDto dto) {
        log.info("StoreRenovationRequirementServiceImpl.saveOrUpdateRequirement?dto={}", dto);
        try {
            StoreRenovationRequirement requirement = new StoreRenovationRequirement();
            BeanUtils.copyProperties(dto, requirement);

            // 处理附件URL列表：List转逗号拼接字符串
            if (dto.getAttachmentUrls() != null && !dto.getAttachmentUrls().isEmpty()) {
                String attachmentUrlsStr = String.join(",", dto.getAttachmentUrls());
                requirement.setAttachmentUrls(attachmentUrlsStr);
            }

            // 获取当前登录用户ID
            Integer currentUserId = null;
            try {
                com.alibaba.fastjson.JSONObject userInfo = JwtUtil.getCurrentUserInfo();
                if (userInfo != null) {
                    currentUserId = userInfo.getInteger("userId");
                }
            } catch (Exception e) {
                log.warn("获取当前用户ID失败: {}", e.getMessage());
            }

            if (requirement.getId() == null) {
                // 新增
                requirement.setCreatedUserId(currentUserId);
                requirement.setCreatedTime(new Date());
                if (requirement.getStatus() == null) {
                    requirement.setStatus(0); // 默认草稿
                }
                if (requirement.getViewCount() == null) {
                    requirement.setViewCount(0);
                }
                if (requirement.getInquiryCount() == null) {
                    requirement.setInquiryCount(0);
                }
                if (requirement.getAuditStatus() == null) {
                    requirement.setAuditStatus(0); // 默认待审核
                }
            } else {
                // 更新
                requirement.setUpdatedUserId(currentUserId);
                requirement.setUpdatedTime(new Date());
            }
            StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getStoreId, dto.getStoreId()).eq(StoreUser::getDeleteFlag, 0));

            LifeNotice lifeMessage = new LifeNotice();
            lifeMessage.setReceiverId("store_" + storeUser.getPhone());
            String text = "您发布的装修动态已提交审核，请于1-3个工作日进行查看";
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("message", text);
            lifeMessage.setContext(jsonObject.toJSONString());
            lifeMessage.setTitle("审核通知");
            lifeMessage.setSenderId("system");
            lifeMessage.setIsRead(0);
            lifeMessage.setNoticeType(1);
            lifeNoticeMapper.insert(lifeMessage);

            WebSocketVo websocketVo = new WebSocketVo();
            websocketVo.setSenderId("system");
            websocketVo.setReceiverId("store_" + storeUser.getPhone());
            websocketVo.setCategory("notice");
            websocketVo.setNoticeType("1");
            websocketVo.setIsRead(0);
            websocketVo.setText(JSONObject.from(lifeMessage).toJSONString());
            webSocketProcess.sendMessage("store_" + storeUser.getPhone(), JSONObject.from(websocketVo).toJSONString());


            // TODO 审核文本和图片内容是否违规
            // 一次遍历完成分类，避免多次流式处理
            Map<String, List<String>> urlCategoryMap = classifyUrls(dto.getAttachmentUrls());
            List<String> videoUrls = urlCategoryMap.get("video");
            // 1.调用文本+图片审核接口 ai为同步接口
            AiContentModerationUtil.AuditResult auditResult = aiContentModerationUtil.auditContent(requirement.getDetailedRequirement(), urlCategoryMap.get("image"));
            if (!auditResult.isPassed()) {
                requirement.setAuditStatus(2);
                requirement.setAuditReason(auditResult.getFailureReason());
                // 发送审核失败通知（文本图片）
                if (storeUser != null && storeUser.getPhone() != null) {
                    sendAuditNotification(storeUser.getPhone(), 2, auditResult.getFailureReason(), "text_image");
                }

            } else {
                // 如果文本/图片审核通过，且没有视频需要审核，直接设置为审核通过
                if (videoUrls == null || videoUrls.isEmpty()) {
                    requirement.setAuditStatus(1);
                    requirement.setAuditReason(null);
                    // 发送审核通过通知（文本图片，无视频）
                    if (storeUser != null && storeUser.getPhone() != null) {
                        sendAuditNotification(storeUser.getPhone(), 1, null, "text_image");
                    }
                } else {
                    // 异步调用视频审核接口,图片审核通过后调用（核心优化）
                    // 保存storeUser信息供异步任务使用
                    final StoreUser finalStoreUser = storeUser;
                    CompletableFuture.runAsync(() -> {
                    AiVideoModerationUtil.VideoAuditResult videoAuditResult = null;
                    try {
                        // 调用审核接口，增加超时控制（避免接口挂死）
                        videoAuditResult = CompletableFuture.supplyAsync(
                                () -> aiVideoModerationUtil.auditVideos(urlCategoryMap.get("video")),
                                videoAuditExecutor
                        ).get();

                        // 审核不通过则更新状态和原因
                        if (Objects.nonNull(videoAuditResult) && !videoAuditResult.isPassed()) {
                            // 重新查询最新的requirement，避免并发覆盖
                            StoreRenovationRequirement latestRequirement = this.getById(requirement.getId());
                            if (Objects.isNull(latestRequirement)) {
                                log.error("视频审核后更新失败，requirement不存在，ID：{}", requirement.getId());
                                return;
                            }
                            latestRequirement.setAuditStatus(2);
                            latestRequirement.setAuditReason(videoAuditResult.getFailureReason());
                            this.saveOrUpdate(latestRequirement);
                            log.info("视频审核不通过，已更新状态，requirementID：{}，原因：{}",
                                    requirement.getId(), videoAuditResult.getFailureReason());
                            // 发送审核不通过通知（视频）
                            if (finalStoreUser != null && finalStoreUser.getPhone() != null) {
                                sendAuditNotification(finalStoreUser.getPhone(), 2, videoAuditResult.getFailureReason(), "video");
                            }

                        } else if (Objects.nonNull(videoAuditResult) && videoAuditResult.isPassed()) {
                            // 审核通过也更新状态（可选，根据业务需求）
                            StoreRenovationRequirement latestRequirement = this.getById(requirement.getId());
                            if (Objects.nonNull(latestRequirement)) {
                                latestRequirement.setAuditStatus(1);
                                latestRequirement.setAuditReason(null);
                                this.saveOrUpdate(latestRequirement);
                                // 发送审核通过通知（视频）
                                if (finalStoreUser != null && finalStoreUser.getPhone() != null) {
                                    sendAuditNotification(finalStoreUser.getPhone(), 1, null, "video");
                                }

                                log.info("视频审核通过，已更新状态，requirementID：{}", requirement.getId());
                            }
                        }
                    } catch (Exception e) {
                        log.error("视频审核接口调用异常，requirementID：{}", requirement.getId(), e);
                        StoreRenovationRequirement latestRequirement = this.getById(requirement.getId());
                        if (Objects.nonNull(latestRequirement)) {
                            String exceptionMessage = "视频审核接口调用异常：" + e.getMessage();
                            latestRequirement.setAuditStatus(2);
                            latestRequirement.setAuditReason(exceptionMessage);
                            this.saveOrUpdate(latestRequirement);
                            // 发送审核异常通知（视频）
                            if (finalStoreUser != null && finalStoreUser.getPhone() != null) {
                                sendAuditNotification(finalStoreUser.getPhone(), 2, exceptionMessage, "video");
                            }
                        }
                    }
                    }, videoAuditExecutor);
                }
            }
            requirement.setAuditTime(new Date());
            boolean isSuccess  = this.saveOrUpdate(requirement);

            return isSuccess;
        } catch (Exception e) {
            log.error("保存装修需求失败: {}", e.getMessage(), e);
            throw new RuntimeException("保存装修需求失败: " + e.getMessage());
        }
    }

    /**
     * 对URL列表进行分类（图片/视频/其他）
     * @param attachmentUrls 原始URL列表
     * @return 分类后的Map
     */
    public static Map<String, List<String>> classifyUrls(List<String> attachmentUrls) {
        // 初始化分类容器
        List<String> imageUrls = new ArrayList<>();
        List<String> videoUrls = new ArrayList<>();
        List<String> otherUrls = new ArrayList<>();

        if (Objects.isNull(attachmentUrls) || attachmentUrls.isEmpty()) {
            return buildResultMap(imageUrls, videoUrls, otherUrls);
        }

        for (String url : attachmentUrls) {
            // 空URL直接归为其他
            if (url == null || url.trim().isEmpty()) {
                otherUrls.add(url);
                continue;
            }

            String lowerUrl = url.toLowerCase().trim();
            // 优先判断图片（避免URL中同时包含图片+视频后缀的极端情况）
            boolean isImage = IMAGE_SUFFIXES.stream().anyMatch(lowerUrl::contains);
            if (isImage) {
                imageUrls.add(url); // 保留原始URL，而非小写后的
                continue;
            }

            // 判断是否为视频
            boolean isVideo = VIDEO_SUFFIXES.stream().anyMatch(lowerUrl::contains);
            if (isVideo) {
                videoUrls.add(url);
            } else {
                otherUrls.add(url);
            }
        }

        return buildResultMap(imageUrls, videoUrls, otherUrls);
    }

    /**
     * 构建分类结果Map
     */
    public static Map<String, List<String>> buildResultMap(List<String> imageUrls, List<String> videoUrls, List<String> otherUrls) {
        Map<String, List<String>> resultMap = new HashMap<>(3);
        resultMap.put("image", Collections.unmodifiableList(imageUrls)); // 返回不可修改列表，避免外部篡改
        resultMap.put("video", Collections.unmodifiableList(videoUrls));
        resultMap.put("other", Collections.unmodifiableList(otherUrls));
        return resultMap;
    }

    /**
     * 发送审核结果通知
     * @param storePhone 商铺电话
     * @param auditStatus 审核状态：1-通过，2-不通过
     * @param auditReason 审核原因（不通过时提供）
     * @param auditType 审核类型：text_image-文本图片审核，video-视频审核
     */
    private void sendAuditNotification(String storePhone, Integer auditStatus, String auditReason, String auditType) {
        try {
            if (storePhone == null || storePhone.trim().isEmpty()) {
                log.warn("发送审核通知失败，商铺电话为空");
                return;
            }

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
            String commonDate = sdf.format(new Date());

            String title;
            String message;
            if (auditStatus == 1) {
                // 审核通过
                title = "审核通知";
                if ("video".equals(auditType)) {
                    message = "在" + commonDate + "，您发布的装修动态视频审核已通过。";
                } else {
                    message = "您发布的装修需求已通过审核,平台已将此需求发布,有意向的装修公司会与您联系";
                }
            } else {
                // 审核不通过
                title = "审核通知";
//                String reasonText = auditReason != null && !auditReason.trim().isEmpty()
//                    ? "，原因：" + auditReason
//                    : "";
                if ("video".equals(auditType)) {
                    message = "在" + commonDate + "，您发布的装修动态视频审核未通过" + auditReason + "，请修改后重新提交。";
                } else {
                    message = "您发布的装修需求未通过审核.驳回原因:"+auditReason+"请您重新发布.";
                }
            }

            LifeNotice lifeNotice = new LifeNotice();
            lifeNotice.setReceiverId("store_" + storePhone);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("message", message);
            lifeNotice.setContext(jsonObject.toJSONString());
            lifeNotice.setTitle(title);
            lifeNotice.setSenderId("system");
            lifeNotice.setIsRead(0);
            lifeNotice.setNoticeType(1);
            lifeNoticeMapper.insert(lifeNotice);

            WebSocketVo websocketVo = new WebSocketVo();
            websocketVo.setSenderId("system");
            websocketVo.setReceiverId("store_" + storePhone);
            websocketVo.setCategory("notice");
            websocketVo.setNoticeType("1");
            websocketVo.setIsRead(0);
            websocketVo.setText(JSONObject.from(lifeNotice).toJSONString());
            webSocketProcess.sendMessage("store_" + storePhone, JSONObject.from(websocketVo).toJSONString());

            log.info("审核通知发送成功，商铺电话：{}，审核状态：{}，审核类型：{}", storePhone, auditStatus, auditType);
        } catch (Exception e) {
            log.error("发送审核通知异常，商铺电话：{}，审核状态：{}，审核类型：{}", storePhone, auditStatus, auditType, e);
        }
    }


    @Override
    public StoreRenovationRequirementDto getRequirementDetail(Integer id) {
        log.info("StoreRenovationRequirementServiceImpl.getRequirementDetail?id={}", id);
        StoreRenovationRequirement requirement = this.getById(id);
        if (requirement == null) {
            return null;
        }

        StoreRenovationRequirementDto dto = new StoreRenovationRequirementDto();
        BeanUtils.copyProperties(requirement, dto);

        // 处理附件URL字符串：逗号拼接转List
        if (StringUtils.hasText(requirement.getAttachmentUrls())) {
            List<String> attachmentUrls = Arrays.asList(requirement.getAttachmentUrls().split(","));
            dto.setAttachmentUrls(attachmentUrls);
        } else {
            dto.setAttachmentUrls(new ArrayList<>());
        }

        // 填充商铺信息和商户头像
        if (requirement.getStoreId() != null) {
            // 查询商铺信息
            StoreInfo storeInfo = storeInfoMapper.selectById(requirement.getStoreId());
            if (storeInfo != null) {
                dto.setStoreName(storeInfo.getStoreName());
                dto.setStoreTel(storeInfo.getStoreTel());
                dto.setStoreAddress(storeInfo.getStoreAddress());
                dto.setStoreBlurb(storeInfo.getStoreBlurb());
            }

            // 查询商户头像（从store_user表获取head_img）
            StoreUser storeUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>()
                    .eq(StoreUser::getStoreId, requirement.getStoreId())
                    .eq(StoreUser::getDeleteFlag, 0));
            if (storeUser != null && StringUtils.hasText(storeUser.getHeadImg())) {
                dto.setStoreAvatar(storeUser.getHeadImg());
            }
        }

        return dto;
    }

    @Override
    public IPage<StoreRenovationRequirementDto> getRequirementPage(Page<StoreRenovationRequirementDto> page,
                                                                     Integer storeId,
                                                                     String city,
                                                                     Integer renovationType,
                                                                     Integer status,
                                                                     Integer auditStatus,
                                                                     Integer sortType) {
        log.info("StoreRenovationRequirementServiceImpl.getRequirementPage?storeId={}, city={}, renovationType={}, status={}, auditStatus={}, sortType={}",
                storeId, city, renovationType, status, auditStatus, sortType);

        LambdaQueryWrapper<StoreRenovationRequirement> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreRenovationRequirement::getDeleteFlag, 0);

        if (storeId != null) {
            wrapper.eq(StoreRenovationRequirement::getStoreId, storeId);
        }
        if (StringUtils.hasText(city)) {
            wrapper.eq(StoreRenovationRequirement::getCity, city);
        }
        if (renovationType != null) {
            wrapper.eq(StoreRenovationRequirement::getRenovationType, renovationType);
        }
        if (status != null) {
            wrapper.eq(StoreRenovationRequirement::getStatus, status);
        }
        if (auditStatus != null) {
            wrapper.eq(StoreRenovationRequirement::getAuditStatus, auditStatus);
        }

        // 排序处理：1-最新发布, 2-价格最高, 3-面积最大
        if (sortType == null || sortType == 1) {
            // 默认：最新发布（按创建时间降序）
            wrapper.orderByDesc(StoreRenovationRequirement::getCreatedTime);
        } else if (sortType == 2) {
            // 价格最高（按装修预算降序）
            wrapper.orderByDesc(StoreRenovationRequirement::getRenovationBudget);
            wrapper.orderByDesc(StoreRenovationRequirement::getCreatedTime); // 价格相同则按时间排序
        } else if (sortType == 3) {
            // 面积最大（按房屋面积降序）
            wrapper.orderByDesc(StoreRenovationRequirement::getHouseArea);
            wrapper.orderByDesc(StoreRenovationRequirement::getCreatedTime); // 面积相同则按时间排序
        } else {
            // 无效的排序类型，使用默认排序
            wrapper.orderByDesc(StoreRenovationRequirement::getCreatedTime);
        }

        IPage<StoreRenovationRequirement> requirementPage = this.page(new Page<>(page.getCurrent(), page.getSize()), wrapper);

        // 转换为DTO
        IPage<StoreRenovationRequirementDto> dtoPage = requirementPage.convert(requirement -> {
            StoreRenovationRequirementDto dto = new StoreRenovationRequirementDto();
            BeanUtils.copyProperties(requirement, dto);

            // 处理附件URL字符串：逗号拼接转List
            if (StringUtils.hasText(requirement.getAttachmentUrls())) {
                List<String> attachmentUrls = Arrays.asList(requirement.getAttachmentUrls().split(","));
                dto.setAttachmentUrls(attachmentUrls);
            } else {
                dto.setAttachmentUrls(new ArrayList<>());
            }

            return dto;
        });

        // 批量查询商铺信息并填充到DTO
        if (dtoPage.getRecords() != null && !dtoPage.getRecords().isEmpty()) {
            // 收集所有的门店ID
            List<Integer> storeIds = dtoPage.getRecords().stream()
                    .map(StoreRenovationRequirementDto::getStoreId)
                    .filter(id -> id != null)
                    .distinct()
                    .collect(Collectors.toList());

            // 批量查询商铺信息
            if (!storeIds.isEmpty()) {
                List<StoreInfo> storeInfoList = storeInfoMapper.selectBatchIds(storeIds);
                // 转换为Map，key为storeId，value为StoreInfo
                Map<Integer, StoreInfo> storeInfoMap = storeInfoList.stream()
                        .collect(Collectors.toMap(StoreInfo::getId, storeInfo -> storeInfo, (v1, v2) -> v1));

                // 批量查询商户头像（store_user.head_img）
                LambdaQueryWrapper<StoreUser> userWrapper = new LambdaQueryWrapper<StoreUser>()
                        .in(StoreUser::getStoreId, storeIds)
                        .eq(StoreUser::getDeleteFlag, 0);
                List<StoreUser> storeUserList = storeUserMapper.selectList(userWrapper);
                Map<Integer, String> storeAvatarMap = storeUserList.stream()
                        .filter(u -> u.getStoreId() != null && u.getHeadImg() != null)
                        .collect(Collectors.toMap(StoreUser::getStoreId, StoreUser::getHeadImg, (v1, v2) -> v1));

                // 填充商铺信息（含头像）到DTO
                dtoPage.getRecords().forEach(dto -> {
                    StoreInfo storeInfo = storeInfoMap.get(dto.getStoreId());
                    if (storeInfo != null) {
                        dto.setStoreName(storeInfo.getStoreName());
                        dto.setStoreTel(storeInfo.getStoreTel());
                        dto.setStoreAddress(storeInfo.getStoreAddress());
                        dto.setStoreBlurb(storeInfo.getStoreBlurb());
                    }
                    dto.setStoreAvatar(storeAvatarMap.get(dto.getStoreId()));
                });
            }

            // 检查是否已与发布商铺发生沟通
            String currentUserPhone = null;
            try {
                com.alibaba.fastjson.JSONObject userInfo = JwtUtil.getCurrentUserInfo();
                if (userInfo != null) {
                    currentUserPhone = userInfo.getString("phone");
                }
            } catch (Exception e) {
                log.debug("获取当前用户手机号失败（用户可能未登录）: {}", e.getMessage());
            }

            if (currentUserPhone != null && StringUtils.hasText(currentUserPhone)) {
                String currentUserPhoneId = "store_" + currentUserPhone;

                // 批量查询沟通状态（优化：使用Map缓存结果，避免重复查询）
                Map<String, Boolean> communicationStatusMap = new HashMap<>();

                dtoPage.getRecords().forEach(dto -> {
                    String storeTel = dto.getStoreTel();
                    if (storeTel != null && StringUtils.hasText(storeTel)) {
                        String publishingShopPhoneId = "store_" + storeTel;

                        // 检查是否已查询过该商铺的沟通状态
                        String communicationKey = currentUserPhoneId + "_" + publishingShopPhoneId;
                        Boolean hasCommunicated = communicationStatusMap.get(communicationKey);

                        if (hasCommunicated == null) {
                            // 查询是否有消息记录（检查双向消息）
                            LambdaQueryWrapper<LifeMessage> messageWrapper = new LambdaQueryWrapper<>();
                            messageWrapper.eq(LifeMessage::getDeleteFlag, 0);
                            messageWrapper.and(w -> w.and(w1 -> w1.eq(LifeMessage::getSenderId, currentUserPhoneId)
                                            .eq(LifeMessage::getReceiverId, publishingShopPhoneId))
                                    .or(w2 -> w2.eq(LifeMessage::getSenderId, publishingShopPhoneId)
                                            .eq(LifeMessage::getReceiverId, currentUserPhoneId)));
                            Integer messageCount = lifeMessageMapper.selectCount(messageWrapper);
                            hasCommunicated = messageCount != null && messageCount > 0;
                            communicationStatusMap.put(communicationKey, hasCommunicated);
                        }

                        dto.setHasCommunicated(hasCommunicated);
                    } else {
                        dto.setHasCommunicated(false);
                    }
                });
            } else {
                // 用户未登录，所有记录都设为未沟通
                dtoPage.getRecords().forEach(dto -> dto.setHasCommunicated(false));
            }
        }

        return dtoPage;
    }

    @Override
    public void incrementViewCount(Integer id) {
        log.info("StoreRenovationRequirementServiceImpl.incrementViewCount?id={}", id);
        LambdaUpdateWrapper<StoreRenovationRequirement> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(StoreRenovationRequirement::getId, id);
        wrapper.setSql("view_count = view_count + 1");
        this.update(wrapper);
    }

    @Override
    public void incrementInquiryCount(Integer id) {
        log.info("StoreRenovationRequirementServiceImpl.incrementInquiryCount?id={}", id);
        LambdaUpdateWrapper<StoreRenovationRequirement> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(StoreRenovationRequirement::getId, id);
        wrapper.setSql("inquiry_count = inquiry_count + 1");
        this.update(wrapper);
    }

    @Override
    public boolean updateStatus(Integer id, Integer status) {
        log.info("StoreRenovationRequirementServiceImpl.updateStatus?id={}, status={}", id, status);
        LambdaUpdateWrapper<StoreRenovationRequirement> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(StoreRenovationRequirement::getId, id);
        wrapper.set(StoreRenovationRequirement::getStatus, status);
        wrapper.set(StoreRenovationRequirement::getUpdatedTime, new Date());

        try {
            com.alibaba.fastjson.JSONObject userInfo = JwtUtil.getCurrentUserInfo();
            if (userInfo != null) {
                wrapper.set(StoreRenovationRequirement::getUpdatedUserId, userInfo.getInteger("userId"));
            }
        } catch (Exception e) {
            log.warn("获取当前用户ID失败: {}", e.getMessage());
        }

        return this.update(wrapper);
    }

    @Override
    public boolean auditRequirement(Integer id, Integer auditStatus, String auditReason, Integer auditUserId) {
        log.info("StoreRenovationRequirementServiceImpl.auditRequirement?id={}, auditStatus={}, auditReason={}, auditUserId={}",
                id, auditStatus, auditReason, auditUserId);

        if (auditStatus == 2 && !StringUtils.hasText(auditReason)) {
            throw new RuntimeException("审核失败时必须填写审核原因");
        }

        LambdaUpdateWrapper<StoreRenovationRequirement> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(StoreRenovationRequirement::getId, id);
        wrapper.set(StoreRenovationRequirement::getAuditStatus, auditStatus);
        wrapper.set(StoreRenovationRequirement::getAuditTime, new Date());
        wrapper.set(StoreRenovationRequirement::getAuditUserId, auditUserId);
        wrapper.set(StoreRenovationRequirement::getUpdatedTime, new Date());

        if (auditStatus == 2) {
            wrapper.set(StoreRenovationRequirement::getAuditReason, auditReason);
        } else {
            wrapper.set(StoreRenovationRequirement::getAuditReason, null);
        }

        return this.update(wrapper);
    }

    @Override
    public boolean deleteRequirement(Integer id) {
        log.info("StoreRenovationRequirementServiceImpl.deleteRequirement?id={}", id);
        return this.removeById(id);
    }

    @Override
    public List<StoreRenovationRequirementDto> getRequirementListByStoreId(Integer storeId) {
        log.info("StoreRenovationRequirementServiceImpl.getRequirementListByStoreId?storeId={}", storeId);
        LambdaQueryWrapper<StoreRenovationRequirement> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreRenovationRequirement::getStoreId, storeId);
        wrapper.eq(StoreRenovationRequirement::getDeleteFlag, 0);
        wrapper.orderByDesc(StoreRenovationRequirement::getCreatedTime);

        List<StoreRenovationRequirement> requirements = this.list(wrapper);

        return requirements.stream().map(requirement -> {
            StoreRenovationRequirementDto dto = new StoreRenovationRequirementDto();
            BeanUtils.copyProperties(requirement, dto);

            // 处理附件URL字符串：逗号拼接转List
            if (StringUtils.hasText(requirement.getAttachmentUrls())) {
                List<String> attachmentUrls = Arrays.asList(requirement.getAttachmentUrls().split(","));
                dto.setAttachmentUrls(attachmentUrls);
            } else {
                dto.setAttachmentUrls(new ArrayList<>());
            }

            return dto;
        }).collect(Collectors.toList());
    }
}

