package shop.alien.store.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
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.apache.commons.lang3.tuple.Triple;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import shop.alien.entity.result.R;
import shop.alien.entity.store.*;
import shop.alien.entity.store.excelVo.StoreUserExcelVo;
import shop.alien.entity.store.excelVo.util.ExcelGenerator;
import shop.alien.entity.store.vo.StoreSubExcelVo;
import shop.alien.entity.store.vo.StoreUserLogoutListVo;
import shop.alien.entity.store.vo.StoreUserVo;
import shop.alien.entity.store.vo.StoreUserWithStoreVo;
import shop.alien.entity.store.vo.WebSocketVo;
import shop.alien.mapper.*;
import shop.alien.store.config.BaseRedisService;
import shop.alien.store.config.WebSocketProcess;
import shop.alien.store.service.NearMeService;
import shop.alien.store.service.StoreLogoutSyncService;
import shop.alien.store.service.StoreUserService;
import shop.alien.store.util.FunctionMagic;
import shop.alien.util.ali.AliOSSUtil;
import shop.alien.util.common.DateUtils;
import shop.alien.util.common.JwtUtil;
import shop.alien.util.type.LifeNoticeUtil;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 二期-门店用户 服务实现类
 *
 * @author ssk
 * @since 2024-12-11
 */
@Slf4j
@Transactional
@Service
@RequiredArgsConstructor
public class StoreUserServiceImpl extends ServiceImpl<StoreUserMapper, StoreUser> implements StoreUserService {

    private final StoreUserMapper storeUserMapper;

    private final StoreInfoMapper storeInfoMapper;

    private final BaseRedisService baseRedisService;

    private final LifeUserDynamicsMapper lifeUserDynamicsMapper;

    private final LifeFansMapper lifeFansMapper;

    private final LifeNoticeMapper lifeNoticeMapper;

    private final LifeNoticeUtil lifeNoticeUtil;

    private final LifeMessageMapper lifeMessageMapper;

    private final StorePlatformUserRoleMapper storePlatformUserRoleMapper;

    private final NearMeService nearMeService;

    private final AliOSSUtil aliOSSUtil;

    private final WebSocketProcess webSocketProcess;

    private final StoreLogoutSyncService storeLogoutSyncService;

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

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

    @Value("${jwt.expiration-time}")
    private String effectiveTime;

    /** 点餐订单未完成：待支付、已支付未完结 */
    private static final List<Integer> PENDING_DINING_ORDER_STATUSES = Arrays.asList(0, 1);

    /** 预订订单未完成：待支付、待使用、退款中、商家预订 */
    private static final List<Integer> PENDING_RESERVATION_ORDER_STATUSES = Arrays.asList(0, 1, 6, 8);

    private final StoreOrderMapper storeOrderMapper;

    private final UserReservationOrderMapper userReservationOrderMapper;

    /**
     * 设定初始化默认密码
     */
    private static final String DEFAULT_PASSWORD = "123456";

    /**
     * 手机号获取
     *
     * @param phone 手机号
     * @return StoreUser
     */
    @Override
    public StoreUserVo getUserByPhone(String phone) {
        LambdaQueryWrapper<StoreUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StoreUser::getPhone, phone);
        StoreUser user = this.getOne(lambdaQueryWrapper);
        StoreUserVo storeUserVo = new StoreUserVo();
        if (user != null) {
            if (isStoreUserLogoutCooling(user) && user.getLogoutTime() != null) {
                LocalDateTime localDateTime = user.getLogoutTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                LocalDateTime future = localDateTime.plusDays(7);
                LocalDateTime now = LocalDateTime.now();
                Duration duration = Duration.between(now, future);
                long correct = duration.toMillis();
                storeUserVo.setCountdown(correct);
            }
        } else {
            return new StoreUserVo();
        }
        BeanUtils.copyProperties(user, storeUserVo);
        storeUserVo.setMoneyStr(new BigDecimal(storeUserVo.getMoney()).divide(new BigDecimal(100), 2, RoundingMode.DOWN).toString());
        return storeUserVo;
    }

    @Override
    public R<StoreUserWithStoreVo> getStoreUserWithStore(Integer type, Integer id) {
        if (type == null || id == null) {
            return R.fail("type和id不能为空");
        }
        StoreUser storeUser;
        Integer storeId;
        if (type == 1) {
            storeUser = storeUserMapper.selectById(id);
            if (storeUser == null || (storeUser.getDeleteFlag() != null && storeUser.getDeleteFlag() == 1)) {
                return R.fail("店铺用户不存在");
            }
            storeId = resolveStoreIdByUser(storeUser);
        } else if (type == 2) {
            StoreInfo storeInfo = storeInfoMapper.selectById(id);
            if (storeInfo == null || (storeInfo.getDeleteFlag() != null && storeInfo.getDeleteFlag() != 0)) {
                return R.fail("店铺不存在");
            }
            storeId = id;
            storeUser = findMainStoreUserByStoreId(storeId);
            if (storeUser == null) {
                return R.fail("未找到该店铺关联的店铺用户");
            }
        } else {
            return R.fail("type参数无效，1-店铺用户ID，2-店铺ID");
        }

        StoreUserWithStoreVo result = new StoreUserWithStoreVo();
        result.setStoreUser(storeUser);
        if (storeId != null && storeId > 0) {
            result.setStoreInfo(storeInfoMapper.selectById(storeId));
        }
        return R.data(result);
    }

    private Integer resolveStoreIdByUser(StoreUser storeUser) {
        if (storeUser.getStoreId() != null && storeUser.getStoreId() > 0) {
            return storeUser.getStoreId();
        }
        StorePlatformUserRole role = storePlatformUserRoleMapper.selectOne(new LambdaQueryWrapper<StorePlatformUserRole>()
                .eq(StorePlatformUserRole::getUserId, storeUser.getId())
                .eq(StorePlatformUserRole::getDeleteFlag, 0)
                .orderByDesc(StorePlatformUserRole::getCreatedTime)
                .last("LIMIT 1"));
        return role != null ? role.getStoreId() : null;
    }

    private StoreUser findMainStoreUserByStoreId(Integer storeId) {
        StoreUser mainUser = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>()
                .eq(StoreUser::getStoreId, storeId)
                .eq(StoreUser::getDeleteFlag, 0)
                .eq(StoreUser::getAccountType, 1)
                .orderByDesc(StoreUser::getCreatedTime)
                .last("LIMIT 1"));
        if (mainUser != null) {
            return mainUser;
        }
        return storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>()
                .eq(StoreUser::getStoreId, storeId)
                .eq(StoreUser::getDeleteFlag, 0)
                .orderByDesc(StoreUser::getCreatedTime)
                .last("LIMIT 1"));
    }

    /**
     * token
     *
     * @param storeUser
     * @return
     */
    @Override
    public R<StoreUserVo> createToKen(StoreUser storeUser) {
        int effectiveTimeInt = Integer.parseInt(effectiveTime.substring(0, effectiveTime.length() - 1));
        String effectiveTimeUnit = effectiveTime.substring(effectiveTime.length() - 1);
        long effectiveTimeIntLong = 0L;
        switch (effectiveTimeUnit) {
            case "s": {
                effectiveTimeIntLong = effectiveTimeInt * 1000L;
                break;
            }
            case "m": {
                effectiveTimeIntLong = effectiveTimeInt * 60L * 1000L;
                break;
            }
            case "h": {
                effectiveTimeIntLong = effectiveTimeInt * 60L * 60L * 1000L;
                break;
            }
            case "d": {
                effectiveTimeIntLong = effectiveTimeInt * 24L * 60L * 60L * 1000L;
                break;
            }
        }

        StoreUserVo storeUserVo = new StoreUserVo();
        BeanUtils.copyProperties(storeUser, storeUserVo);
        Map<String, String> tokenMap = new HashMap<>();
        tokenMap.put("phone", storeUser.getPhone());
        tokenMap.put("userName", storeUser.getName());
        tokenMap.put("userId", storeUser.getId().toString());
        tokenMap.put("userType", "store");
        storeUserVo.setToken(JwtUtil.createJWT("store_" + storeUser.getPhone(), storeUser.getName(), JSONObject.toJSONString(tokenMap), effectiveTimeIntLong));
        baseRedisService.setString("store_" + storeUser.getPhone(), storeUserVo.getToken());
        StoreInfo storeInfo = storeInfoMapper.selectById(storeUser.getStoreId());
        if (storeInfo != null) {
            storeUserVo.setBusinessSection(storeInfo.getBusinessSection());
            storeUserVo.setBusinessTypesName(storeInfo.getBusinessTypesName());
        }
        return R.data(storeUserVo);
    }

    /**
     * 修改用户状态
     *
     * @param phone 手机号
     * @param type  修改类型 (pass:密码状态改为1, face:人脸状态改为2)
     * @return StoreUser
     */
    @Override
    public boolean updateUserStatus(String phone, String type) {
        LambdaQueryWrapper<StoreUser> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(StoreUser::getPhone, phone);
        StoreUser one = this.getOne(lambdaQueryWrapper);
        if ("face".equals(type)) {
            one.setPassType(2);
        }
        if ("pass".equals(type)) {
            one.setPassType(2);
        }
        return this.updateById(one);
    }

    /**
     * 修改密码
     *
     * @param id       主键
     * @param password 密码
     * @return boolean
     */
    @Override
    public boolean updatePassword(Integer id, String password) {
        StoreUser storeUser = new StoreUser();
        storeUser.setId(id);
        storeUser.setPassword(password);
        return this.updateById(storeUser);
    }

    @Override
    public R<String> forgetOrModifyPassword(String phone, String newPhone, String oldPassword, String newPassword, String confirmNewPassword, String verificationCode, Integer type) {
        boolean flag = false;
        try {
            //类型为0 忘记密码
            if (type == 0) {
                return forgetPassword(phone, newPassword);
            }
            //修改密码
            else if (type == 1) {
                //效验新密码规则
                passwordVerification(phone, oldPassword, newPassword, confirmNewPassword);
                LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(StoreUser::getPhone, phone);
                updateWrapper.set(StoreUser::getPassword, newPassword);
                flag = this.update(updateWrapper);

                //修改成功后同步删除redis缓存token
                if (flag) {
                    String token = "store_" + phone;
                    String toKenStr = baseRedisService.getString(token);
                    if (toKenStr != null) {
                        baseRedisService.delete(token);
                    }
                    return R.success("密码修改成");
                } else {
                    log.error("密码修改失败");
                    return R.fail("密码修改失败");
                }
            }
            //更换绑定手机号
            else if (type == 2) {
                return ChangeBoundPhone(phone, newPhone);
            }
            return R.success("密码修改成功");
        } catch (Exception e) {
            return R.fail(e.getMessage());
        }
    }

    @Override
    public Map<String, String> changePhoneVerification(String phone, String oldPassword, String verificationCode) {
        Map<String, String> changePhoneMap = new HashMap<>();
        if (oldPassword != null && !oldPassword.equals("")) {
            LambdaUpdateWrapper<StoreUser> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            userLambdaUpdateWrapper.eq(StoreUser::getPhone, phone);
            StoreUser storeUser = this.getOne(userLambdaUpdateWrapper);
            if (storeUser.getPassword().equals(oldPassword)) {
                changePhoneMap.put("passwordStatus", "1");
                return changePhoneMap;
            } else {
                changePhoneMap.put("passwordStatus", "0");
                return changePhoneMap;
            }
        } else {
            changePhoneMap.put("verificationStatus", "0");
            return changePhoneMap;
        }
    }

    private void passwordVerification(String phone, String password, String newPassword, String confirmNewPassword) {
        LambdaQueryWrapper<StoreUser> wrapperFans = new LambdaQueryWrapper<>();
        wrapperFans.eq(StoreUser::getPhone, phone);
        StoreUser storeUser = this.getOne(wrapperFans);
        if (!newPassword.equals(confirmNewPassword)) {
            log.info("两次新密码输入不一致 请重新输入");
            throw new RuntimeException("两次新密码输入不一致 请重新输入");
        }
        if (storeUser == null || storeUser.equals("")) {
            log.info("该手机号没有注册过账户");
            throw new RuntimeException("该手机号没有注册过账户");
        } else {
            // 由于password字段使用了EncryptTypeHandler，查询时密码会被自动解密
            // 所以这里直接比较解密后的密码和用户输入的明文密码
            String dbPassword = storeUser.getPassword();
            if (dbPassword == null || dbPassword.isEmpty() || !dbPassword.equals(password)) {
                log.info("原密码错误");
                throw new RuntimeException("原密码错误");
            }
        }
    }

    private R<String> forgetPassword(String phone, String newPassword) {
        boolean flag = false;
        LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(StoreUser::getPhone, phone);
        updateWrapper.set(StoreUser::getPassword, newPassword);
        flag = this.update(updateWrapper);
        if (flag) {
            log.info("密码修改成功");
            String token = "store_" + phone;
            String tokenStr = baseRedisService.getString(token);
            if (tokenStr != null) {
                baseRedisService.delete(token);
            }
        }
        if (!flag) {
            log.error("密码修改失败");
            throw new RuntimeException("密码修改失败");
        }
        return R.success("密码修改成功");
    }

    private R<String> ChangeBoundPhone(String phone, String newPhone) {
        boolean flag = false;
        //获取新手机号验证码
        LambdaUpdateWrapper<StoreUser> newUpdateWrapper = new LambdaUpdateWrapper<>();
        newUpdateWrapper.eq(StoreUser::getPhone, newPhone);
        StoreUser newStoreUser = this.getOne(newUpdateWrapper);
        if (newStoreUser != null) {
            if (newStoreUser.getPhone().equals(newPhone)) {
                throw new RuntimeException("该手机号已注册过商户");
            }
        } else {
            LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(StoreUser::getPhone, phone);
            StoreUser storeUser = this.getOne(updateWrapper);
            storeUser.setPhone(newPhone);
            flag = this.updateById(storeUser);
            if (flag) {
                String token = "store_" + phone;
                String tokenStr = baseRedisService.getString(token);
                if (tokenStr != null) {
                    baseRedisService.delete(token);
                }
            }
        }
        return R.success("新手机号绑定成功");
    }

    /**
     * 设置用户信息
     *
     * @return boolean
     */
    @Override
    public boolean setUserInfo(StoreUser storeUserParam) {
        StoreUser storeUser = new StoreUser();
        storeUser.setId(storeUserParam.getId());
        //昵称
        if (StringUtils.isNotEmpty(storeUserParam.getNickName())) {
            storeUser.setNickName(storeUserParam.getNickName());
        }
        //身份证号
        if (StringUtils.isNotEmpty(storeUserParam.getIdCard())) {
            storeUser.setIdCard(storeUserParam.getIdCard());
        }
        //姓名
        if (StringUtils.isNotEmpty(storeUserParam.getName())) {
            storeUser.setName(storeUserParam.getName());
        }
        //账号简介
        if (StringUtils.isNotEmpty(storeUserParam.getAccountBlurb())) {
            storeUser.setAccountBlurb(storeUserParam.getAccountBlurb());
        }
        //头像
        if (StringUtils.isNotEmpty(storeUserParam.getHeadImg())) {
            storeUser.setHeadImg(storeUserParam.getHeadImg());
        }
        return this.updateById(storeUser);
    }

    /**
     * 修改支付密码
     *
     * @param id          主键
     * @param payPassword 支付密码
     * @return boolean
     */
    @Override
    public boolean setPayPassword(Integer id, String payPassword) {
        StoreUser storeUser = new StoreUser();
        storeUser.setId(id);
        storeUser.setPayPassword(payPassword);
        return this.updateById(storeUser);
    }

    @Override
    public R<StoreUserVo> addStoreUser(StoreUserVo storeUserVo) {
        //判断当前手机号是否存在
        StoreUser phoneHave = storeUserMapper.selectOne(new LambdaQueryWrapper<StoreUser>().eq(StoreUser::getPhone, storeUserVo.getPhone()));
        if (phoneHave != null) {
            throw new RuntimeException("手机号已存在！！");
        }
        StoreUserVo vo = new StoreUserVo();
        StoreUser storeUser = new StoreUser();
        BeanUtils.copyProperties(storeUserVo, storeUser);
        //存入密码类型为已修改  2025-4-22 业务修改
        storeUser.setPassType(2);
        int insert = storeUserMapper.insert(storeUser);
        BeanUtils.copyProperties(storeUser, vo);
        return R.data(vo);
    }

    @Override
    public R<IPage<StoreUserVo>> getStoreUserList(int pageNum, int pageSize, String id, String phone, Integer status, Integer accountType, String mainAccountId, String mainAccountPhone) {
        IPage<StoreUser> page = new Page<>(pageNum, pageSize);
        IPage<StoreUserVo> storeUserVoIPage = new Page<>();
        // 子账号分支：以 store_platform_user_role 每条记录为一行（不去重 userId），同一子账号在不同店铺展示多行，每行带主账号 id
        if (accountType == 2) {
            LambdaQueryWrapper<StorePlatformUserRole> roleWrapper = new LambdaQueryWrapper<>();
            roleWrapper.eq(StorePlatformUserRole::getDeleteFlag, 0);
            List<StorePlatformUserRole> userRoles = storePlatformUserRoleMapper.selectList(roleWrapper);
            if (CollectionUtils.isEmpty(userRoles)) {
                storeUserVoIPage.setRecords(new ArrayList<>());
                storeUserVoIPage.setTotal(0);
                storeUserVoIPage.setCurrent(pageNum);
                storeUserVoIPage.setSize(pageSize);
                return R.data(storeUserVoIPage);
            }

            // 主账号ID 模糊：只保留 platform 中 store_id 属于这些主账号店铺的 role 记录
            if (StringUtils.isNotEmpty(mainAccountId)) {
                LambdaQueryWrapper<StoreUser> mainById = new LambdaQueryWrapper<>();
                mainById.eq(StoreUser::getAccountType, 1).eq(StoreUser::getDeleteFlag, 0)
                        .apply("CAST(id AS CHAR) LIKE {0}", "%" + mainAccountId + "%");
                List<StoreUser> mains = storeUserMapper.selectList(mainById);
                List<Integer> storeIds = mains == null ? Collections.emptyList() : mains.stream().map(StoreUser::getStoreId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
                if (storeIds.isEmpty()) {
                    userRoles = Collections.emptyList();
                } else {
                    userRoles = userRoles.stream().filter(r -> storeIds.contains(r.getStoreId())).collect(Collectors.toList());
                }
            }
            // 主账号联系电话 模糊：只保留 platform 中 store_id 属于这些主账号店铺的 role 记录
            if (StringUtils.isNotEmpty(mainAccountPhone) && !userRoles.isEmpty()) {
                LambdaQueryWrapper<StoreUser> mainByPhone = new LambdaQueryWrapper<>();
                mainByPhone.eq(StoreUser::getAccountType, 1).eq(StoreUser::getDeleteFlag, 0).like(StoreUser::getPhone, mainAccountPhone);
                List<StoreUser> mains = storeUserMapper.selectList(mainByPhone);
                List<Integer> storeIds = mains == null ? Collections.emptyList() : mains.stream().map(StoreUser::getStoreId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
                if (storeIds.isEmpty()) {
                    userRoles = Collections.emptyList();
                } else {
                    userRoles = userRoles.stream().filter(r -> storeIds.contains(r.getStoreId())).collect(Collectors.toList());
                }
            }

            if (userRoles.isEmpty()) {
                storeUserVoIPage.setRecords(new ArrayList<>());
                storeUserVoIPage.setTotal(0);
                storeUserVoIPage.setCurrent(pageNum);
                storeUserVoIPage.setSize(pageSize);
                return R.data(storeUserVoIPage);
            }

            // 按 (userId, role_id) 去重，同一用户同一角色只保留一条（保留 id 最小的一条）
            userRoles = userRoles.stream()
                    .sorted(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())))
                    .collect(Collectors.toMap(
                            r -> (r.getUserId() != null ? r.getUserId() : 0) + "_" + (r.getRoleId() != null ? r.getRoleId() : ""),
                            r -> r,
                            (a, b) -> a
                    ))
                    .values().stream()
                    .sorted(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())))
                    .collect(Collectors.toList());

            // 按子账号 id/phone/status 过滤：批量查 store_user，只保留对应子账号满足条件的 role
            List<Integer> distinctUserIds = userRoles.stream().map(StorePlatformUserRole::getUserId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<StoreUser> subAccountList = distinctUserIds.isEmpty() ? Collections.emptyList() : storeUserMapper.selectBatchIds(distinctUserIds);
            // 根据 status 参数决定子账号池：选「注销中/已注销」时只保留对应状态；否则排除注销中、已注销
            Map<Integer, StoreUser> subAccountMap;
            if (status != null && (status == -1 || status == 2)) {
                final int filterStatus = status;
                subAccountMap = subAccountList == null ? new HashMap<>() : subAccountList.stream()
                        .filter(u -> u.getDeleteFlag() != null && u.getDeleteFlag() == 0)
                        .filter(u -> filterStatus == -1 ? isStoreUserLogoutCooling(u) : isStoreUserLoggedOut(u))
                        .collect(Collectors.toMap(StoreUser::getId, u -> u, (a, b) -> a));
            } else {
                subAccountMap = subAccountList == null ? new HashMap<>() : subAccountList.stream()
                        .filter(u -> u.getDeleteFlag() != null && u.getDeleteFlag() == 0
                                && !isStoreUserLogoutCooling(u) && !isStoreUserLoggedOut(u))
                        .collect(Collectors.toMap(StoreUser::getId, u -> u, (a, b) -> a));
            }
            List<StorePlatformUserRole> filteredRoles = new ArrayList<>();
            for (StorePlatformUserRole role : userRoles) {
                StoreUser subAccount = subAccountMap.get(role.getUserId());
                if (subAccount == null) continue;
                if (StringUtils.isNotEmpty(id) && (subAccount.getId() == null || !String.valueOf(subAccount.getId()).contains(id)))
                    continue;
                if (StringUtils.isNotEmpty(phone) && (subAccount.getPhone() == null || !subAccount.getPhone().contains(phone)))
                    continue;
                // 状态筛选：选「注销中/已注销」时以 store_user 为准（已由 subAccountMap 限定）；否则以 role.status 为准
                int rowStatus;
                if (status != null && (status == -1 || status == 2)) {
                    rowStatus = resolveLogoutRowStatus(subAccount);
                } else {
                    rowStatus = role.getStatus() != null ? role.getStatus() : (subAccount.getStatus() != null ? subAccount.getStatus() : 0);
                }
                if (status != null && !status.equals(rowStatus)) continue;
                filteredRoles.add(role);
            }
            filteredRoles.sort(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())));

            int total = filteredRoles.size();
            storeUserVoIPage.setTotal(total);
            storeUserVoIPage.setCurrent(pageNum);
            storeUserVoIPage.setSize(pageSize);
            int from = (pageNum - 1) * pageSize;
            if (from >= total) {
                storeUserVoIPage.setRecords(new ArrayList<>());
                return R.data(storeUserVoIPage);
            }
            int to = Math.min(from + pageSize, total);
            List<StorePlatformUserRole> pageRoles = filteredRoles.subList(from, to);

            // 批量查本页主账号，避免 N+1
            List<Integer> pageStoreIds = pageRoles.stream().map(StorePlatformUserRole::getStoreId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            Map<Integer, StoreUser> mainAccountMap = new HashMap<>();
            if (!pageStoreIds.isEmpty()) {
                LambdaQueryWrapper<StoreUser> mainW = new LambdaQueryWrapper<>();
                mainW.eq(StoreUser::getAccountType, 1).eq(StoreUser::getDeleteFlag, 0).in(StoreUser::getStoreId, pageStoreIds);
                List<StoreUser> mains = storeUserMapper.selectList(mainW);
                if (mains != null) mains.forEach(m -> mainAccountMap.put(m.getStoreId(), m));
            }


            List<StoreUserVo> resultRecords = new ArrayList<>();
            for (StorePlatformUserRole role : pageRoles) {
                StoreUser subAccount = subAccountMap.get(role.getUserId());
                if (subAccount == null) continue;
                StoreUser mainAccount = role.getStoreId() == null ? null : mainAccountMap.get(role.getStoreId());
                StoreUserVo storeUserVo = new StoreUserVo();
                BeanUtils.copyProperties(subAccount, storeUserVo);
                // 分页：返回主账号id(id/parentAccountId)及子账号id(subAccountId)，禁用/删除时用 subAccountId；状态以 store_platform_user_role.status 为准，启用/禁用后分页再查即展示最新状态
                Integer mainId = mainAccount != null ? mainAccount.getId() : subAccount.getSubAccountId();
                storeUserVo.setId(mainId != null ? mainId : subAccount.getId());
                storeUserVo.setSubAccountId(subAccount.getId());
                storeUserVo.setParentAccountId(mainId);
                int rowStatus;
                if (status != null && (status == -1 || status == 2)) {
                    rowStatus = resolveLogoutRowStatus(subAccount);
                } else {
                    rowStatus = role.getStatus() != null ? role.getStatus() : (subAccount.getStatus() != null ? subAccount.getStatus() : 0);
                }
                storeUserVo.setStatus(rowStatus);
                storeUserVo.setSwitchStatus(rowStatus == 0);
                storeUserVo.setStatusName(rowStatus == -1 ? "注销冷静期" : rowStatus == 2 ? "已注销" : (rowStatus == 1 ? "禁用" : "启用"));
                storeUserVo.setPhone(subAccount.getPhone());
                if (mainAccount != null) {
                    storeUserVo.setParentAccountPhone(mainAccount.getPhone());
                    storeUserVo.setParentAccountName(mainAccount.getName());
                }
                storeUserVo.setPassword(null);
                storeUserVo.setPayPassword(null);
                resultRecords.add(storeUserVo);
            }
            storeUserVoIPage.setRecords(resultRecords);
            return R.data(storeUserVoIPage);
        }

        // 主账号分支：直接查库返回最新 status，主账号页面展示子账号数量（按 store_platform_user_role 统计）；排除注销冷静期、已注销
        LambdaQueryWrapper<StoreUser> storeUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        storeUserLambdaQueryWrapper.eq(StoreUser::getDeleteFlag, 0)
                .like(StringUtils.isNotEmpty(id), StoreUser::getId, id)
                .like(StringUtils.isNotEmpty(phone), StoreUser::getPhone, phone)
                .eq(StoreUser::getAccountType, 1)
                .orderByDesc(StoreUser::getCreatedTime);
        if (status != null && status == -1) {
            storeUserLambdaQueryWrapper.and(w -> w.eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_COOLING)
                    .or(o -> o.eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_DONE).eq(StoreUser::getStatus, -1)));
        } else if (status != null && status == 2) {
            storeUserLambdaQueryWrapper.eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_DONE)
                    .and(w -> w.isNull(StoreUser::getStatus).or().ne(StoreUser::getStatus, -1));
        } else if (status != null) {
            storeUserLambdaQueryWrapper.eq(StoreUser::getStatus, status)
                    .and(w -> w.isNull(StoreUser::getLogoutFlag).or().eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_NORMAL));
        } else {
            storeUserLambdaQueryWrapper.and(w -> w.isNull(StoreUser::getLogoutFlag).or().eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_NORMAL));
        }

        IPage<StoreUser> storeUsers = storeUserMapper.selectPage(page, storeUserLambdaQueryWrapper);
        BeanUtils.copyProperties(storeUsers, storeUserVoIPage);

        List<StoreUserVo> resultRecords = new ArrayList<>();
        for (StoreUser storeUser : storeUsers.getRecords()) {
            StoreUserVo vo = new StoreUserVo();
            BeanUtils.copyProperties(storeUser, vo);
            vo.setPassword(null);
            vo.setPayPassword(null);
            // 主账号分页：返回最新 status；注销场景展示冷静期/已注销
            int rowStatus = resolveLogoutRowStatus(storeUser);
            if (rowStatus == 0 || rowStatus == 1) {
                rowStatus = storeUser.getStatus() != null ? storeUser.getStatus() : 0;
            }
            vo.setStatus(rowStatus);
            vo.setSwitchStatus(rowStatus == 0);
            vo.setStatusName(rowStatus == -1 ? "注销冷静期" : rowStatus == 2 ? "已注销" : (rowStatus == 1 ? "禁用" : "启用"));
            int childCount = countSubAccountUserIdsByStoreId(storeUser.getStoreId(), storeUser.getId());
            vo.setChildAccountCount(childCount);
            List<Integer> childUserIds = getSubAccountUserIdsByStoreId(storeUser.getStoreId(), storeUser.getId());
            if (!childUserIds.isEmpty()) {
                List<StoreUser> childUsers = storeUserMapper.selectBatchIds(childUserIds);
                vo.setChildPhoneNumbers(childUsers == null ? Collections.emptyList() : childUsers.stream().map(StoreUser::getPhone).collect(Collectors.toList()));
            }
            resultRecords.add(vo);
        }
        storeUserVoIPage.setRecords(resultRecords);
        return R.data(storeUserVoIPage);
    }

    /**
     * 通过主账号 id 用 MyBatis-Plus selectCount 查子账号数量（中间表 store_platform_user_role + store_user）。
     * 能查出数量大于 0 则代表有子账号，禁止删除或禁用主账号。
     *
     * @param mainAccountId 主账号 id（store_user.id）
     * @return true 表示有子账号，禁止删除/禁用；false 表示无子账号，可操作
     */
    private boolean hasSubAccountsByMainAccountId(Integer mainAccountId) {
        if (mainAccountId == null) {
            return false;
        }
        // 2. 在中间表 store_platform_user_role 中 selectCount：user_id in 子账号id 且 delete_flag=0
        LambdaQueryWrapper<StorePlatformUserRole> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(StorePlatformUserRole::getUserId,mainAccountId)
                .eq(StorePlatformUserRole::getDeleteFlag, 0);
        Long count = Long.valueOf(storePlatformUserRoleMapper.selectCount(roleWrapper));
        return count != null && count > 0;
    }

    /**
     * 按 store_platform_user_role 统计该店铺下子账号数量（排除主账号自身，按 distinct user_id 计）
     */
    private int countSubAccountUserIdsByStoreId(Integer storeId, Integer excludeUserId) {
        List<Integer> userIds = getSubAccountUserIdsByStoreId(storeId, excludeUserId);
        return userIds == null ? 0 : userIds.size();
    }

    /**
     * 统计某个子账号用户在中间表中的有效关联数量（跨店铺、未删除）。
     * 用于删除 / 启用禁用员工账号时判断：若同一 userId 关联多个店铺，则禁止直接删除 / 禁用全局账号。
     */
    private long countActiveSubAccountRelations(Integer userId) {
        if (userId == null) {
            return 0L;
        }
        LambdaQueryWrapper<StorePlatformUserRole> countWrapper = new LambdaQueryWrapper<>();
        countWrapper.eq(StorePlatformUserRole::getUserId, userId)
                .eq(StorePlatformUserRole::getDeleteFlag, 0);
        return storePlatformUserRoleMapper.selectCount(countWrapper);
    }

    /**
     * 按 store_platform_user_role 查询该店铺下子账号 userId 列表（排除主账号自身）
     */
    private List<Integer> getSubAccountUserIdsByStoreId(Integer storeId, Integer excludeUserId) {
        if (storeId == null) return Collections.emptyList();
        LambdaQueryWrapper<StorePlatformUserRole> w = new LambdaQueryWrapper<>();
        w.eq(StorePlatformUserRole::getStoreId, storeId).eq(StorePlatformUserRole::getDeleteFlag, 0);
        if (excludeUserId != null) w.ne(StorePlatformUserRole::getUserId, excludeUserId);
        List<StorePlatformUserRole> list = storePlatformUserRoleMapper.selectList(w);
        return list == null ? Collections.emptyList() : list.stream().map(StorePlatformUserRole::getUserId).distinct().collect(Collectors.toList());
    }


    /**
     * 主账号注销时：解除该店铺下所有子账号绑定；若子账号仅绑定此店铺且非主账号，则逻辑删除 store_user。
     * 逻辑参照 {@code StorePlatformUserRoleServiceImpl#batchDeleteSubAccounts}。
     */
    private void unbindSubAccountsOnMainAccountLogout(Integer storeId, Integer mainAccountUserId) {
        if (storeId == null) {
            return;
        }
        List<Integer> subAccountUserIds = getSubAccountUserIdsByStoreId(storeId, mainAccountUserId);
        if (CollectionUtils.isEmpty(subAccountUserIds)) {
            return;
        }
        log.info("主账号注销，解除店铺子账号绑定: storeId={}, mainAccountUserId={}, subAccountCount={}",
                storeId, mainAccountUserId, subAccountUserIds.size());
        for (Integer userId : subAccountUserIds) {
            unbindSubAccountFromStore(userId, storeId);
        }
    }

    /**
     * 注销时解除当前账号作为其他店铺子账号的绑定（仅清除 store_platform_user_role，不删除 store_user）。
     */
    private void unbindSelfAsSubAccountOnOtherStores(StoreUser storeUser) {
        if (storeUser == null || storeUser.getId() == null) {
            return;
        }
        LambdaQueryWrapper<StorePlatformUserRole> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StorePlatformUserRole::getUserId, storeUser.getId())
                .eq(StorePlatformUserRole::getDeleteFlag, 0);
        if (storeUser.getStoreId() != null) {
            queryWrapper.ne(StorePlatformUserRole::getStoreId, storeUser.getStoreId());
        }
        List<StorePlatformUserRole> roles = storePlatformUserRoleMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(roles)) {
            return;
        }
        Set<Integer> otherStoreIds = roles.stream()
                .map(StorePlatformUserRole::getStoreId)
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        log.info("注销账号，解除自身在其他店铺的子账号绑定: userId={}, storeIds={}", storeUser.getId(), otherStoreIds);
        for (Integer storeId : otherStoreIds) {
            LambdaUpdateWrapper<StorePlatformUserRole> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(StorePlatformUserRole::getUserId, storeUser.getId())
                    .eq(StorePlatformUserRole::getStoreId, storeId)
                    .eq(StorePlatformUserRole::getDeleteFlag, 0)
                    .set(StorePlatformUserRole::getDeleteFlag, 1);
            int updated = storePlatformUserRoleMapper.update(null, updateWrapper);
            if (updated > 0) {
                log.info("已解除自身子账号绑定: userId={}, storeId={}, count={}", storeUser.getId(), storeId, updated);
            }
        }
    }

    /**
     * 解除单个子账号与指定店铺的绑定；仅绑定一个店铺且非主账号时逻辑删除 store_user。
     */
    private void unbindSubAccountFromStore(Integer userId, Integer storeId) {
        if (userId == null || storeId == null) {
            return;
        }
        long subAccountCount = countActiveSubAccountRelations(userId);

        LambdaUpdateWrapper<StorePlatformUserRole> roleUpdateWrapper = new LambdaUpdateWrapper<>();
        roleUpdateWrapper.eq(StorePlatformUserRole::getUserId, userId)
                .eq(StorePlatformUserRole::getStoreId, storeId)
                .eq(StorePlatformUserRole::getDeleteFlag, 0)
                .set(StorePlatformUserRole::getDeleteFlag, 1);
        int roleUpdateResult = storePlatformUserRoleMapper.update(null, roleUpdateWrapper);
        if (roleUpdateResult <= 0) {
            log.warn("主账号注销解除子账号绑定失败: userId={}, storeId={}", userId, storeId);
            return;
        }

        StoreUser subUser = storeUserMapper.selectById(userId);
        clearStoreUserToken(subUser);

        if (subAccountCount == 1) {
            if (isStoreMainAccount(subUser)) {


                log.info("子账号同时是主账号，仅解除绑定不删除 store_user: userId={}, storeId={}", userId, storeId);
            } else {
                LambdaUpdateWrapper<StoreUser> userUpdateWrapper = new LambdaUpdateWrapper<>();
                userUpdateWrapper.eq(StoreUser::getId, userId)
                        .eq(StoreUser::getDeleteFlag, 0)
                        .set(StoreUser::getDeleteFlag, 1);
                int userUpdateResult = storeUserMapper.update(null, userUpdateWrapper);
                if (userUpdateResult > 0) {
                    log.info("子账号仅绑定一个店铺，已逻辑删除 store_user: userId={}, storeId={}", userId, storeId);
                } else {
                    log.warn("子账号逻辑删除 store_user 失败: userId={}", userId);
                }
            }
        } else {
            log.info("子账号绑定多个店铺，仅解除当前店铺绑定: userId={}, storeId={}, totalBindings={}",
                    userId, storeId, subAccountCount);
        }
    }

    private boolean isStoreMainAccount(StoreUser user) {
        if (user == null) {
            return false;
        }
        if (user.getStoreId() != null && user.getStoreId() > 0) {
            return true;
        }
        return user.getAccountType() != null && user.getAccountType() == 1;
    }

    private void clearStoreUserToken(StoreUser storeUser) {
        if (storeUser == null || storeUser.getPhone() == null) {
            return;
        }
        try {
            String tokenKey = "store_" + storeUser.getPhone();
            if (baseRedisService.getString(tokenKey) != null) {
                baseRedisService.delete(tokenKey);
                log.info("清除子账号 token: userId={}, phone={}", storeUser.getId(), storeUser.getPhone());
            }
        } catch (Exception e) {
            log.warn("清除子账号 token 异常: userId={}, msg={}", storeUser.getId(), e.getMessage());
        }
    }

    private List<Integer> getSubAccountUserIds(Integer excludeUserId) {
        if (excludeUserId == null) return Collections.emptyList();
        LambdaQueryWrapper<StorePlatformUserRole> w = new LambdaQueryWrapper<>();
        w.eq(StorePlatformUserRole::getDeleteFlag, 0);
        if (excludeUserId != null) w.ne(StorePlatformUserRole::getUserId, excludeUserId);
        List<StorePlatformUserRole> list = storePlatformUserRoleMapper.selectList(w);
        return list == null ? Collections.emptyList() : list.stream().map(StorePlatformUserRole::getUserId).distinct().collect(Collectors.toList());
    }

    @Override
    public R<StoreUserVo> editStoreUser(StoreUser storeUser) {
        storeUserMapper.updateById(storeUser);
        StoreUserVo storeUserVo = new StoreUserVo();
        BeanUtils.copyProperties(storeUser, storeUserVo);
        return R.data(storeUserVo);
    }

    @Override
    public void resetStoreUserPassword(StoreUser storeUser) {
        StoreUser storeUserById = storeUserMapper.selectById(storeUser.getId());
        //初始化密码赋值
        storeUserById.setPassword(DEFAULT_PASSWORD);
//        storeUserById.setPayPassword(DEFAULT_PASSWORD);
        storeUserMapper.updateById(storeUserById);
    }


    /**
     * 启用/禁用（入参必传 id）。默认状态 0=启用，1=禁用。
     * 禁用：主账号底下有关联子账号时需先删除子账号后才能禁用，否则用 UPDATE 把 status 从 0 改为 1，并删 token。
     * 启用：用 UPDATE 把 status 从 1 改为 0。
     * 若入参未传 status/accountType，则按 id 查库补全。
     */
    @Override
    public R<StoreUserVo> switchingStates(StoreUser storeUserParam) {
        if (storeUserParam == null) {
            throw new RuntimeException("参数不能为空");
        }
        if (storeUserParam.getId() == null) {
            throw new RuntimeException("请传入用户id");
        }
        // 入参未传 status / accountType / storeId 时，按 id 查库补全，避免缺字段导致子账号数量判断不准确
        if (storeUserParam.getStatus() == null
                || storeUserParam.getAccountType() == null
                || storeUserParam.getStoreId() == null) {
            StoreUser dbUser = storeUserMapper.selectById(storeUserParam.getId());
            if (dbUser == null) {
                throw new RuntimeException("用户不存在");
            }
            if (storeUserParam.getStatus() == null) {
                storeUserParam.setStatus(dbUser.getStatus());
            }
            if (storeUserParam.getAccountType() == null) {
                storeUserParam.setAccountType(dbUser.getAccountType());
            }
            if (storeUserParam.getStoreId() == null) {
                storeUserParam.setStoreId(dbUser.getStoreId());
            }
        }
        // 当前状态默认 0（启用）；点击禁用则 0->1，点击启用则 1->0
        int currentStatus = storeUserParam.getStatus() != null ? storeUserParam.getStatus() : 0;
        int newStatus = (currentStatus == 0) ? 1 : 0;
        boolean isMainAccount = storeUserParam.getAccountType() != null && storeUserParam.getAccountType() == 1;


        if (newStatus == 1) {
            StoreUser storeUser = storeUserMapper.selectById(storeUserParam.getId());

            // 2）子账号：只要在中间表存在关联记录（userId 对得上），就禁止禁用，需先在子账号管理中解除

            // UPDATE store_user SET status = 1 WHERE id = ?
            LambdaUpdateWrapper<StoreUser> userUpdateWrapper = new LambdaUpdateWrapper<>();
            userUpdateWrapper.eq(StoreUser::getId, storeUserParam.getId()).set(StoreUser::getStatus, 1);
            storeUserMapper.update(null, userUpdateWrapper);
            // 禁用时删除 token
            StoreUser u = storeUserMapper.selectById(storeUserParam.getId());
            if (u != null && u.getPhone() != null) {
                try {
                    baseRedisService.delete("store_" + u.getPhone());
                } catch (Exception e) {
                    log.warn("switchingStates 删除 token 异常: {}", e.getMessage());
                }
            }
        } else {
            // 启用：UPDATE store_user SET status = 0 WHERE id = ?
            LambdaUpdateWrapper<StoreUser> userUpdateWrapper = new LambdaUpdateWrapper<>();
            userUpdateWrapper.eq(StoreUser::getId, storeUserParam.getId()).set(StoreUser::getStatus, 0);
            storeUserMapper.update(null, userUpdateWrapper);
        }

        StoreUserVo vo = new StoreUserVo();
        vo.setId(storeUserParam.getId());
        vo.setStatus(newStatus);
        vo.setSwitchStatus(newStatus == 0);
        return R.data(vo);
    }

    /**
     * 分页查询
     *
     * @param
     * @param
     * @param id
     * @param phone
     * @param status
     * @param accountType
     * @return
     */
    @Override
    public String exportExcel(String id, String phone, String status, Integer accountType) throws IOException {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 主账号导出：与 getStoreUserList 主账号分支一致
        if (accountType == 1) {
            LambdaQueryWrapper<StoreUser> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(StoreUser::getDeleteFlag, 0)
                    .like(StringUtils.isNotEmpty(id), StoreUser::getId, id)
                    .like(StringUtils.isNotEmpty(phone), StoreUser::getPhone, phone)
                    .eq(StoreUser::getAccountType, 1)
                    .orderByDesc(StoreUser::getCreatedTime);
            Integer statusInt = null;
            if (StringUtils.isNotEmpty(status)) {
                try {
                    statusInt = Integer.parseInt(status.trim());
                } catch (NumberFormatException ignored) {
                }
            }
            if (statusInt != null && statusInt == -1) {
                wrapper.and(w -> w.eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_COOLING)
                        .or(o -> o.eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_DONE).eq(StoreUser::getStatus, -1)));
            } else if (statusInt != null && statusInt == 2) {
                wrapper.eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_DONE)
                        .and(w -> w.isNull(StoreUser::getStatus).or().ne(StoreUser::getStatus, -1));
            } else if (statusInt != null) {
                wrapper.eq(StoreUser::getStatus, statusInt)
                        .and(w -> w.isNull(StoreUser::getLogoutFlag).or().eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_NORMAL));
            } else {
                wrapper.and(w -> w.isNull(StoreUser::getLogoutFlag).or().eq(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_NORMAL));
            }
            List<StoreUser> storeUsers = storeUserMapper.selectList(wrapper);
            List<StoreUserExcelVo> storeUserExcelVoList = new ArrayList<>();
            int serialNumber = 0;
            for (StoreUser storeUser : storeUsers) {
                StoreUserExcelVo vo = new StoreUserExcelVo();
                vo.setSerialNumber(++serialNumber);
                BeanUtils.copyProperties(storeUser, vo);
                vo.setCreatedTime(storeUser.getCreatedTime() != null ? storeUser.getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().format(formatter) : null);
                vo.setStatus(storeUser.getStatus() == null ? "" : (storeUser.getStatus() == 0 ? "启用" : "禁用"));
                vo.setChildAccountCount(countSubAccountUserIdsByStoreId(storeUser.getStoreId(), storeUser.getId()));
                storeUserExcelVoList.add(vo);
            }
            String fileName = UUID.randomUUID().toString().replace("-", "");
            String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeUserExcelVoList, StoreUserExcelVo.class);
            return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
        }
        // 子账号导出：与 getStoreUserList 子账号分页一致，每条 store_platform_user_role 为一行（不去重），带主账号 id
        LambdaQueryWrapper<StorePlatformUserRole> roleWrapper = new LambdaQueryWrapper<>();
        roleWrapper.eq(StorePlatformUserRole::getDeleteFlag, 0);
        List<StorePlatformUserRole> userRoles = storePlatformUserRoleMapper.selectList(roleWrapper);
        if (CollectionUtils.isEmpty(userRoles)) {
            String fileName = UUID.randomUUID().toString().replace("-", "");
            String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", new ArrayList<StoreSubExcelVo>(), StoreSubExcelVo.class);
            return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");
        }
        // 按 (userId, role_id) 去重，与 getStoreUserList 子账号分页一致
        userRoles = userRoles.stream()
                .sorted(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())))
                .collect(Collectors.toMap(
                        r -> (r.getUserId() != null ? r.getUserId() : 0) + "_" + (r.getRoleId() != null ? r.getRoleId() : ""),
                        r -> r,
                        (a, b) -> a
                ))
                .values().stream()
                .sorted(Comparator.comparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.naturalOrder())))
                .collect(Collectors.toList());
        List<Integer> distinctUserIds = userRoles.stream().map(StorePlatformUserRole::getUserId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        List<StoreUser> subAccountList = distinctUserIds.isEmpty() ? Collections.emptyList() : storeUserMapper.selectBatchIds(distinctUserIds);
        Integer statusInt = null;
        if (StringUtils.isNotEmpty(status)) {
            try {
                statusInt = Integer.parseInt(status.trim());
            } catch (NumberFormatException ignored) {
            }
        }
        // 与 getStoreUserList 一致：选「注销中/已注销」时只保留对应状态；否则排除注销中、已注销
        Map<Integer, StoreUser> subAccountMap;
        if (statusInt != null && (statusInt == -1 || statusInt == 2)) {
            final int filterStatus = statusInt;
            subAccountMap = subAccountList == null ? new HashMap<>() : subAccountList.stream()
                    .filter(u -> u.getDeleteFlag() != null && u.getDeleteFlag() == 0)
                    .filter(u -> filterStatus == -1 ? isStoreUserLogoutCooling(u) : isStoreUserLoggedOut(u))
                    .collect(Collectors.toMap(StoreUser::getId, u -> u, (a, b) -> a));
        } else {
            subAccountMap = subAccountList == null ? new HashMap<>() : subAccountList.stream()
                    .filter(u -> u.getDeleteFlag() != null && u.getDeleteFlag() == 0
                            && !isStoreUserLogoutCooling(u) && !isStoreUserLoggedOut(u))
                    .collect(Collectors.toMap(StoreUser::getId, u -> u, (a, b) -> a));
        }
        List<StorePlatformUserRole> filteredRoles = new ArrayList<>();
        for (StorePlatformUserRole role : userRoles) {
            StoreUser subAccount = subAccountMap.get(role.getUserId());
            if (subAccount == null) continue;
            if (StringUtils.isNotEmpty(id) && (subAccount.getId() == null || !String.valueOf(subAccount.getId()).contains(id)))
                continue;
            if (StringUtils.isNotEmpty(phone) && (subAccount.getPhone() == null || !subAccount.getPhone().contains(phone)))
                continue;
            int rowStatus;
            if (statusInt != null && (statusInt == -1 || statusInt == 2)) {
                rowStatus = resolveLogoutRowStatus(subAccount);
            } else {
                rowStatus = role.getStatus() != null ? role.getStatus() : (subAccount.getStatus() != null ? subAccount.getStatus() : 0);
            }
            if (statusInt != null && !statusInt.equals(rowStatus)) continue;
            filteredRoles.add(role);
        }
        // 子账号导出与列表一致：按创建时间从近到远（降序）
        filteredRoles.sort(Comparator.comparing(
                (StorePlatformUserRole r) -> {
                    StoreUser sub = subAccountMap.get(r.getUserId());
                    return sub != null && sub.getCreatedTime() != null ? sub.getCreatedTime() : new Date(0L);
                },
                Comparator.nullsLast(Comparator.reverseOrder())
        ).thenComparing(StorePlatformUserRole::getId, Comparator.nullsLast(Comparator.reverseOrder())));
        List<Integer> storeIds = filteredRoles.stream().map(StorePlatformUserRole::getStoreId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
        Map<Integer, StoreUser> mainAccountMap = new HashMap<>();
        if (!storeIds.isEmpty()) {
            LambdaQueryWrapper<StoreUser> mainW = new LambdaQueryWrapper<>();
            mainW.eq(StoreUser::getAccountType, 1).eq(StoreUser::getDeleteFlag, 0).in(StoreUser::getStoreId, storeIds);
            List<StoreUser> mains = storeUserMapper.selectList(mainW);
            if (mains != null) mains.forEach(m -> mainAccountMap.put(m.getStoreId(), m));
        }
        List<StoreSubExcelVo> storeSubExcelVoList = new ArrayList<>();
        int serialNumber = 0;
        for (StorePlatformUserRole role : filteredRoles) {
            StoreUser subAccount = subAccountMap.get(role.getUserId());
            if (subAccount == null) continue;
            StoreUser mainAccount = role.getStoreId() == null ? null : mainAccountMap.get(role.getStoreId());
            StoreSubExcelVo vo = new StoreSubExcelVo();
            vo.setSerialNumber(++serialNumber);
            vo.setParentAccountId(mainAccount != null ? mainAccount.getId() : null);
            vo.setParentAccountPhone(mainAccount != null ? mainAccount.getPhone() : null);
            vo.setPhone(subAccount.getPhone());
            vo.setCreatedTime(subAccount.getCreatedTime() != null ? subAccount.getCreatedTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime().format(formatter) : null);
            int rowStatus = resolveLogoutRowStatus(subAccount);
            if (statusInt == null || (statusInt != -1 && statusInt != 2)) {
                rowStatus = role.getStatus() != null ? role.getStatus() : (subAccount.getStatus() != null ? subAccount.getStatus() : 0);
            }
            vo.setStatus(rowStatus == -1 ? "注销冷静期" : rowStatus == 2 ? "已注销" : (rowStatus == 0 ? "启用" : "禁用"));
            storeSubExcelVoList.add(vo);
        }
        String fileName = UUID.randomUUID().toString().replace("-", "");
        String filePath = ExcelGenerator.generateExcel(excelPath + excelGeneratePath + fileName + ".xlsx", storeSubExcelVoList, StoreSubExcelVo.class);
        return aliOSSUtil.uploadFile(new File(filePath), "excel/" + fileName + ".xlsx");

    }


    /**
     * 注册校验
     *
     * @param phone
     * @return
     */
    public boolean checkRegister(String phone) {
        LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StoreUser::getPhone, phone);
        queryWrapper.in(StoreUser::getStatus, 0, 1);
        List<StoreUser> storeUsers = storeUserMapper.selectList(queryWrapper);
        return CollectionUtils.isEmpty(storeUsers) ? Boolean.TRUE : Boolean.FALSE;
    }

    /**
     * 注册
     *
     * @param phone
     * @param password
     * @return
     */
    @Override
    public R<Boolean> register(String phone, String password) {

        LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StoreUser::getPhone, phone)
                .orderByDesc(StoreUser::getCreatedTime).last("LIMIT 1");
        StoreUser storeUser = storeUserMapper.selectOne(queryWrapper);

        List<Integer> noRegister = Arrays.asList(0, 1);

        if (Objects.isNull((storeUser))) {
            // 没有数据
            saveNewUser(phone, password);
            return R.success("操作成功");

        } else if (noRegister.contains(storeUser.getStatus())) {
            return R.fail("手机号已经注册过");
        }

        int daysSinceDeletion = DateUtils.subtraction(storeUser.getCreatedTime(), new Date());
        if (daysSinceDeletion < 30) return R.fail(String.format("请于%d天后重新申请注册", 30 - daysSinceDeletion));
        saveNewUser(phone, password);
        return R.success("操作成功");

    }

    @Override
    public Map<String, String> storeCancelAccountVerification(StoreUserVo storeUserVo) {
        // 通过id获取当前商家账号信息
        LambdaQueryWrapper<StoreUser> storeUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        storeUserLambdaQueryWrapper.eq(StoreUser::getId, storeUserVo.getId());
        StoreUser storeUser = storeUserMapper.selectOne(storeUserLambdaQueryWrapper);
        Map<String, String> storeMap = new HashMap<>();
        if (storeUser != null) {
            storeMap.put("status", storeUser.getStatus().toString());
            if (null != storeUser.getStoreId()) {
                // value为0代表有商铺未注销
                storeMap.put("accountStore", "0");
                fillPendingOrderVerification(storeMap, storeUser.getStoreId());
            } else {
                // value为1代表绑定店铺已注销
                storeMap.put("accountStore", "1");
                storeMap.put("accountDiningOrder", "1");
                storeMap.put("accountReservationOrder", "1");
            }
            //钱包功能暂未完成此效验默认状态都是1通过
            if (storeUser.getMoney() != null && storeUser.getMoney() > 0) {
                // value为0代表有未体现的现金
                storeMap.put("accountMoney", "0");
            } else {
                // value为1代表没有未体现的现金
                storeMap.put("accountMoney", "1");
            }
        }
        return storeMap;
    }

    /**
     * 注销校验：店铺是否存在未结束的点餐/预订订单。
     * value 为 0 表示存在未完成订单，1 表示通过。
     */
    private void fillPendingOrderVerification(Map<String, String> storeMap, Integer storeId) {
        long pendingDiningCount = storeOrderMapper.selectCount(new LambdaQueryWrapper<StoreOrder>()
                .eq(StoreOrder::getStoreId, storeId)
                .in(StoreOrder::getOrderStatus, PENDING_DINING_ORDER_STATUSES)
                .eq(StoreOrder::getDeleteFlag, 0));
        storeMap.put("accountDiningOrder", pendingDiningCount > 0 ? "0" : "1");
        storeMap.put("accountDiningOrderCount", String.valueOf(pendingDiningCount));

        long pendingReservationCount = userReservationOrderMapper.selectCount(new LambdaQueryWrapper<UserReservationOrder>()
                .eq(UserReservationOrder::getStoreId, storeId)
                .in(UserReservationOrder::getOrderStatus, PENDING_RESERVATION_ORDER_STATUSES)
                .eq(UserReservationOrder::getDeleteFlag, 0));
        storeMap.put("accountReservationOrder", pendingReservationCount > 0 ? "0" : "1");
        storeMap.put("accountReservationOrderCount", String.valueOf(pendingReservationCount));
    }


    /**
     * @param phone
     * @return
     */
    @Override
    public R<StoreUser> checkLogin(String phone) {
        LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StoreUser::getPhone, phone)
                .orderByDesc(StoreUser::getCreatedTime).last("LIMIT 1");
        StoreUser storeUser = storeUserMapper.selectOne(queryWrapper);
        // 用户状态 0：启用，1：禁用；logout_flag 1：已注销，2：注销冷静期
        if (Objects.isNull(storeUser)) {
            return R.success("用户不存在，快去注册吧！");
        } else if (storeUser.getStatus() != null && storeUser.getStatus() == 1) {
            return R.success("账号已被禁用");
        } else if (isStoreUserLoggedOut(storeUser)) {
            return R.data(storeUser,"账号已注销");
        } else if (isStoreUserLogoutCooling(storeUser)) {
            return R.data(storeUser,"账号注销冷静期中");
        }
        return R.data(storeUser,"success");
    }


    /**
     * save User
     *
     * @param phone
     * @param password
     */
    private void saveNewUser(String phone, String password) {
        StoreUser registerStoreUser = new StoreUser();
        registerStoreUser.setPhone(phone);
        registerStoreUser.setPassword(password);
        registerStoreUser.setPassType(2);
        registerStoreUser.setMoney(0);
        registerStoreUser.setDeleteFlag(0);
        registerStoreUser.setStatus(0);
        registerStoreUser.setIdCard("");
        registerStoreUser.setPassType(2);
        registerStoreUser.setCreatedTime(new Date());
        registerStoreUser.setLogoutFlag(0);
        registerStoreUser.setNickName(phone);
        storeUserMapper.insert(registerStoreUser);
    }

    @Override
    public void storeCancelAccount(StoreUserVo storeUserVo) {
        // 通过id获取当前商家账号信息
        LambdaQueryWrapper<StoreUser> storeUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        storeUserLambdaQueryWrapper.eq(StoreUser::getId, storeUserVo.getId());
        StoreUser storeUser = storeUserMapper.selectOne(storeUserLambdaQueryWrapper);
        if (storeUser != null) {
            if (isStoreUserLogoutCooling(storeUser) || isStoreUserLoggedOut(storeUser)) {
                throw new IllegalArgumentException("账号已在注销流程中");
            }
            storeUser.setLogoutReason(storeUserVo.getLogoutReason());
            storeUser.setLogoutCode(storeUserVo.getLogoutCode());
            storeUser.setLogoutFlag(StoreUser.LOGOUT_FLAG_COOLING);
            storeUser.setLogoutTime(new Date());
            int num = storeUserMapper.updateById(storeUser);
            if (num > 0) {
                storeLogoutSyncService.applyCoolingForStoreUser(
                        storeUser, storeUserVo.getLogoutReason(), storeUserVo.getLogoutCode());
                if (storeUser.getStoreId() != null) {
                    unbindSubAccountsOnMainAccountLogout(storeUser.getStoreId(), storeUser.getId());
                }
                unbindSelfAsSubAccountOnOtherStores(storeUser);
                // 发送通知
                LifeNotice lifeMessage = new LifeNotice();
                lifeMessage.setReceiverId("store_" + storeUser.getPhone());
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String storeDate = simpleDateFormat.format(new Date());
                String text = "您在" + storeDate + "注销了账号，平台将为您保留7天，在此期间您可撤销注销账号，7天后账号将变为已注销状态。";
                com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject();
                jsonObject.put("message", text);
                lifeMessage.setContext(jsonObject.toJSONString());
                lifeMessage.setTitle("注销商家账号通知");
                lifeMessage.setSenderId("system");
                lifeMessage.setIsRead(0);
                lifeMessage.setNoticeType(1);

                lifeNoticeUtil.fillUserTypeAndRefId(lifeMessage);
                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(com.alibaba.fastjson2.JSONObject.from(lifeMessage).toJSONString());
                try {
                    webSocketProcess.sendMessage("store_" + storeUser.getPhone(), com.alibaba.fastjson2.JSONObject.from(websocketVo).toJSONString());
                } catch (Exception e) {
                    log.error("LifeUserViolationServiceImpl_approve Error Stack={}", e.getMessage());
                }
            }
        }
    }

    @Override
    public void storeCancelAccountUn(StoreUserVo storeUserVo) {
        // 通过id获取当前商家账号信息
        LambdaQueryWrapper<StoreUser> storeUserLambdaQueryWrapper = new LambdaQueryWrapper<>();
        storeUserLambdaQueryWrapper.eq(StoreUser::getId, storeUserVo.getId());
        StoreUser storeUser = storeUserMapper.selectOne(storeUserLambdaQueryWrapper);
        if (storeUser == null) {
            throw new IllegalArgumentException("账号不存在");
        }
        if (!isStoreUserLogoutCooling(storeUser)) {
            throw new IllegalArgumentException("当前账号不在注销冷静期内，无法撤销");
        }
        storeUser.setLogoutFlag(StoreUser.LOGOUT_FLAG_NORMAL);
        storeUser.setLogoutTime(null);
        int num = storeUserMapper.updateById(storeUser);
        if (num > 0) {
            storeLogoutSyncService.revokeCoolingForStoreUser(storeUser);
            // 发送通知
            LifeNotice lifeMessage = new LifeNotice();
            lifeMessage.setReceiverId("store_" + storeUser.getPhone());

            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String storeDate = simpleDateFormat.format(storeUser.getCreatedTime());
            String text = "您在" + storeDate + "撤销了注销账号，所有数据均已保留，您可继续在平台使用。";
            com.alibaba.fastjson2.JSONObject jsonObject = new com.alibaba.fastjson2.JSONObject();
            jsonObject.put("message", text);
            lifeMessage.setContext(jsonObject.toJSONString());
            lifeMessage.setTitle("撤销商家账号注销通知");
            lifeMessage.setSenderId("system");
            lifeMessage.setIsRead(0);
            lifeMessage.setNoticeType(1);
            lifeNoticeUtil.fillUserTypeAndRefId(lifeMessage);
            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(com.alibaba.fastjson2.JSONObject.from(lifeMessage).toJSONString());
            try {
                webSocketProcess.sendMessage("store_" + storeUser.getPhone(), com.alibaba.fastjson2.JSONObject.from(websocketVo).toJSONString());
            } catch (Exception e) {
                log.error("StoreUserServiceImpl webSocketProcess Stack={}", e.getMessage());
            }
        }
    }

    /**
     * 删除商家账号。
     * 主账号：有关联店铺禁止删除，有关联子账号禁止删除。
     * 子账号：参照 removeRole 逻辑，按 userId/storeId 逻辑删除 store_platform_user_role；若该主账号下仅 1 个子账号且非主账号则同时逻辑删除 store_user 并清 token。
     */
    @Override
    public String deleteStoreAccountInfo(StoreUser storeUser) {
        if (storeUser == null) {
            log.warn("deleteStoreAccountInfo 参数不能为空");
            return "删除失败";
        }
       StoreUser user = storeUserMapper.selectById(storeUser.getId());
        // 2. 主账号删除校验：有关联店铺禁止删除，有关联子账号禁止删除
        if (storeUser.getAccountType() != null && storeUser.getAccountType() == 1) {
            if (user == null) {
                log.warn("deleteStoreAccountInfo 删除主账号时 id 不能为空");
                return "删除失败";
            }

            if (user != null && user.getStoreId() != null && user.getStoreId() > 0) {
                log.error("该主账号下存在关联店铺，禁止删除");
                return "当前账号下存在店铺 禁止删除";
            }

            // 主账号：存在子账号则禁止删除（按主账号id + 中间表统计）

            if (hasSubAccountsByMainAccountId(user.getId())) {
                log.error("该主账号下存在关联子账号，不能删除");
                return "请先删除主账号下的子账号后再删除";
            }

        }

        // 子账号删除：只要该 userId 在中间表存在关联记录（userId 对得上），就禁止直接删除全局账号
        if (storeUser != null && storeUser.getAccountType() != null && storeUser.getAccountType() == 2) {
            long relationCount = countActiveSubAccountRelations(storeUser.getId());
            if (relationCount > 0) {
                log.error("该子账号在子账号列表中仍有关联记录，禁止直接删除全局账号 userId={}", storeUser.getId());
                return "当前子账号在子账号管理中仍有关联记录，请先解除子账号后再删除";
            }
        }

        LambdaUpdateWrapper<StoreUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(StoreUser::getId, storeUser.getId());
        updateWrapper.set(StoreUser::getDeleteFlag, 1);
        int update = storeUserMapper.update(null, updateWrapper);
        if (update > 0) {
            return "删除成功";
        }
        return "删除失败";
    }

    @Override
    public List<String> getIds(String name, String phone) {
        if (Objects.isNull(name) && Objects.isNull(phone)) return Collections.singletonList("");
        LambdaQueryWrapper<StoreUser> wrapper = new LambdaQueryWrapper<>();
        List<Triple<Boolean, SFunction<StoreUser, ?>, Object>> conditions = new ArrayList<>();
        conditions.add(Triple.of(StringUtils.isNotEmpty(name), StoreUser::getName, name));
        conditions.add(Triple.of(StringUtils.isNotEmpty(phone), StoreUser::getPhone, phone));
        FunctionMagic.buildLikeConditions(wrapper, conditions);
        List<String> res = FunctionMagic.convertToIds(storeUserMapper.selectList(wrapper), StoreUser::getId);
        return CollectionUtils.isEmpty(res) ? Collections.singletonList("") : res;
    }

    @Override
    public R havePayPassword(String storeUserId, String password) {
        StoreUser storeUser = storeUserMapper.selectById(storeUserId);
        HashMap<Object, Object> returnMap = new HashMap<>();
        returnMap.put("code", 200);
        if (null == storeUser) {
            returnMap.put("message", "未查询到用户");
            returnMap.put("data", "false");
            return R.data(returnMap);
        }
        if (null == storeUser.getPayPassword()) {
            returnMap.put("message", "用户未设置支付密码");
            returnMap.put("data", "false");
            return R.data(returnMap);
        } else if (null != password) {
            if (!password.equals(storeUser.getPayPassword())) {
                returnMap.put("message", "密码错误");
                returnMap.put("data", "false");
                return R.data(returnMap);
            }
        }
        returnMap.put("data", "true");
        returnMap.put("message", "用户已设置支付密码");
        return R.data(returnMap);
    }

    @Override
    public List<StoreUser> getSubAccountsByMainAccountId(Integer mainAccountId) {
        LambdaQueryWrapper<StoreUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(StoreUser::getAccountType, 2)  // 子账号类型
                .eq(StoreUser::getSubAccountId, mainAccountId)  // 关联主账号ID
                .eq(StoreUser::getDeleteFlag, 0)  // 未删除的账号
                .orderByDesc(StoreUser::getCreatedTime);  // 按创建时间倒序

        return storeUserMapper.selectList(queryWrapper);
    }


    @Override
    public List<StoreUser> getChildAccountsByParentId(String Id) {
        Integer parentId = safeParseInt(Id);
        if (parentId == null) {
            return Collections.emptyList();
        }

        LambdaQueryWrapper<StoreUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreUser::getSubAccountId, Id)
                .eq(StoreUser::getAccountType, 2)  // 子账号
                .eq(StoreUser::getDeleteFlag, 0)
                .orderByAsc(StoreUser::getCreatedTime);

        List<StoreUser> result = this.list(wrapper);

        // 确保返回非空集合
        return result != null ? result : Collections.emptyList();

    }

    /** 是否处于注销冷静期（含旧数据：status=-1 且 logout_flag=1） */
    private static boolean isStoreUserLogoutCooling(StoreUser user) {
        if (user == null || user.getLogoutFlag() == null) {
            return Integer.valueOf(-1).equals(user != null ? user.getStatus() : null);
        }
        if (StoreUser.LOGOUT_FLAG_COOLING == user.getLogoutFlag()) {
            return true;
        }
        return StoreUser.LOGOUT_FLAG_DONE == user.getLogoutFlag()
                && Integer.valueOf(-1).equals(user.getStatus());
    }

    /** 是否已注销（logout_flag=1 且非旧冷静期数据） */
    private static boolean isStoreUserLoggedOut(StoreUser user) {
        if (user == null) {
            return false;
        }
        if (StoreUser.LOGOUT_FLAG_DONE == user.getLogoutFlag()
                && !Integer.valueOf(-1).equals(user.getStatus())) {
            return true;
        }
        return Integer.valueOf(2).equals(user.getStatus());
    }

    /** 管理端展示：-1 冷静期，2 已注销 */
    private static int resolveLogoutRowStatus(StoreUser user) {
        if (isStoreUserLogoutCooling(user)) {
            return -1;
        }
        if (isStoreUserLoggedOut(user)) {
            return 2;
        }
        return user.getStatus() != null ? user.getStatus() : 0;
    }

    /**
     * 安全解析字符串为整数
     */
    private Integer safeParseInt(String str) {
        if (str == null || str.trim().isEmpty()) {
            return null;
        }
        try {
            return Integer.valueOf(str.trim());
        } catch (NumberFormatException e) {
            log.warn("无法解析字符串为整数: {}", str);
            return null;
        }
    }

    @Override
    public IPage<StoreUserLogoutListVo> getStoreUserLogoutPage(int pageNum, int pageSize, String userName, String phone, Integer logoutFlag) {
        Page<StoreUser> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<StoreUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreUser::getDeleteFlag, 0)
                .in(StoreUser::getLogoutFlag, StoreUser.LOGOUT_FLAG_DONE, StoreUser.LOGOUT_FLAG_COOLING);
        if (logoutFlag != null) {
            wrapper.eq(StoreUser::getLogoutFlag, logoutFlag);
        }
        if (StringUtils.isNotEmpty(userName)) {
            wrapper.like(StoreUser::getName, userName);
        }
        wrapper.like(StringUtils.isNotEmpty(phone), StoreUser::getPhone, phone)
                .orderByDesc(StoreUser::getLogoutTime)
                .orderByDesc(StoreUser::getCreatedTime);

        IPage<StoreUser> userPage = storeUserMapper.selectPage(page, wrapper);
        Page<StoreUserLogoutListVo> result = new Page<>(userPage.getCurrent(), userPage.getSize(), userPage.getTotal());
        result.setRecords(userPage.getRecords().stream().map(this::toStoreUserLogoutListVo).collect(Collectors.toList()));
        return result;
    }

    private StoreUserLogoutListVo toStoreUserLogoutListVo(StoreUser user) {
        StoreUserLogoutListVo vo = new StoreUserLogoutListVo();
        vo.setId(user.getId());
        vo.setName(user.getName());
        vo.setRealName(user.getName());
        vo.setPhone(user.getPhone());
        vo.setCreatedTime(user.getCreatedTime());
        vo.setApplyLogoutTime(user.getLogoutTime());
        vo.setLogoutReason(user.getLogoutReason());

        Integer flag = user.getLogoutFlag();
        vo.setLogoutFlag(flag);
        vo.setStatusName(resolveLogoutFlagName(flag));
        vo.setLogoutFinishTime(resolveLogoutFinishTime(user, flag));
        return vo;
    }

    private String resolveLogoutFlagName(Integer logoutFlag) {
        if (logoutFlag != null && logoutFlag == StoreUser.LOGOUT_FLAG_COOLING) {
            return "注销中";
        }
        if (logoutFlag != null && logoutFlag == StoreUser.LOGOUT_FLAG_DONE) {
            return "已注销";
        }
        return "";
    }

    private Date resolveLogoutFinishTime(StoreUser user, Integer logoutFlag) {
        if (logoutFlag != null && logoutFlag == StoreUser.LOGOUT_FLAG_COOLING && user.getLogoutTime() != null) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(user.getLogoutTime());
            calendar.add(Calendar.DAY_OF_YEAR, 7);
            return calendar.getTime();
        }
        return user.getUpdatedTime();
    }
}
