package com.starry.admin.modules.clerk.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
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.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.starry.admin.common.component.JwtToken;
import com.starry.admin.common.domain.LoginUser;
import com.starry.admin.common.exception.CustomException;
import com.starry.admin.modules.clerk.enums.ClerkMediaReviewState;
import com.starry.admin.modules.clerk.enums.ClerkMediaUsage;
import com.starry.admin.modules.clerk.mapper.PlayClerkUserInfoMapper;
import com.starry.admin.modules.clerk.module.entity.PlayClerkCommodityEntity;
import com.starry.admin.modules.clerk.module.entity.PlayClerkDataReviewInfoEntity;
import com.starry.admin.modules.clerk.module.entity.PlayClerkLevelInfoEntity;
import com.starry.admin.modules.clerk.module.entity.PlayClerkMediaAssetEntity;
import com.starry.admin.modules.clerk.module.entity.PlayClerkUserInfoEntity;
import com.starry.admin.modules.clerk.module.entity.PlayClerkUserQueryVo;
import com.starry.admin.modules.clerk.module.entity.PlayClerkUserReturnVo;
import com.starry.admin.modules.clerk.module.entity.PlayClerkUserReviewInfoEntity;
import com.starry.admin.modules.clerk.module.enums.ClerkRoleStatus;
import com.starry.admin.modules.clerk.module.enums.ListingStatus;
import com.starry.admin.modules.clerk.module.enums.OnboardingStatus;
import com.starry.admin.modules.clerk.module.vo.PlayClerkCommodityQueryVo;
import com.starry.admin.modules.clerk.module.vo.PlayClerkUnsettledWagesInfoQueryVo;
import com.starry.admin.modules.clerk.module.vo.PlayClerkUnsettledWagesInfoReturnVo;
import com.starry.admin.modules.clerk.service.IPlayClerkCommodityService;
import com.starry.admin.modules.clerk.service.IPlayClerkDataReviewInfoService;
import com.starry.admin.modules.clerk.service.IPlayClerkLevelInfoService;
import com.starry.admin.modules.clerk.service.IPlayClerkMediaAssetService;
import com.starry.admin.modules.clerk.service.IPlayClerkUserInfoService;
import com.starry.admin.modules.custom.entity.PlayCustomFollowInfoEntity;
import com.starry.admin.modules.custom.service.IPlayCustomFollowInfoService;
import com.starry.admin.modules.media.entity.PlayMediaEntity;
import com.starry.admin.modules.media.enums.MediaStatus;
import com.starry.admin.modules.media.service.IPlayMediaService;
import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity;
import com.starry.admin.modules.order.service.IPlayOrderInfoService;
import com.starry.admin.modules.personnel.module.entity.PlayPersonnelAdminInfoEntity;
import com.starry.admin.modules.personnel.module.entity.PlayPersonnelGroupInfoEntity;
import com.starry.admin.modules.personnel.module.entity.PlayPersonnelWaiterInfoEntity;
import com.starry.admin.modules.personnel.service.IPlayBalanceDetailsInfoService;
import com.starry.admin.modules.personnel.service.IPlayPersonnelAdminInfoService;
import com.starry.admin.modules.personnel.service.IPlayPersonnelGroupInfoService;
import com.starry.admin.modules.personnel.service.IPlayPersonnelWaiterInfoService;
import com.starry.admin.modules.statistics.module.vo.PlayClerkPerformanceInfoQueryVo;
import com.starry.admin.modules.system.service.LoginService;
import com.starry.admin.modules.weichat.assembler.ClerkMediaAssembler;
import com.starry.admin.modules.weichat.entity.PlayClerkUserLoginResponseVo;
import com.starry.admin.modules.weichat.entity.clerk.MediaVo;
import com.starry.admin.modules.weichat.entity.clerk.PlayClerkUserInfoQueryVo;
import com.starry.admin.modules.weichat.entity.clerk.PlayClerkUserInfoResultVo;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.utils.ConvertUtil;
import com.starry.common.utils.IdUtils;
import com.starry.common.utils.StringUtils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;

/**
 * 店员Service业务层处理
 *
 * @author admin
 * @since 2024-03-30
 */
@Service
public class PlayClerkUserInfoServiceImpl extends ServiceImpl<PlayClerkUserInfoMapper, PlayClerkUserInfoEntity> implements IPlayClerkUserInfoService {

    private static final String OFFBOARD_MESSAGE = "你已离职，需要复职请联系店铺管理员";
    private static final String DELISTED_MESSAGE = "你已被下架，没有权限访问";
    private static final String INVALID_CLERK_MESSAGE = "你不是有效店员，无法执行该操作";
    @Resource
    private PlayClerkUserInfoMapper playClerkUserInfoMapper;
    @Resource
    private PlayClerkUserReviewInfoServiceImpl playClerkUserReviewInfoService;
    @Resource
    private IPlayClerkCommodityService playClerkCommodityService;
    @Resource
    private IPlayClerkDataReviewInfoService playClerkDataReviewInfoService;
    @Resource
    private IPlayCustomFollowInfoService customFollowInfoService;
    @Resource
    private IPlayClerkMediaAssetService clerkMediaAssetService;
    @Resource
    private IPlayMediaService mediaService;
    @Resource
    private IPlayBalanceDetailsInfoService playBalanceDetailsInfoService;
    @Resource
    private IPlayOrderInfoService playOrderInfoService;
    @Resource
    private IPlayPersonnelGroupInfoService playClerkGroupInfoService;
    @Resource
    private IPlayPersonnelAdminInfoService playPersonnelAdminInfoService;
    @Resource
    private IPlayPersonnelWaiterInfoService playClerkWaiterInfoService;
    @Resource
    private LoginService loginService;
    @Resource
    private JwtToken jwtToken;
    @Resource
    private IPlayClerkLevelInfoService playClerkLevelInfoService;

    @Override
    public List<PlayClerkUserInfoEntity> listAllByTypeId(String typeId) {
        MPJLambdaWrapper<PlayClerkUserInfoEntity> lambdaWrapper = new MPJLambdaWrapper<>();
        lambdaWrapper.select(PlayClerkUserInfoEntity::getId);
        lambdaWrapper.eq(PlayClerkUserInfoEntity::getTypeId, typeId);
        return this.baseMapper.selectList(lambdaWrapper);
    }

    @Override
    public List<PlayClerkUserInfoEntity> listAllByGroupId(String groupId) {
        MPJLambdaWrapper<PlayClerkUserInfoEntity> lambdaWrapper = new MPJLambdaWrapper<>();
        lambdaWrapper.select(PlayClerkUserInfoEntity::getId, PlayClerkUserInfoEntity::getListingState);
        lambdaWrapper.eq(PlayClerkUserInfoEntity::getGroupId, groupId);
        return this.baseMapper.selectList(lambdaWrapper);
    }

    @Override
    public Long getTotalClerkUser(String tenantId) {
        MPJLambdaWrapper<PlayClerkUserInfoEntity> lambdaWrapper = new MPJLambdaWrapper<>();
        lambdaWrapper.eq(PlayClerkUserInfoEntity::getTenantId, tenantId);
        return this.baseMapper.selectCount(lambdaWrapper);
    }

    @Override
    public PlayClerkLevelInfoEntity queryLevelCommission(String clerkId) {
        MPJLambdaWrapper<PlayClerkUserInfoEntity> lambdaWrapper = new MPJLambdaWrapper<>();
        lambdaWrapper.selectAll(PlayClerkLevelInfoEntity.class);
        lambdaWrapper.selectAs(PlayClerkUserInfoEntity::getLevelId, "levelId");
        lambdaWrapper.leftJoin(PlayClerkLevelInfoEntity.class, PlayClerkLevelInfoEntity::getId, PlayClerkUserInfoEntity::getLevelId);
        lambdaWrapper.eq(PlayClerkUserInfoEntity::getId, clerkId);
        PlayClerkLevelInfoEntity levelInfo = this.baseMapper.selectJoinOne(PlayClerkLevelInfoEntity.class, lambdaWrapper);
        if (levelInfo != null) {
            return levelInfo;
        }

        PlayClerkUserInfoEntity clerk = this.baseMapper.selectById(clerkId);
        if (clerk == null || StringUtils.isBlank(clerk.getLevelId())) {
            return null;
        }
        return playClerkLevelInfoService.getById(clerk.getLevelId());

    }

    @Override
    public PlayClerkUserInfoEntity selectByOpenid(String openId) {
        LambdaQueryWrapper<PlayClerkUserInfoEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getOpenid, openId);
        return this.baseMapper.selectOne(lambdaQueryWrapper);
    }

    /**
     * 查询店员
     *
     * @param id 店员主键
     * @return 店员
     */
    @Override
    public PlayClerkUserInfoEntity selectById(String id) {
        PlayClerkUserInfoEntity entity = this.baseMapper.selectById(id);
        if (entity == null) {
            throw new CustomException("店员不存在");
        }
        return entity;
    }

    @Override
    public PlayClerkUserLoginResponseVo getVo(PlayClerkUserInfoEntity userInfo) {
        PlayClerkUserLoginResponseVo result = ConvertUtil.entityToVo(userInfo, PlayClerkUserLoginResponseVo.class);
        List<PlayClerkDataReviewInfoEntity> pendingReviews = playClerkDataReviewInfoService.queryByClerkId(userInfo.getId(), "0");
        if (pendingReviews != null && !pendingReviews.isEmpty()) {
            Set<String> pendingTypes = pendingReviews.stream().map(PlayClerkDataReviewInfoEntity::getDataType).filter(StrUtil::isNotBlank).collect(Collectors.toSet());
            if (pendingTypes.contains("0")) {
                result.setNicknameAllowEdit(false);
            }
            if (pendingTypes.contains("1")) {
                result.setAvatarAllowEdit(false);
            }
            if (pendingTypes.contains("2")) {
                result.setAlbumAllowEdit(false);
            }
            if (pendingTypes.contains("3")) {
                result.setAudioAllowEdit(false);
            }
            if (pendingTypes.contains("4")) {
                result.setSexAllowEdit(false);
            }
        }
        // 是店员之后，判断是否可以登录
        if (ClerkRoleStatus.isClerk(result.getClerkState())) {
            // 设置店员是否运行登录
            if (OnboardingStatus.isOffboarded(userInfo.getOnboardingState())) {
                result.setAllowLogin("1");
                result.setDisableLoginReason("你已离职，需要复职请联系店铺管理员");
            }
            if (ListingStatus.isDelisted(userInfo.getListingState())) {
                result.setAllowLogin("1");
                result.setDisableLoginReason("你已被下架，没有权限访问");
            }

        }

        // 如果存在未审批的申请，或者当前已经是店员-可以申请陪聊
        PlayClerkUserReviewInfoEntity entity = playClerkUserReviewInfoService.queryByClerkId(userInfo.getId(), "0");
        if (entity != null || ClerkRoleStatus.isClerk(result.getClerkState())) {
            result.setClerkAllowEdit(false);
        }

        // 查询店员服务项目
        List<PlayClerkCommodityEntity> clerkCommodityEntities = playClerkCommodityService.selectCommodityTypeByUser(userInfo.getId(), "");
        List<PlayClerkCommodityQueryVo> playClerkCommodityQueryVos = new ArrayList<>();
        for (PlayClerkCommodityEntity clerkCommodityEntity : clerkCommodityEntities) {
            playClerkCommodityQueryVos.add(new PlayClerkCommodityQueryVo(clerkCommodityEntity.getCommodityName(), clerkCommodityEntity.getEnablingState()));
        }
        result.setCommodity(playClerkCommodityQueryVos);
        result.setArea(userInfo.getProvince() + "-" + userInfo.getCity());

        result.setPcData(this.getPcData(userInfo));
        result.setLevelInfo(playClerkLevelInfoService.selectPlayClerkLevelInfoById(userInfo.getLevelId()));
        List<MediaVo> mediaList = loadMediaForClerk(userInfo.getId(), true);
        result.setMediaList(mergeLegacyAlbum(userInfo.getAlbum(), mediaList));
        result.setAlbum(CollectionUtil.isEmpty(userInfo.getAlbum()) ? new ArrayList<>() : new ArrayList<>(userInfo.getAlbum()));
        return result;
    }

    @Override
    public void ensureClerkIsActive(PlayClerkUserInfoEntity clerkUserInfoEntity) {
        ensureClerkSessionIsValid(clerkUserInfoEntity);
        if (!ClerkRoleStatus.isClerk(clerkUserInfoEntity.getClerkState())) {
            invalidateClerkSession(clerkUserInfoEntity.getId());
            throw new CustomException(INVALID_CLERK_MESSAGE);
        }
    }

    @Override
    public void ensureClerkSessionIsValid(PlayClerkUserInfoEntity clerkUserInfoEntity) {
        if (Objects.isNull(clerkUserInfoEntity)) {
            throw new CustomException("店员不存在");
        }
        if (Boolean.TRUE.equals(clerkUserInfoEntity.getDeleted())) {
            invalidateClerkSession(clerkUserInfoEntity.getId());
            throw new CustomException(INVALID_CLERK_MESSAGE);
        }
        if (OnboardingStatus.isOffboarded(clerkUserInfoEntity.getOnboardingState())) {
            invalidateClerkSession(clerkUserInfoEntity.getId());
            throw new CustomException(OFFBOARD_MESSAGE);
        }
        if (ListingStatus.isDelisted(clerkUserInfoEntity.getListingState())) {
            invalidateClerkSession(clerkUserInfoEntity.getId());
            throw new CustomException(DELISTED_MESSAGE);
        }
    }

    @Override
    public void invalidateClerkSession(String clerkId) {
        if (StrUtil.isBlank(clerkId)) {
            return;
        }
        LambdaUpdateWrapper<PlayClerkUserInfoEntity> wrapper = Wrappers.lambdaUpdate(PlayClerkUserInfoEntity.class).eq(PlayClerkUserInfoEntity::getId, clerkId).set(PlayClerkUserInfoEntity::getToken, "empty").set(PlayClerkUserInfoEntity::getOnlineState, "0");
        this.baseMapper.update(null, wrapper);
    }

    @Override
    public void updateTokenById(String id, String token) {
        PlayClerkUserInfoEntity entity = new PlayClerkUserInfoEntity();
        entity.setToken(token);
        entity.setId(id);
        this.baseMapper.updateById(entity);
    }

    @Override
    public void updateAccountBalanceById(String id, BigDecimal accountBalance) {

    }

    @Override
    public void updateAccountBalanceById(String userId, BigDecimal balanceBeforeOperation, BigDecimal balanceAfterOperation, String operationType, String operationAction, BigDecimal balanceMoney, String orderId) {
        // 修改用户余额
        this.baseMapper.updateById(new PlayClerkUserInfoEntity(userId, balanceAfterOperation));
        // 记录余额变更记录
        playBalanceDetailsInfoService.insertBalanceDetailsInfo("0", userId, balanceBeforeOperation, balanceAfterOperation, operationType, operationAction, balanceMoney, BigDecimal.ZERO, orderId);
    }

    /**
     * 查询店员列表
     *
     * @param vo 店员查询对象
     * @return 店员
     */
    @Override
    public IPage<PlayClerkUserInfoResultVo> selectPlayClerkUserInfoByPage(PlayClerkUserInfoQueryVo vo) {
        Page<PlayClerkUserInfoResultVo> page = new Page<>(vo.getPageNum(), vo.getPageSize());

        MPJLambdaWrapper<PlayClerkUserInfoEntity> lambdaQueryWrapper = new MPJLambdaWrapper<>();
        // 查询不隐藏的
        lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getDisplayState, "1");
        // 查询主表全部字段
        lambdaQueryWrapper.selectAll(PlayClerkUserInfoEntity.class).selectAs(PlayClerkUserInfoEntity::getCity, "address");
        // 等级表
        lambdaQueryWrapper.selectAs(PlayClerkLevelInfoEntity::getName, "levelName");
        lambdaQueryWrapper.leftJoin(PlayClerkLevelInfoEntity.class, PlayClerkLevelInfoEntity::getId, PlayClerkUserInfoEntity::getLevelId);

        // 服务项目表
        if (StrUtil.isNotBlank(vo.getNickname())) {
            lambdaQueryWrapper.like(PlayClerkUserInfoEntity::getNickname, vo.getNickname());
        }
        if (StrUtil.isNotBlank(vo.getTypeId())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getTypeId, vo.getTypeId());
        }
        if (StrUtil.isNotBlank(vo.getLevelId())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getLevelId, vo.getLevelId());
        }
        if (StrUtil.isNotBlank(vo.getSex())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getSex, vo.getSex());
        }
        if (StrUtil.isNotBlank(vo.getProvince())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getProvince, vo.getProvince());
        }
        if (StrUtil.isNotBlank(vo.getClerkState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getClerkState, vo.getClerkState());
        }
        if (StrUtil.isNotBlank(vo.getRecommendationState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getRecommendationState, vo.getRecommendationState());
        }
        if (StrUtil.isNotBlank(vo.getOnboardingState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getOnboardingState, vo.getOnboardingState());
        }

        // 排序：非空的等级排序号优先，值越小越靠前；同一排序号在线状态优先
        lambdaQueryWrapper
                .orderByDesc(PlayClerkUserInfoEntity::getOnlineState)
                .orderByDesc(PlayClerkUserInfoEntity::getPinToTopState)
                .orderByAsc(true, "CASE WHEN t1.order_number IS NULL THEN 1 ELSE 0 END")
                .orderByAsc(PlayClerkLevelInfoEntity::getOrderNumber)
                .orderByAsc(PlayClerkUserInfoEntity::getCreatedTime)
                .orderByAsc(PlayClerkUserInfoEntity::getNickname)
                .orderByAsc(PlayClerkUserInfoEntity::getId);

        IPage<PlayClerkUserInfoResultVo> pageResult = this.baseMapper.selectJoinPage(page,
                PlayClerkUserInfoResultVo.class, lambdaQueryWrapper);
        if (pageResult != null && pageResult.getRecords() != null) {
            List<PlayClerkUserInfoResultVo> deduped = new ArrayList<>();
            Set<String> seen = new HashSet<>();
            for (PlayClerkUserInfoResultVo record : pageResult.getRecords()) {
                String id = record.getId();
                if (id == null || !seen.add(id)) {
                    continue;
                }
                deduped.add(record);
            }
            pageResult.setRecords(deduped);
        }
        if (pageResult != null) {
            attachMediaToResultVos(pageResult.getRecords(), false);
        }
        return pageResult;
    }

    @Override
    public List<PlayClerkUserInfoEntity> listAll() {
        LambdaQueryWrapper<PlayClerkUserInfoEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getClerkState, ClerkRoleStatus.CLERK.getCode());
        return this.baseMapper.selectList(lambdaQueryWrapper);

    }

    @Override
    public IPage<PlayClerkUnsettledWagesInfoReturnVo> listUnsettledWagesByPage(PlayClerkUnsettledWagesInfoQueryVo vo) {
        MPJLambdaWrapper<PlayClerkUserInfoEntity> lambdaQueryWrapper = new MPJLambdaWrapper<>();
        // 查询所有店员
        lambdaQueryWrapper.selectAs(PlayClerkUserInfoEntity::getNickname, "clerkNickname").selectAs(PlayClerkUserInfoEntity::getId, "clerkId");
        lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getClerkState, ClerkRoleStatus.CLERK.getCode());
        // 加入组员的筛选
        List<String> clerkIdList = playClerkGroupInfoService.getValidClerkIdList(SecurityUtils.getLoginUser(), null);
        lambdaQueryWrapper.in(PlayClerkUserInfoEntity::getId, clerkIdList);
        if (StrUtil.isNotBlank(vo.getClerkId())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getId, vo.getClerkId());
        }
        if (StrUtil.isNotBlank(vo.getListingState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getListingState, vo.getListingState());
        }
        // 查询店员订单信息
        lambdaQueryWrapper.selectCollection(PlayOrderInfoEntity.class, PlayClerkUnsettledWagesInfoReturnVo::getOrderInfoEntities);
        lambdaQueryWrapper.leftJoin(PlayOrderInfoEntity.class, PlayOrderInfoEntity::getAcceptBy, PlayClerkUserInfoEntity::getId);
        lambdaQueryWrapper.eq(PlayOrderInfoEntity::getOrderSettlementState, "0");

        return this.baseMapper.selectJoinPage(new Page<>(vo.getPageNum(), vo.getPageSize()), PlayClerkUnsettledWagesInfoReturnVo.class, lambdaQueryWrapper);
    }

    @Override
    public IPage<PlayClerkUserInfoEntity> selectByPage(PlayClerkPerformanceInfoQueryVo vo) {
        LambdaQueryWrapper<PlayClerkUserInfoEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotBlank(vo.getClerkId())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getId, vo.getClerkId());
        }
        // if (StrUtil.isNotBlank(vo.getGroupId())) {
        // lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getGroupId, vo.getGroupId());
        // }
        if (StrUtil.isNotBlank(vo.getSex())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getSex, vo.getSex());
        }
        if (StrUtil.isNotBlank(vo.getListingState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getListingState, vo.getListingState());
        }
        lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getClerkState, "1");
        // 加入组员的筛选
        List<String> clerkIdList = playClerkGroupInfoService.getValidClerkIdList(SecurityUtils.getLoginUser(), null);
        lambdaQueryWrapper.in(PlayClerkUserInfoEntity::getId, clerkIdList);
        return this.baseMapper.selectPage(new Page<>(vo.getPageNum(), vo.getPageSize()), lambdaQueryWrapper);
    }

    @Override
    public IPage<PlayClerkUserReturnVo> selectByPage(PlayClerkUserQueryVo vo) {
        MPJLambdaWrapper<PlayClerkUserInfoEntity> lambdaQueryWrapper = new MPJLambdaWrapper<>();

        LoginUser loginUser = SecurityUtils.getLoginUser();
        // 主表（店员表全部字段）
        lambdaQueryWrapper.selectAll(PlayClerkUserInfoEntity.class);

        if (StrUtil.isNotBlank(vo.getId())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getId, vo.getId());
        }
        if (StrUtil.isNotBlank(vo.getNickname())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getNickname, vo.getNickname());
        }
        if (StrUtil.isNotBlank(vo.getPhone())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getPhone, vo.getPhone());
        }
        if (StrUtil.isNotBlank(vo.getGroupId())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getGroupId, vo.getGroupId());
        }
        if (StrUtil.isNotBlank(vo.getSex())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getSex, vo.getSex());
        }
        if (StrUtil.isNotBlank(vo.getFixingLevel())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getFixingLevel, vo.getFixingLevel());
        }
        if (StrUtil.isNotBlank(vo.getLevelId())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getLevelId, vo.getLevelId());
        }
        if (StrUtil.isNotBlank(vo.getListingState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getListingState, vo.getListingState());
        }
        if (StrUtil.isNotBlank(vo.getRandomOrderState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getRandomOrderState, vo.getRandomOrderState());
        }
        if (StrUtil.isNotBlank(vo.getProvince())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getProvince, vo.getProvince());
        }
        if (StrUtil.isNotBlank(vo.getCity())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getCity, vo.getCity());
        }
        if (StrUtil.isNotBlank(vo.getOnboardingState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getOnboardingState, vo.getOnboardingState());
        }
        if (StrUtil.isNotBlank(vo.getRecommendationState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getRecommendationState, vo.getRecommendationState());
        }
        if (StrUtil.isNotBlank(vo.getPinToTopState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getPinToTopState, vo.getPinToTopState());
        }
        if (StrUtil.isNotBlank(vo.getOnlineState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getOnlineState, vo.getOnlineState());
        }
        if (StrUtil.isNotBlank(vo.getDisplayState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getDisplayState, vo.getDisplayState());
        }
        if (StrUtil.isNotBlank(vo.getRealState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getRealState, vo.getRealState());
        }
        if (StrUtil.isNotBlank(vo.getMandatoryRealState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getMandatoryRealState, vo.getMandatoryRealState());
        }
        if (StrUtil.isNotBlank(vo.getClerkState())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getClerkState, vo.getClerkState());
        }
        if (StrUtil.isNotBlank(vo.getCode())) {
            lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getCode, vo.getCode());
        }

        // 加入组员的筛选
        List<String> clerkIdList = playClerkGroupInfoService.getValidClerkIdList(SecurityUtils.getLoginUser(), null);
        lambdaQueryWrapper.in(PlayClerkUserInfoEntity::getId, clerkIdList);

        // 排序：置顶状态优先，在线用户其次，最后按创建时间倒序
        lambdaQueryWrapper.orderByDesc(PlayClerkUserInfoEntity::getPinToTopState).orderByDesc(PlayClerkUserInfoEntity::getOnlineState).orderByDesc(PlayClerkUserInfoEntity::getCreatedTime);

        IPage<PlayClerkUserReturnVo> page = this.baseMapper.selectJoinPage(new Page<>(vo.getPageNum(), vo.getPageSize()), PlayClerkUserReturnVo.class, lambdaQueryWrapper);

        for (PlayClerkUserReturnVo record : page.getRecords()) {
            BigDecimal orderTotalAmount = new BigDecimal("0");
            int orderContinueNumber = 0;
            int orderNumber = 0;
            for (PlayOrderInfoEntity orderInfo : playOrderInfoService.queryBySettlementOrder(record.getId(), "")) {
                if ("0".equals(orderInfo.getFirstOrder())) {
                    orderContinueNumber++;
                }
                orderNumber++;
                if (!"4".equals(orderInfo.getOrderStatus())) {
                    orderTotalAmount = orderTotalAmount.add(orderInfo.getFinalAmount());
                }
            }
            record.setOrderTotalAmount(orderTotalAmount);
            record.setOrderNumber(String.valueOf(orderNumber));
            record.setOrderContinueNumber(String.valueOf(orderContinueNumber));
        }

        attachMediaToAdminVos(page.getRecords());
        return page;
    }

    @Override
    public IPage<PlayClerkUserInfoResultVo> selectByPage(PlayClerkUserInfoQueryVo vo, String customUserId) {
        IPage<PlayClerkUserInfoResultVo> voPage = this.selectPlayClerkUserInfoByPage(vo);
        Map<String, String> customFollows = new HashMap<>(16);
        // 如果当前顾客已登录，查询用户关注状态
        if (StrUtil.isNotBlank(customUserId)) {
            LambdaQueryWrapper<PlayCustomFollowInfoEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(PlayCustomFollowInfoEntity::getCustomId, customUserId);
            List<PlayCustomFollowInfoEntity> customFollowInfoEntities = customFollowInfoService.list(lambdaQueryWrapper);
            customFollows = customFollowInfoEntities.stream().collect(Collectors.toMap(PlayCustomFollowInfoEntity::getClerkId, PlayCustomFollowInfoEntity::getFollowState));
        }
        for (PlayClerkUserInfoResultVo record : voPage.getRecords()) {
            record.setFollowState(customFollows.containsKey(record.getId()) ? "1" : "0");
            record.setCommodity(playClerkCommodityService.getClerkCommodityList(record.getId(), "1"));
        }
        voPage.getRecords().parallelStream().forEach(ca -> {
            ca.setLevelInfo(playClerkLevelInfoService.selectPlayClerkLevelInfoById(ca.getLevelId()));
        });
        return voPage;
    }

    @Override
    public PlayClerkUserInfoResultVo buildCustomerDetail(String clerkId, String customUserId) {
        PlayClerkUserInfoEntity entity = this.baseMapper.selectById(clerkId);
        if (entity == null) {
            throw new CustomException("店员不存在");
        }
        PlayClerkUserInfoResultVo vo = ConvertUtil.entityToVo(entity, PlayClerkUserInfoResultVo.class);
        vo.setAddress(entity.getCity());
        vo.setCommodity(playClerkCommodityService.getClerkCommodityList(vo.getId(), "1"));

        String followState = "0";
        if (StrUtil.isNotBlank(customUserId)) {
            LambdaQueryWrapper<PlayCustomFollowInfoEntity> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(PlayCustomFollowInfoEntity::getCustomId, customUserId)
                    .eq(PlayCustomFollowInfoEntity::getClerkId, clerkId);
            PlayCustomFollowInfoEntity followInfo = customFollowInfoService.getOne(wrapper, false);
            if (followInfo != null && "1".equals(followInfo.getFollowState())) {
                followState = "1";
            }
        }
        vo.setFollowState(followState);

        List<MediaVo> mediaList = loadMediaForClerk(clerkId, false);
        vo.setMediaList(mergeLegacyAlbum(entity.getAlbum(), mediaList));
        return vo;
    }

    /**
     * 新增店员
     *
     * @param playClerkUserInfo 店员
     * @return 结果
     */
    @Override
    public boolean create(PlayClerkUserInfoEntity playClerkUserInfo) {
        if (StrUtil.isBlankIfStr(playClerkUserInfo.getId())) {
            playClerkUserInfo.setId(IdUtils.getUuid());
        }
        return save(playClerkUserInfo);
    }

    /**
     * 修改店员
     *
     * @param playClerkUserInfo 店员
     * @return 结果
     */
    @Override
    public boolean update(PlayClerkUserInfoEntity playClerkUserInfo) {
        boolean inspectStatus = StringUtils.isNotBlank(playClerkUserInfo.getId()) && (StrUtil.isNotBlank(playClerkUserInfo.getOnboardingState()) || StrUtil.isNotBlank(playClerkUserInfo.getListingState()) || StrUtil.isNotBlank(playClerkUserInfo.getClerkState()));
        PlayClerkUserInfoEntity beforeUpdate = null;
        if (inspectStatus) {
            beforeUpdate = this.baseMapper.selectById(playClerkUserInfo.getId());
        }
        boolean updated = updateById(playClerkUserInfo);
        if (updated && inspectStatus && beforeUpdate != null) {
            handleStatusSideEffects(playClerkUserInfo, beforeUpdate);
        }
        return updated;
    }

    /**
     * 批量删除店员
     *
     * @param ids 需要删除的店员主键
     * @return 结果
     */
    @Override
    public int deletePlayClerkUserInfoByIds(String[] ids) {
        return playClerkUserInfoMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除店员信息
     *
     * @param id 店员主键
     * @return 结果
     */
    @Override
    public int deletePlayClerkUserInfoById(String id) {
        return playClerkUserInfoMapper.deleteById(id);
    }

    @Override
    public List<PlayClerkUserInfoEntity> simpleList() {
        List<String> clerkIdList = playClerkGroupInfoService.getValidClerkIdList(SecurityUtils.getLoginUser(), null);
        LambdaQueryWrapper<PlayClerkUserInfoEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(PlayClerkUserInfoEntity::getDeleted, 0);
        lambdaQueryWrapper.in(PlayClerkUserInfoEntity::getId, clerkIdList);
        lambdaQueryWrapper.select(PlayClerkUserInfoEntity::getId, PlayClerkUserInfoEntity::getNickname, PlayClerkUserInfoEntity::getAvatar, PlayClerkUserInfoEntity::getTypeId, PlayClerkUserInfoEntity::getGroupId, PlayClerkUserInfoEntity::getPhone);
        lambdaQueryWrapper.orderByDesc(PlayClerkUserInfoEntity::getId);
        return this.baseMapper.selectList(lambdaQueryWrapper);
    }

    @Override
    public List<PlayClerkUserInfoEntity> listWithAlbumIgnoringTenant() {
        return playClerkUserInfoMapper.selectAllWithAlbumIgnoringTenant();
    }

    @Override
    public JSONObject getPcData(PlayClerkUserInfoEntity entity) {
        JSONObject data = new JSONObject();
        data.fluentPut("token", "");
        data.fluentPut("role", "");
        if (StringUtils.isEmpty(entity.getSysUserId())) {
            return data;
        }
        LoginUser loginUserInfo = loginService.getLoginUserInfo(entity.getSysUserId());
        Map<String, Object> tokenMap = jwtToken.createToken(loginUserInfo);
        data.fluentPut("token", tokenMap.get("token"));
        PlayPersonnelAdminInfoEntity adminInfoEntity = playPersonnelAdminInfoService.selectByUserId(entity.getSysUserId());
        if (Objects.nonNull(adminInfoEntity)) {
            data.fluentPut("role", "operator");
            return data;
        }
        PlayPersonnelGroupInfoEntity groupInfoEntity = playClerkGroupInfoService.selectByUserId(entity.getSysUserId());
        if (Objects.nonNull(groupInfoEntity)) {
            data.fluentPut("role", "leader");
            return data;
        }
        PlayPersonnelWaiterInfoEntity waiterInfoEntity = playClerkWaiterInfoService.selectByUserId(entity.getSysUserId());
        if (Objects.nonNull(waiterInfoEntity)) {
            data.fluentPut("role", "waiter");
            return data;
        }
        return data;
    }

    private void handleStatusSideEffects(PlayClerkUserInfoEntity updatedPayload, PlayClerkUserInfoEntity beforeUpdate) {
        if (beforeUpdate == null) {
            return;
        }
        if (OnboardingStatus.transitionedToOffboarded(updatedPayload.getOnboardingState(), beforeUpdate.getOnboardingState()) || ListingStatus.transitionedToDelisted(updatedPayload.getListingState(), beforeUpdate.getListingState()) || ClerkRoleStatus.transitionedToNonClerk(updatedPayload.getClerkState(), beforeUpdate.getClerkState())) {
            invalidateClerkSession(beforeUpdate.getId());
        }
    }
    private void attachMediaToResultVos(List<PlayClerkUserInfoResultVo> records, boolean includePending) {
        if (CollectionUtil.isEmpty(records)) {
            return;
        }
        Map<String, List<MediaVo>> mediaMap = resolveMediaByAssets(
                records.stream().map(PlayClerkUserInfoResultVo::getId).collect(Collectors.toList()), includePending);
        for (PlayClerkUserInfoResultVo record : records) {
            List<MediaVo> mediaList = new ArrayList<>(mediaMap.getOrDefault(record.getId(), Collections.emptyList()));
            record.setMediaList(mergeLegacyAlbum(record.getAlbum(), mediaList));
        }
    }

    private void attachMediaToAdminVos(List<PlayClerkUserReturnVo> records) {
        if (CollectionUtil.isEmpty(records)) {
            return;
        }
        Map<String, List<MediaVo>> mediaMap = resolveMediaByAssets(
                records.stream().map(PlayClerkUserReturnVo::getId).collect(Collectors.toList()), true);
        for (PlayClerkUserReturnVo record : records) {
            List<MediaVo> mediaList = new ArrayList<>(mediaMap.getOrDefault(record.getId(), Collections.emptyList()));
            record.setMediaList(mergeLegacyAlbum(record.getAlbum(), mediaList));
        }
    }

    private List<MediaVo> loadMediaForClerk(String clerkId, boolean includePending) {
        Map<String, List<MediaVo>> mediaMap = resolveMediaByAssets(Collections.singletonList(clerkId), includePending);
        return new ArrayList<>(mediaMap.getOrDefault(clerkId, Collections.emptyList()));
    }

    private Map<String, List<MediaVo>> resolveMediaByAssets(List<String> clerkIds, boolean includePending) {
        if (CollectionUtil.isEmpty(clerkIds)) {
            return Collections.emptyMap();
        }

        List<ClerkMediaReviewState> targetStates = includePending
                ? Arrays.asList(ClerkMediaReviewState.APPROVED, ClerkMediaReviewState.PENDING,
                        ClerkMediaReviewState.DRAFT, ClerkMediaReviewState.REJECTED)
                : Collections.singletonList(ClerkMediaReviewState.APPROVED);

        List<PlayClerkMediaAssetEntity> assets = clerkMediaAssetService.lambdaQuery()
                .in(PlayClerkMediaAssetEntity::getClerkId, clerkIds)
                .eq(PlayClerkMediaAssetEntity::getUsage, ClerkMediaUsage.PROFILE.getCode())
                .eq(PlayClerkMediaAssetEntity::getDeleted, false)
                .in(CollectionUtil.isNotEmpty(targetStates), PlayClerkMediaAssetEntity::getReviewState,
                        targetStates.stream().map(ClerkMediaReviewState::getCode).collect(Collectors.toList()))
                .orderByAsc(PlayClerkMediaAssetEntity::getOrderIndex)
                .orderByDesc(PlayClerkMediaAssetEntity::getCreatedTime)
                .list();
        if (CollectionUtil.isEmpty(assets)) {
            Map<String, List<MediaVo>> empty = new HashMap<>();
            clerkIds.forEach(id -> empty.put(id, Collections.emptyList()));
            return empty;
        }

        List<String> mediaIds = assets.stream().map(PlayClerkMediaAssetEntity::getMediaId).distinct()
                .collect(Collectors.toList());
        Map<String, PlayMediaEntity> mediaById = CollectionUtil.isEmpty(mediaIds)
                ? Collections.emptyMap()
                : mediaService.listByIds(mediaIds).stream()
                        .collect(Collectors.toMap(PlayMediaEntity::getId, item -> item, (left, right) -> left));

        Map<String, List<PlayClerkMediaAssetEntity>> groupedAssets = assets.stream()
                .collect(Collectors.groupingBy(PlayClerkMediaAssetEntity::getClerkId));

        Map<String, List<MediaVo>> result = new HashMap<>(groupedAssets.size());
        groupedAssets.forEach((clerkId, assetList) -> result.put(clerkId, ClerkMediaAssembler.toVoList(assetList, mediaById)));

        clerkIds.forEach(id -> result.computeIfAbsent(id, key -> Collections.emptyList()));
        return result;
    }

    static List<MediaVo> mergeLegacyAlbum(List<String> legacyAlbum, List<MediaVo> destination) {
        if (CollectionUtil.isEmpty(legacyAlbum)) {
            return destination;
        }
        Set<String> existingUrls = destination.stream()
                .map(MediaVo::getUrl)
                .filter(StrUtil::isNotBlank)
                .collect(Collectors.toSet());
        for (String url : legacyAlbum) {
            if (StrUtil.isBlank(url) || !existingUrls.add(url)) {
                continue;
            }
            MediaVo legacyVo = new MediaVo();
            legacyVo.setId(url);
            legacyVo.setUrl(url);
            legacyVo.setUsage(ClerkMediaUsage.PROFILE.getCode());
            legacyVo.setStatus(MediaStatus.READY.getCode());
            legacyVo.setReviewState(ClerkMediaReviewState.APPROVED.getCode());
            destination.add(legacyVo);
        }
        return destination;
    }
}
