package com.ylx.moment.service.impl;

import cn.hutool.core.collection.CollUtil;
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.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylx.common.exception.ServiceException;
import com.ylx.discover.moment.domain.dto.MomentPageDTO;
import com.ylx.discover.moment.domain.vo.MomentPageVO;
import com.ylx.massage.domain.MaTechnician;
import com.ylx.moment.domain.*;
import com.ylx.massage.domain.dto.EditMomentDTO;
import com.ylx.moment.domain.dto.MomentAuditDTO;
import com.ylx.moment.domain.dto.MomentManageQueryDTO;
import com.ylx.massage.domain.dto.PublishMomentDTO;
import com.ylx.massage.mapper.MaTechnicianMapper;
import com.ylx.moment.domain.vo.*;
import com.ylx.moment.mapper.MomentMediaMapper;
import com.ylx.massage.mapper.TJsMapper;
import com.ylx.moment.mapper.TechnicianMomentMapper;
import com.ylx.merchant.domain.dto.MerchantMomentDTO;
import com.ylx.merchant.domain.vo.MomentVO;
import com.ylx.moment.service.ITechnicianMomentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 技师动态服务实现类
 */
@Service
@Slf4j
public class TechnicianMomentServiceImpl extends ServiceImpl<TechnicianMomentMapper, TechnicianMoment> implements ITechnicianMomentService {

    private static final int AUDIT_STATUS_PENDING = 1;
    private static final int NOT_DELETED = 0;
    private static final int DELETED = 1;

    @Autowired
    private TechnicianMomentMapper momentMapper;

    @Autowired
    private MomentMediaMapper mediaMapper;

    @Autowired
    private TJsMapper tJsMapper;

    @Autowired
    private MaTechnicianMapper maTechnicianMapper;

    /**
     * 查询推荐动态列表（不分地区，按日期倒序，同一天按浏览量倒序）
     *
     * @param pageNum  页码，默认1
     * @param pageSize 每页数量，默认10
     * @return R<List < MomentListVO>> 动态列表
     */
    @Override
    public List<MomentListVO> getRecommendedMoments(Integer pageNum, Integer pageSize) {
        Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
        List<TechnicianMoment> moments = momentMapper.selectRecommendedMoments(page);
        if (moments == null || moments.isEmpty()) {
            return new ArrayList<>();
        }

        // 查询技师信息
        List<Integer> technicianIds = moments.stream().map(TechnicianMoment::getTechnicianId).collect(Collectors.toList());
        Map<Integer, MaTechnician> technicianMap = getTechnicianMap(technicianIds);

        // 组装VO
        return moments.stream().map(moment -> {
            MomentListVO vo = new MomentListVO();
            BeanUtils.copyProperties(moment, vo);

            MaTechnician technician = technicianMap.get(moment.getTechnicianId());
            if (technician != null) {
                vo.setTechnicianNickName(technician.getTeNickName());
                vo.setTechnicianAvatar(technician.getTeAvatar());
                vo.setTechnicianStatus(getTechnicianStatus(technician));
            }
            return vo;
        }).collect(Collectors.toList());
    }

    /**
     * 查询同城动态列表（按城市和发布时间倒序）
     */
    @Override
    public List<MomentListVO> getSameCityMoments(String cityCode, Integer pageNum, Integer pageSize) {
        Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
        List<TechnicianMoment> moments = momentMapper.selectSameCityMoments(page, cityCode);
        if (moments == null || moments.isEmpty()) {
            return new ArrayList<>();
        }

        // 查询技师信息
        List<Integer> technicianIds = moments.stream().map(TechnicianMoment::getTechnicianId).collect(Collectors.toList());
        Map<Integer, MaTechnician> technicianMap = getTechnicianMap(technicianIds);

        // 组装VO
        return moments.stream().map(moment -> {
            MomentListVO vo = new MomentListVO();
            BeanUtils.copyProperties(moment, vo);

            MaTechnician technician = technicianMap.get(moment.getTechnicianId());
            if (technician != null) {
                vo.setTechnicianNickName(technician.getTeNickName());
                vo.setTechnicianAvatar(technician.getTeAvatar());
                vo.setTechnicianStatus(getTechnicianStatus(technician));
            }
            return vo;
        }).collect(Collectors.toList());
    }

    /**
     * 查询附近动态列表（10km内，按日期倒序，同一天按距离排序）
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @param pageNum   页码，默认1
     * @param pageSize  每页数量，默认10
     * @return R<List < MomentListVO>> 动态列表
     */
    @Override
    public List<MomentListVO> getNearbyMoments(BigDecimal longitude, BigDecimal latitude, Integer pageNum, Integer pageSize) {
        if (latitude == null || longitude == null) {
            throw new ServiceException("地理位置信息不能为空");
        }
        Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
        List<TechnicianMoment> moments = momentMapper.selectNearbyMoments(page, longitude, latitude);
        if (moments == null || moments.isEmpty()) {
            return new ArrayList<>();
        }

        // 查询技师信息
        List<Integer> technicianIds = moments.stream().map(TechnicianMoment::getTechnicianId).collect(Collectors.toList());

        Map<Integer, MaTechnician> technicianMap = getTechnicianMap(technicianIds);

        // 组装VO（需要计算距离）
        return moments.stream().map(moment -> {
            MomentListVO vo = new MomentListVO();
            BeanUtils.copyProperties(moment, vo);

            MaTechnician technician = technicianMap.get(moment.getTechnicianId());
            if (technician != null) {
                vo.setTechnicianNickName(technician.getTeNickName());
                vo.setTechnicianAvatar(technician.getTeAvatar());
                vo.setTechnicianStatus(getTechnicianStatus(technician));

                // 计算距离
                if (moment.getLatitude() != null && moment.getLongitude() != null) {
                    double distance = calculateDistance(
                            latitude.doubleValue(), longitude.doubleValue(),
                            moment.getLatitude().doubleValue(), moment.getLongitude().doubleValue()
                    );
                    vo.setDistance(Math.round(distance * 100.0) / 100.0); // 保留两位小数
                }
            }
            return vo;
        }).collect(Collectors.toList());
    }

    /**
     * 查询动态详情（浏览量+1）
     *
     * @param momentId 动态ID
     * @param longitude 用户经度
     * @param latitude  用户纬度
     * @return MomentDetailVO 动态详情
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public MomentDetailVO getMomentDetail(Long momentId, BigDecimal longitude, BigDecimal latitude) {
        // 查询动态信息
        TechnicianMoment moment = momentMapper.selectById(momentId);
        if (moment == null) {
            throw new ServiceException("动态不存在");
        }

        // 增加浏览量
        momentMapper.incrementViewCount(momentId);
        moment.setViewCount(moment.getViewCount() + 1);

        // 查询商户信息
        MaTechnician technician = maTechnicianMapper.selectById(moment.getTechnicianId());

        // 查询媒体列表
        List<MomentMedia> mediaList = mediaMapper.selectMediaListByMomentId(momentId);
        List<MomentMediaVO> mediaVOList = mediaList.stream().map(media -> {
            MomentMediaVO mediaVO = new MomentMediaVO();
            BeanUtils.copyProperties(media, mediaVO);
            return mediaVO;
        }).collect(Collectors.toList());

        // 组装VO
        MomentDetailVO vo = new MomentDetailVO();
        BeanUtils.copyProperties(moment, vo);

        if (technician != null) {
            vo.setTechnicianNickName(technician.getTeNickName());
            vo.setTechnicianAvatar(technician.getTeAvatar());
            vo.setTechnicianStatus(getTechnicianStatus(technician));
        }
        vo.setMediaList(mediaVOList);
        // 计算距离（如果有位置信息）
        if (moment.getLatitude() != null && moment.getLongitude() != null) {
            if(latitude != null && longitude != null){
                // 传入用户位置，计算用户与技师之间的距离
                double distance = calculateDistance(
                        latitude.doubleValue(), longitude.doubleValue(),
                        moment.getLatitude().doubleValue(), moment.getLongitude().doubleValue()
                );
                vo.setDistance(Math.round(distance * 100.0) / 100.0); // 保留两位小数
            }
        }
        return vo;
    }

    /**
     * 批量查询技师信息
     *
     * @param technicianIds 技师ID列表
     * @return Map<String, TJs> 技师ID-技师实体映射
     */
    private Map<Integer, MaTechnician> getTechnicianMap(List<Integer> technicianIds) {
        return maTechnicianMapper.selectBatchIds(technicianIds).stream().collect(Collectors.toMap(MaTechnician::getId, t -> t));
    }

    /**
     * 获取技师状态
     * 1-可服务（当前时间技师空闲）
     * 2-可预约（当前时间技师"已接单-服务中"）
     */
    private Integer getTechnicianStatus(MaTechnician technician) {
        if (technician.getServiceState() != null && technician.getServiceState() == 1) {
            return 1; // 可服务
        } else if (technician.getServiceState() != null && technician.getServiceState() == 0) {
            return 2; // 可预约（服务中）
        }
        return null;
    }

    /**
     * 计算两点之间的距离（单位：km）
     *
     * @param lat1 纬度1（用户纬度）
     * @param lon1 经度1（用户经度）
     * @param lat2 纬度2（技师纬度）
     * @param lon2 经度2（技师经度）
     * @return double 距离（单位：km）
     * <p>
     * 使用Haversine公式
     */
    private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        final double R = 6371; // 地球半径，单位km

        double dLat = Math.toRadians(lat2 - lat1);
        double dLon = Math.toRadians(lon2 - lon1);

        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
                Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
                        Math.sin(dLon / 2) * Math.sin(dLon / 2);

        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        return R * c;
    }

    /**
     * 发布动态或保存草稿
     *
     * @param dto    发布动态请求对象
     * @param openId 技师OpenID
     * @return Long 动态ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long publishMoment(PublishMomentDTO dto, String openId) {
        // 根据openId查询技师信息
        LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MaTechnician::getCOpenid, openId);
        MaTechnician technician = maTechnicianMapper.selectOne(queryWrapper);
        if (technician == null) {
            throw new ServiceException("商户信息不存在");
        }

        //查询是否保存为草稿
        Integer isDraft = dto.getIsDraft();
        boolean draft = Objects.equals(isDraft, 1);
        String cityCode = validatePublishCityCode(dto, draft);
        if (draft) {
            //只校验标题
            if (dto.getTitle() == null || dto.getTitle().trim().isEmpty()) {
                throw new ServiceException("动态标题不能为空");
            }
        } else {
            // 校验动态标题
            if (dto.getTitle() == null || dto.getTitle().trim().isEmpty()) {
                throw new ServiceException("动态标题不能为空");
            }
            // 校验动态内容
            if (StringUtils.isBlank(dto.getContent())) {
                throw new ServiceException("动态内容不能为空");
            }
            // 校验媒体类型和媒体文件
            if (dto.getMediaType() != null) {
                if (dto.getMediaType() == 1) {
                    // 图片类型
                    if (dto.getImageUrls() == null || dto.getImageUrls().isEmpty()) {
                        throw new ServiceException("图片不能为空");
                    }
                    if (dto.getImageUrls().size() > 9) {
                        throw new ServiceException("最多只能上传9张图片");
                    }
                } else if (dto.getMediaType() == 2) {
                    // 视频类型
                    if (StringUtils.isBlank(dto.getVideoUrl())) {
                        throw new ServiceException("视频不能为空");
                    }
                } else {
                    throw new ServiceException("媒体类型不正确");
                }
            }
        }

        // 创建动态对象
        TechnicianMoment moment = new TechnicianMoment();
        moment.setTechnicianId(technician.getId());
        moment.setTitle(dto.getTitle());
        moment.setContent(dto.getContent());
        moment.setMediaType(dto.getMediaType());
        moment.setLatitude(dto.getLatitude());
        moment.setLongitude(dto.getLongitude());
        moment.setLocation(dto.getLocation());
        moment.setAddress(dto.getAddress());
        moment.setCityCode(cityCode);

        if(Objects.nonNull(dto.getMediaType())){
            // 设置封面图
            if (dto.getMediaType() == 1) {
                // 图片类型，默认取第一张作为封面
                if (dto.getImageUrls() != null && !dto.getImageUrls().isEmpty()) {
                    moment.setCoverUrl(dto.getImageUrls().get(0));
                }
            } else if (dto.getMediaType() == 2) {
                // 视频类型，使用视频URL作为封面
                moment.setCoverUrl(dto.getVideoCoverUrl());
            }
        }

        // 设置审核状态和发布时间
        if (draft) {
            // 保存草稿
            moment.setAuditStatus(0);
            moment.setPublishTime(null);
        } else {
            // 立即发布，进入待审核状态
            moment.setAuditStatus(1);
            moment.setPublishTime(LocalDateTime.now());
        }

        // 设置初始状态
        moment.setIsDelete(0);
        moment.setViewCount(0);
        moment.setCreateTime(LocalDateTime.now());

        // 8. 保存动态到数据库
        int insertResult = momentMapper.insert(moment);
        if (insertResult <= 0) {
            throw new ServiceException("发布动态失败");
        }

        Long momentId = moment.getId();

        // 9. 保存媒体信息到媒体表
        if(Objects.nonNull(dto.getMediaType())){
            if (dto.getMediaType() == 1) {
                // 保存图片
                if (dto.getImageUrls() != null && !dto.getImageUrls().isEmpty()) {
                    for (int i = 0; i < dto.getImageUrls().size(); i++) {
                        MomentMedia media = new MomentMedia();
                        media.setMomentId(momentId);
                        media.setMediaUrl(dto.getImageUrls().get(i));
                        media.setMediaType(1); // 图片
                        media.setSortOrder(i + 1);
                        media.setCreateTime(LocalDateTime.now());
                        //获取文件的格式
                        String fileFormat = dto.getImageUrls().get(i).substring(dto.getImageUrls().get(i).lastIndexOf(".") + 1);
                        media.setFileFormat(fileFormat);
                        mediaMapper.insert(media);
                    }
                }
            } else if (dto.getMediaType() == 2) {
                // 保存视频
                MomentMedia media = new MomentMedia();
                media.setMomentId(momentId);
                media.setMediaUrl(dto.getVideoUrl());
                media.setMediaType(2); // 视频
                media.setSortOrder(1);
                media.setCreateTime(LocalDateTime.now());
                mediaMapper.insert(media);
            }
        }
        log.info("发布动态成功，动态ID：{}，技师ID：{}，是否草稿：{}", momentId, technician.getId(), dto.getIsDraft());
        return momentId;
    }

    /**
     * 验证发布的城市code
     *
     * @param dto 发布动态请求对象
     * @param draft 是否草稿
     * @return String 城市编码
     */
    private String validatePublishCityCode(PublishMomentDTO dto, boolean draft) {
        String cityCode = StringUtils.trimToNull(dto.getCityCode());
        if (draft && StringUtils.isBlank(cityCode)) {
            return null;
        }
        if (StringUtils.isBlank(cityCode)) {
            throw new ServiceException("城市编码不能为空");
        }
        Boolean cityOpened = maTechnicianMapper.isHasMerchantCity(cityCode);
        if (!Boolean.TRUE.equals(cityOpened)) {
            throw new ServiceException("当前城市暂未开通服务");
        }
        return cityCode;
    }

    /**
     * 编辑动态
     *
     * @param dto    编辑动态请求对象
     * @param openId 技师OpenID
     * @return Long 动态ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long editMoment(EditMomentDTO dto, String openId) {
        // 1. 参数校验
        if (dto == null) {
            throw new ServiceException("编辑动态信息不能为空");
        }
        if (openId == null || openId.trim().isEmpty()) {
            throw new ServiceException("openId不能为空");
        }
        if (dto.getMomentId() == null) {
            throw new ServiceException("动态ID不能为空");
        }

        // 2. 根据openId查询商户信息
        LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MaTechnician::getCOpenid, openId);
        MaTechnician technician = maTechnicianMapper.selectOne(queryWrapper);
        if (technician == null) {
            throw new ServiceException("商户信息不存在");
        }

        // 3. 查询动态信息
        TechnicianMoment moment = momentMapper.selectById(dto.getMomentId());
        if (moment == null) {
            throw new ServiceException("动态不存在");
        }

        // 4. 验证动态是否属于当前商户
        if (!moment.getTechnicianId().equals(technician.getId())) {
            throw new ServiceException("无权编辑此动态");
        }

        // 5. 验证动态状态是否允许编辑（只能编辑草稿和审核拒绝的动态）
        if (moment.getAuditStatus() == null || (moment.getAuditStatus() != 0 && moment.getAuditStatus() != 3)) {
            throw new ServiceException("只能编辑草稿或审核拒绝的动态");
        }

        // 6. 校验媒体类型和媒体文件
        if (dto.getMediaType() == null) {
            throw new ServiceException("媒体类型不能为空");
        }
        if (dto.getMediaType() == 1) {
            // 图片类型
            if (dto.getImageUrls() == null || dto.getImageUrls().isEmpty()) {
                throw new ServiceException("图片不能为空");
            }
            if (dto.getImageUrls().size() > 9) {
                throw new ServiceException("最多只能上传9张图片");
            }
        } else if (dto.getMediaType() == 2) {
            // 视频类型
            if (dto.getVideoUrl() == null || dto.getVideoUrl().trim().isEmpty()) {
                throw new ServiceException("视频不能为空");
            }
        } else {
            throw new ServiceException("媒体类型不正确");
        }


        // 7. 更新动态对象
        moment.setTitle(dto.getTitle());
        moment.setContent(dto.getContent());
        moment.setMediaType(dto.getMediaType());
        moment.setLongitude(dto.getLongitude());
        moment.setLatitude(dto.getLatitude());
        moment.setLocation(dto.getLocation());
        moment.setAddress(dto.getAddress());

        // 8.设置封面图
        if (dto.getMediaType() == 1) {
            // 图片类型，默认取第一张作为封面
            if (dto.getImageUrls() != null && !dto.getImageUrls().isEmpty()) {
                moment.setCoverUrl(dto.getImageUrls().get(0));
            }
        } else if (dto.getMediaType() == 2) {
            // 视频类型，使用视频封面URL（如果提供了）或视频URL作为封面
            if (dto.getVideoCoverUrl() != null && !dto.getVideoCoverUrl().trim().isEmpty()) {
                moment.setCoverUrl(dto.getVideoCoverUrl());
            } else {
                moment.setCoverUrl(dto.getVideoUrl());
            }
        }

        // 9. 设置审核状态和发布时间
        if (dto.getIsDraft() != null && dto.getIsDraft() == 1) {
            // 保存草稿
            moment.setAuditStatus(0); // 草稿
            moment.setPublishTime(null);
            moment.setRejectReason(null); // 清空拒绝原因
        } else {
            // 提交发布，进入待审核状态
            moment.setAuditStatus(1);
            if (moment.getPublishTime() == null) {
                moment.setPublishTime(LocalDateTime.now());
            }
            moment.setRejectReason(null); // 清空拒绝原因
        }
        moment.setUpdateTime(LocalDateTime.now());

        // 10. 更新动态到数据库
        int updateResult = momentMapper.updateById(moment);
        if (updateResult <= 0) {
            throw new ServiceException("编辑动态失败");
        }

        Long momentId = moment.getId();

        // 11. 删除旧的媒体信息
        LambdaQueryWrapper<MomentMedia> mediaWrapper = new LambdaQueryWrapper<>();
        mediaWrapper.eq(MomentMedia::getMomentId, momentId);
        mediaMapper.delete(mediaWrapper);

        // 12. 保存新的媒体信息到媒体表
        if (dto.getMediaType() == 1) {
            // 保存图片
            if (dto.getImageUrls() != null && !dto.getImageUrls().isEmpty()) {
                for (int i = 0; i < dto.getImageUrls().size(); i++) {
                    MomentMedia media = new MomentMedia();
                    media.setMomentId(momentId);
                    media.setMediaUrl(dto.getImageUrls().get(i));
                    media.setMediaType(1); // 图片
                    media.setSortOrder(i + 1);
                    media.setCreateTime(LocalDateTime.now());
                    // 获取文件的格式
                    String fileFormat = dto.getImageUrls().get(i).substring(dto.getImageUrls().get(i).lastIndexOf(".") + 1);
                    media.setFileFormat(fileFormat);
                    mediaMapper.insert(media);
                }
            }
        } else if (dto.getMediaType() == 2) {
            // 保存视频
            MomentMedia media = new MomentMedia();
            media.setMomentId(momentId);
            media.setMediaUrl(dto.getVideoUrl());
            media.setMediaType(2); // 视频
            media.setSortOrder(1);
            media.setCreateTime(LocalDateTime.now());
            mediaMapper.insert(media);
        }
        log.info("编辑动态成功，动态ID：{}，技师ID：{}，是否草稿：{}", momentId, technician.getId(), dto.getIsDraft());
        return momentId;
    }

    /**
     * 查询草稿箱列表
     *
     * @param openId   技师OpenID
     * @param pageNum  页码
     * @param pageSize 每页数量
     * @return List<MomentListVO> 草稿列表
     */
    @Override
    public Page<MomentListVO> getDraftMoments(String openId, Integer pageNum, Integer pageSize) {
        if (openId == null || openId.trim().isEmpty()) {
            throw new ServiceException("openId不能为空");
        }

        // 1. 根据openId查询技师信息
        LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MaTechnician::getCOpenid, openId);
        MaTechnician technician = maTechnicianMapper.selectOne(queryWrapper);
        if (technician == null) {
            throw new ServiceException("商户信息不存在");
        }

        // 2. 查询该商户的草稿列表
        Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<TechnicianMoment> momentWrapper = new LambdaQueryWrapper<>();
        momentWrapper.eq(TechnicianMoment::getTechnicianId, technician.getId())
                .eq(TechnicianMoment::getAuditStatus, 0) // 草稿状态
                .orderByDesc(TechnicianMoment::getCreateTime);

        Page<TechnicianMoment> momentPage = momentMapper.selectPage(page, momentWrapper);
        List<TechnicianMoment> moments = momentPage.getRecords();
        Page<MomentListVO> voPage = new Page<>(pageNum, pageSize);
        if (moments == null || moments.isEmpty()) {
            // 草稿列表为空时，返回空Page对象
            return voPage;
        }

        // 3. 组装VO
        List<MomentListVO> collect = moments.stream().map(moment -> {
            MomentListVO vo = new MomentListVO();
            BeanUtils.copyProperties(moment, vo);
            vo.setTechnicianId(technician.getId());
            vo.setTechnicianNickName(technician.getTeNickName());
            vo.setTechnicianAvatar(technician.getTeAvatar());
            vo.setTechnicianStatus(getTechnicianStatus(technician));
            // 草稿的发布时间使用创建时间
            vo.setPublishTime(moment.getCreateTime());
            return vo;
        }).collect(Collectors.toList());
        //返回Page对象
        voPage.setTotal(momentPage.getTotal());
        voPage.setRecords(collect);
        return voPage;
    }

    /**
     * 查询我的动态列表（已发布的动态：审核中+审核通过+审核拒绝）
     *
     * @param openId   技师OpenID
     * @param pageNum  页码
     * @param pageSize 每页数量
     * @return Page<MyMomentVO> 我的动态列表
     */
    @Override
    public Page<MyMomentVO> getMyMoments(String openId, Integer pageNum, Integer pageSize) {
        // 1. 参数校验
        if (openId == null || openId.trim().isEmpty()) {
            throw new ServiceException("openId不能为空");
        }

        // 2. 根据openId查询技师信息
        LambdaQueryWrapper<MaTechnician> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MaTechnician::getCOpenid, openId);
        MaTechnician technician = maTechnicianMapper.selectOne(queryWrapper);
        if (technician == null) {
            throw new ServiceException("商户信息不存在");
        }

        // 3. 查询该商户的已发布动态（待审核、审核通过、审核拒绝）
        Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<TechnicianMoment> momentWrapper = new LambdaQueryWrapper<>();
        momentWrapper.eq(TechnicianMoment::getTechnicianId, technician.getId())
                .in(TechnicianMoment::getAuditStatus, 0,1, 2,3) // 1-待审核, 2-审核通过,3-审核拒绝
                .orderByDesc(TechnicianMoment::getPublishTime);

        Page<TechnicianMoment> momentPage = momentMapper.selectPage(page, momentWrapper);

        // 4. 组装分页返回结果
        Page<MyMomentVO> voPage = new Page<>(pageNum, pageSize);
        voPage.setTotal(momentPage.getTotal());
        voPage.setCurrent(momentPage.getCurrent());
        voPage.setSize(momentPage.getSize());

        List<TechnicianMoment> moments = momentPage.getRecords();
        if (moments == null || moments.isEmpty()) {
            voPage.setRecords(new ArrayList<>());
            return voPage;
        }

        // 5. 组装VO列表
        List<MyMomentVO> voList = moments.stream().map(moment -> {
            MyMomentVO vo = new MyMomentVO();
            vo.setId(moment.getId());
            vo.setTitle(moment.getTitle());
            vo.setContent(moment.getContent());
            vo.setAuditStatus(moment.getAuditStatus());
            vo.setCoverUrl(moment.getCoverUrl());
            vo.setPublishTime(moment.getPublishTime());
            vo.setViewCount(moment.getViewCount());
            return vo;
        }).collect(Collectors.toList());

        voPage.setRecords(voList);
        return voPage;
    }

    /**
     * 删除我的动态。
     *
     * <p>审核中的动态不允许删除；其它属于当前商户且未删除的动态仅做逻辑删除。</p>
     *
     * @param momentId 动态ID
     * @param openId   当前登录商户OpenID
     * @return Boolean 是否删除成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteMyMoment(Long momentId, String openId) {
        if (momentId == null) {
            throw new ServiceException("动态ID不能为空");
        }
        if (StringUtils.isBlank(openId)) {
            throw new ServiceException("openId不能为空");
        }

        LambdaQueryWrapper<MaTechnician> technicianWrapper = new LambdaQueryWrapper<>();
        technicianWrapper.eq(MaTechnician::getCOpenid, openId);
        MaTechnician technician = maTechnicianMapper.selectOne(technicianWrapper);
        if (technician == null) {
            throw new ServiceException("商户信息不存在");
        }

        TechnicianMoment moment = momentMapper.selectById(momentId);
        if (moment == null || Objects.equals(moment.getIsDelete(), DELETED)) {
            throw new ServiceException("动态不存在或已删除");
        }
        if (!Objects.equals(moment.getTechnicianId(), technician.getId())) {
            throw new ServiceException("无权删除此动态");
        }
        if (Objects.equals(moment.getAuditStatus(), AUDIT_STATUS_PENDING)) {
            throw new ServiceException("审核中的动态不支持删除");
        }

        TechnicianMoment update = new TechnicianMoment();
        update.setIsDelete(DELETED);
        update.setUpdateBy(openId);
        update.setUpdateTime(LocalDateTime.now());

        LambdaUpdateWrapper<TechnicianMoment> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(TechnicianMoment::getId, momentId)
                .eq(TechnicianMoment::getTechnicianId, technician.getId())
                .eq(TechnicianMoment::getIsDelete, NOT_DELETED);
        int rows = momentMapper.update(update, updateWrapper);
        if (rows <= 0) {
            throw new ServiceException("删除动态失败");
        }
        LambdaQueryWrapper<MomentMedia> mediaQueryWrapper = new LambdaQueryWrapper<>();
        mediaQueryWrapper.eq(MomentMedia::getMomentId, momentId);
        mediaMapper.delete(mediaQueryWrapper);
        log.info("删除动态成功，动态ID：{}，商户ID：{}", momentId, technician.getId());
        return true;
    }


    /**
     * 根据技师ID查询动态列表（已发布的动态：审核中+审核通过）
     *
     * @param technicianId 技师ID
     * @return List<MomentListVO> 动态列表
     */
    @Override
    public List<MomentListVO> getMomentsByTechnicianId(String technicianId) {
        // 1. 参数校验
        if (technicianId == null || technicianId.trim().isEmpty()) {
            throw new ServiceException("技师ID不能为空");
        }

        // 2. 查询该技师的已发布动态（待审核、审核通过）
        LambdaQueryWrapper<TechnicianMoment> momentWrapper = new LambdaQueryWrapper<>();
        momentWrapper.eq(TechnicianMoment::getTechnicianId, technicianId)
                .in(TechnicianMoment::getAuditStatus, 1, 2) // 1-待审核, 2-审核通过
                .orderByDesc(TechnicianMoment::getPublishTime);

        List<TechnicianMoment> moments = momentMapper.selectList(momentWrapper);
        if (moments == null || moments.isEmpty()) {
            return new ArrayList<>();
        }

        // 3. 组装VO列表
        List<MomentListVO> voList = moments.stream().map(moment -> {
            MomentListVO vo = new MomentListVO();
            vo.setId(moment.getId());
            vo.setTitle(moment.getTitle());
            vo.setAuditStatus(moment.getAuditStatus());
            vo.setCoverUrl(moment.getCoverUrl());
            vo.setPublishTime(moment.getPublishTime());
            vo.setViewCount(moment.getViewCount());
            return vo;
        }).collect(Collectors.toList());
        log.info("根据技师ID查询动态列表成功，技师ID：{}，记录数：{}", technicianId, voList.size());
        return voList;
    }

    /**
     * 查询待审核动态列表（管理后台）
     *
     * @param queryDTO 查询参数
     * @return Page<MomentManageVO> 分页结果
     */
    @Override
    public Page<MomentManageVO> getMomentManageList(MomentManageQueryDTO queryDTO) {
        // 1. 参数处理
        Integer pageNum = queryDTO.getPageNum() != null ? queryDTO.getPageNum() : 1;
        Integer pageSize = queryDTO.getPageSize() != null ? queryDTO.getPageSize() : 10;
        String technicianName = queryDTO.getTechnicianName();
        Integer auditStatus = queryDTO.getAuditStatus();
        String startTime = queryDTO.getStartTime();
        if (StringUtils.isNotBlank(startTime)) {
            startTime = startTime + " 00:00:00";
        }
        String endTime = queryDTO.getEndTime();
        if (StringUtils.isNotBlank(endTime)) {
            endTime = endTime + " 23:59:59";
        }

        // 2. 构建查询条件
        LambdaQueryWrapper<TechnicianMoment> queryWrapper = new LambdaQueryWrapper<>();

        // 如果传入了审核状态，则按照审核状态查询
        if (auditStatus != null) {
            queryWrapper.eq(TechnicianMoment::getAuditStatus, auditStatus);
        } else {
            // 默认查询全部的动态（待审核、审核通过、审核拒绝）
            queryWrapper.in(TechnicianMoment::getAuditStatus, 1, 2, 3);
        }

        // 技师姓名查询
        if (StringUtils.isNotBlank(technicianName)) {
            //根据技师姓名查询技师的ID
            LambdaQueryWrapper<MaTechnician> jsQueryWrapper = new LambdaQueryWrapper<>();
            jsQueryWrapper.like(MaTechnician::getTeName, technicianName);
            List<MaTechnician> technicians = maTechnicianMapper.selectList(jsQueryWrapper);
            if (CollUtil.isNotEmpty(technicians)) {
                // 构建查询条件，查询所有匹配商户的动态
                queryWrapper.in(TechnicianMoment::getTechnicianId, technicians.stream().map(MaTechnician::getId).collect(Collectors.toList()));
            } else {
                // 没有匹配的商户，查询空字符串列表
                queryWrapper.in(TechnicianMoment::getTechnicianId, Collections.singleton(""));
            }
        }

        // 时间范围查询
        if (startTime != null && !startTime.trim().isEmpty()) {
            queryWrapper.ge(TechnicianMoment::getPublishTime, startTime);
        }
        if (endTime != null && !endTime.trim().isEmpty()) {
            queryWrapper.le(TechnicianMoment::getPublishTime, endTime);
        }

        // 按创建时间倒序排序
        queryWrapper.orderByDesc(TechnicianMoment::getCreateTime);

        // 3. 分页查询
        Page<TechnicianMoment> page = new Page<>(pageNum, pageSize);
        Page<TechnicianMoment> momentPage = momentMapper.selectPage(page, queryWrapper);

        // 4. 组装VO
        Page<MomentManageVO> voPage = new Page<>(pageNum, pageSize);
        voPage.setTotal(momentPage.getTotal());
        voPage.setCurrent(momentPage.getCurrent());
        voPage.setSize(momentPage.getSize());

        List<TechnicianMoment> moments = momentPage.getRecords();
        if (moments == null || moments.isEmpty()) {
            voPage.setRecords(new ArrayList<>());
            return voPage;
        }

        // 5. 批量查询技师信息
        List<Integer> technicianIds = moments.stream().map(TechnicianMoment::getTechnicianId).collect(Collectors.toList());
        Map<Integer, MaTechnician> technicianMap = getTechnicianMap(technicianIds);

        // 6. 组装VO列表
        List<MomentManageVO> voList = moments.stream().map(moment -> {
            MomentManageVO vo = new MomentManageVO();
            BeanUtils.copyProperties(moment, vo);

            // 设置技师信息
            MaTechnician technician = technicianMap.get(moment.getTechnicianId());
            if (technician != null) {
                // 设置技师姓名
                vo.setTechnicianName(technician.getTeName());
                // 设置技师昵称
                vo.setTechnicianNickname(technician.getTeNickName());
            }
            return vo;
        }).collect(Collectors.toList());
        voPage.setRecords(voList);
        log.info("查询动态管理列表，页码：{}，每页数量：{}，总记录数：{}", pageNum, pageSize, voPage.getTotal());
        return voPage;
    }

    /**
     * 查询后台动态管理审核状态统计。
     *
     * @return MomentAuditStatusCountVO 审核状态统计
     */
    @Override
    public MomentAuditStatusCountVO getManageAuditStatusCount() {
        MomentAuditStatusCountVO count = momentMapper.selectManageAuditStatusCount();
        if (count == null) {
            count = new MomentAuditStatusCountVO();
        }
        if (count.getPendingCount() == null) {
            count.setPendingCount(0L);
        }
        if (count.getApprovedCount() == null) {
            count.setApprovedCount(0L);
        }
        if (count.getRejectedCount() == null) {
            count.setRejectedCount(0L);
        }
        return count;
    }

    /**
     * 审核动态（通过/拒绝）
     *
     * @param momentId     动态ID
     * @param auditStatus  审核状态：2-通过，3-拒绝
     * @param rejectReason 拒绝原因（拒绝时必填）
     * @return Boolean 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean auditMoment(MomentAuditDTO dto) {
        // 1. 参数校验
        if (dto.getMomentId() == null) {
            throw new ServiceException("动态ID不能为空");
        }
        if (dto.getAuditStatus() == null || (dto.getAuditStatus() != 2 && dto.getAuditStatus() != 3)) {
            throw new ServiceException("审核状态不正确");
        }
        if (dto.getAuditStatus() == 3 && (dto.getRejectReason() == null || dto.getRejectReason().trim().isEmpty())) {
            throw new ServiceException("拒绝时必须填写拒绝原因");
        }

        // 2. 查询动态信息
        TechnicianMoment moment = momentMapper.selectById(dto.getMomentId());
        if (moment == null) {
            throw new ServiceException("动态不存在");
        }

        // 3. 校验动态状态
        if (moment.getAuditStatus() != 1) {
            throw new ServiceException("只能审核待审核状态的动态");
        }

        // 4. 更新审核状态
        moment.setAuditStatus(dto.getAuditStatus());
        // 审核通过默认上架状态和推荐状态
        if(dto.getAuditStatus()==2){
            moment.setIsRecommend(1);
            moment.setIsList(1);
        }
        moment.setRejectReason(dto.getRejectReason());
        moment.setUpdateTime(LocalDateTime.now());

        int updateResult = momentMapper.updateById(moment);
        if (updateResult <= 0) {
            throw new ServiceException("审核失败");
        }
        return true;
    }

    /**
     * 更新动态推荐状态
     *
     * @param momentId    动态ID
     * @param isRecommend 是否推荐:0-否,1-是
     * @return 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateRecommendStatus(Long momentId, Integer isRecommend) {
        if (momentId == null) {
            throw new ServiceException("动态ID不能为空");
        }
        if (isRecommend == null || (isRecommend != 0 && isRecommend != 1)) {
            throw new ServiceException("是否推荐参数不正确");
        }

        int rows = momentMapper.updateRecommendStatus(momentId, isRecommend);
        if (rows <= 0) {
            throw new ServiceException("动态不存在或已删除");
        }
        log.info("更新动态推荐状态成功，动态ID：{}，是否推荐：{}", momentId, isRecommend);
        return true;
    }

    /**
     * 更新动态上架状态
     *
     * @param momentId 动态ID
     * @param isList   是否上架:0-否,1-是
     * @return Boolean 是否成功
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateListStatus(Long momentId, Integer isList) {
        if (momentId == null) {
            throw new ServiceException("动态ID不能为空");
        }
        if (isList == null || (isList != 0 && isList != 1)) {
            throw new ServiceException("上架状态参数不正确");
        }

        int rows = momentMapper.updateListStatus(momentId, isList);
        if (rows <= 0) {
            throw new ServiceException("动态不存在或已删除");
        }
        log.info("更新动态上架状态成功，动态ID：{}，是否上架：{}", momentId, isList);
        return true;
    }

    /**
     * 根据动态ID查询动态简要详情（包含媒体URL列表）
     *
     * @param momentId 动态ID
     * @return MomentSimpleDetailVO动态简要详情
     */
    @Override
    public MomentSimpleDetailVO getMomentSimpleDetail(Long momentId) {
        // 1. 参数校验
        if (momentId == null) {
            throw new ServiceException("动态ID不能为空");
        }

        // 2. 查询动态信息
        Map<String, Object> result = momentMapper.selectMomentSimpleDetail(momentId);
        if (result == null || result.isEmpty()) {
            throw new ServiceException("动态不存在");
        }

        // 3. 组装VO
        MomentSimpleDetailVO vo = new MomentSimpleDetailVO();
        vo.setId(((Number) result.get("id")).longValue());
        vo.setTitle((String) result.get("title"));
        vo.setContent((String) result.get("content"));
        vo.setMediaType((Integer) result.get("media_type"));
        vo.setAuditStatus((Integer) result.get("audit_status"));
        vo.setRejectReason((String) result.get("reject_reason"));

        // 4. 处理媒体URL列表
        String mediaUrlsStr = (String) result.get("media_urls");
        if (mediaUrlsStr != null && !mediaUrlsStr.trim().isEmpty()) {
            // 将逗号分隔的字符串转换为List
            List<String> mediaUrls = Arrays.asList(mediaUrlsStr.split(","));
            vo.setMediaUrls(mediaUrls);
        } else {
            vo.setMediaUrls(new ArrayList<>());
        }
        log.info("查询动态简要详情成功，动态ID：{}", momentId);
        return vo;
    }

    @Override
    public Page<MomentVO> getByMerchantMoment(MerchantMomentDTO dto) {
        Page<MomentVO> page = new Page<>(dto.getCurrent(), dto.getSize());
        return this.baseMapper.getMerchantProject(page, dto);
    }

    @Override
    public Page<MomentPageVO> getMomentPage(MomentPageDTO dto) {
        Page<MomentPageVO> page = new Page<>(dto.getCurrent(), dto.getSize());
        return this.baseMapper.getMomentPage(page, dto);
    }

}
