package com.jeesharp.business.modules.member.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeesharp.business.modules.member.convert.MemberConvert;
import com.jeesharp.business.modules.member.constants.MobileAuthConstants;
import com.jeesharp.business.modules.member.dto.MemberSaveDTO;
import com.jeesharp.business.modules.member.dto.MemberThirdPartyLoginOutcome;
import com.jeesharp.business.modules.member.entity.Member;
import com.jeesharp.business.modules.member.entity.MemberLevel;
import com.jeesharp.business.modules.member.mapper.MemberMapper;
import com.jeesharp.business.modules.member.entity.MemberVip;
import com.jeesharp.business.modules.member.enums.MemberPointsTypeEnum;
import com.jeesharp.business.modules.member.service.MemberLevelFeatureService;
import com.jeesharp.business.modules.member.service.MemberLevelService;
import com.jeesharp.business.modules.member.service.MemberOauthService;
import com.jeesharp.business.modules.member.service.MemberPointsLogService;
import com.jeesharp.business.modules.member.service.MemberService;
import com.jeesharp.business.modules.member.service.MemberVipService;
import com.jeesharp.business.modules.member.vo.MemberImportVO;
import com.jeesharp.business.modules.member.vo.MemberQueryVO;
import com.jeesharp.business.modules.member.vo.MemberDisplayVO;
import com.jeesharp.business.modules.member.vo.MemberOrderDisplay;
import com.jeesharp.framework.exception.BizErrorException;
import com.jeesharp.framework.mybatis.core.service.CrudService;
import com.jeesharp.framework.pojo.vo.ImportRespVO;
import com.jeesharp.framework.utils.ServletUtils;
import com.jeesharp.framework.utils.WebFrameworkUtils;
import com.jeesharp.framework.utils.base.ExceptionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * 会员服务实现类
 *
 * @author jeesharp
 * @version 2024-01-24
 */
@Service
@Transactional(readOnly = true)
public class MemberServiceImpl extends CrudService<MemberMapper, Member, MemberQueryVO> implements MemberService {

    @Autowired
    private MemberLevelService memberLevelService;

    @Autowired
    private MemberLevelFeatureService memberLevelFeatureService;

    @Autowired
    @Lazy
    private MemberVipService memberVipService;

    @Autowired
    private MemberOauthService memberOauthService;

    @Autowired
    private MemberPointsLogService memberPointsLogService;

    // ==================== 重写父类方法 ====================

    /**
     * 根据ID获取会员信息
     */
    @Override
    public Member get(String id) {
        return super.get(id);
    }

    /**
     * 保存会员
     */
    @Override
    @Transactional(readOnly = false)
    public boolean save(Member member) {
        // 业务规则验证
        //validateMember(member);

        // 新增时生成会员编号
        if (StrUtil.isBlank(member.getId())) {
            member.setMemberNo(generateMemberNo());
            // 设置默认值
            initDefaultValues(member);
        }

        return super.save(member);
    }

    // ==================== 自定义业务方法 ====================

    /**
     * 批量删除会员
     */
    @Override
    @Transactional(readOnly = false)
    public void deleteData(List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return;
        }
        this.batchDelete(ids);
    }

    @Override
    public List<Member> listByIds(List<String> ids) {
        if (CollUtil.isEmpty(ids)) {
            return List.of();
        }
        List<String> idList = ids.stream()
                .filter(StrUtil::isNotBlank)
                .map(String::trim)
                .distinct()
                .toList();
        if (idList.isEmpty()) {
            return List.of();
        }
        String tenantCode = WebFrameworkUtils.getLoginUserTenantCode();
        if (StrUtil.isBlank(tenantCode)) {
            return List.of();
        }
        return mapper.selectByIds(tenantCode, idList);
    }

    @Override
    public List<String> findIdsByKeyword(String keyword) {
        if (StrUtil.isBlank(keyword)) {
            return List.of();
        }
        String tenantCode = WebFrameworkUtils.getLoginUserTenantCode();
        if (StrUtil.isBlank(tenantCode)) {
            return List.of();
        }
        List<String> ids = mapper.selectIdsByKeyword(tenantCode, keyword.trim());
        return ids != null ? ids : List.of();
    }

    @Override
    public List<String> findIdsByKeywordForGrant(String keyword) {
        if (StrUtil.isBlank(keyword)) {
            return List.of();
        }
        List<String> ids = mapper.selectIdsByKeywordWithoutTenant(keyword.trim());
        return ids != null ? ids : List.of();
    }

    @Override
    public Map<String, MemberDisplayVO> mapDisplayByIds(List<String> memberIds) {
        List<String> idList = normalizeMemberIdsForDisplay(memberIds);
        if (idList.isEmpty()) {
            return Collections.emptyMap();
        }
        List<Member> members = mapper.selectByIdsForDisplay(idList);
        if (CollUtil.isEmpty(members)) {
            return Collections.emptyMap();
        }
        return members.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(Member::getId, this::toDisplayVO, (a, b) -> a));
    }

    @Override
    public <T extends MemberOrderDisplay> void enrichMemberDisplay(List<T> rows) {
        if (CollUtil.isEmpty(rows)) {
            return;
        }
        List<String> memberIds = rows.stream()
                .map(MemberOrderDisplay::getMemberId)
                .collect(Collectors.collectingAndThen(Collectors.toList(), this::normalizeMemberIdsForDisplay));
        Map<String, MemberDisplayVO> displayMap = mapDisplayByIds(memberIds);
        for (T row : rows) {
            applyDisplay(row, displayMap.get(row.getMemberId()));
        }
    }

    @Override
    public void enrichMemberDisplay(MemberOrderDisplay row) {
        if (row == null || StrUtil.isBlank(row.getMemberId())) {
            return;
        }
        String memberId = row.getMemberId().trim();
        if ("-".equals(memberId)) {
            return;
        }
        applyDisplay(row, mapDisplayByIds(List.of(memberId)).get(memberId));
    }

    private MemberDisplayVO toDisplayVO(Member member) {
        MemberDisplayVO vo = new MemberDisplayVO();
        vo.setMemberId(member.getId());
        vo.setMemberNo(member.getMemberNo());
        vo.setMemberNickname(resolveDisplayName(member));
        vo.setMemberMobile(member.getMobile());
        return vo;
    }

    private static void applyDisplay(MemberOrderDisplay row, MemberDisplayVO display) {
        if (row == null || display == null) {
            return;
        }
        row.setMemberNo(display.getMemberNo());
        row.setMemberNickname(display.getMemberNickname());
        row.setMemberMobile(display.getMemberMobile());
    }

    /**
     * 订单/预约单展示补全用会员主键：去空、去占位符、去重。
     */
    private List<String> normalizeMemberIdsForDisplay(List<String> memberIds) {
        if (CollUtil.isEmpty(memberIds)) {
            return List.of();
        }
        return memberIds.stream()
                .filter(StrUtil::isNotBlank)
                .map(String::trim)
                .filter(id -> !"-".equals(id))
                .distinct()
                .toList();
    }

    private static String resolveDisplayName(Member member) {
        if (StrUtil.isNotBlank(member.getRealName())) {
            return member.getRealName();
        }
        return StrUtil.nullToDefault(member.getNickname(), "");
    }

    /**
     * 导入会员数据
     */
    @Override
    @Transactional(readOnly = false)
    public ImportRespVO importData(List<MemberImportVO> list) {
        if (CollUtil.isEmpty(list)) {
            ExceptionUtil.error("导入的数据为空");
        }

        ImportRespVO respVO = ImportRespVO.builder()
                .createData(new ArrayList<>())
                .updateData(new ArrayList<>())
                .failureData(new LinkedHashMap<>())
                .build();

        int rowNum = 1;
        for (MemberImportVO importVO : list) {
            try {
                // 数据验证
                validateImportData(importVO, rowNum);

                // 检查手机号是否已存在
                Member existMember = getByMobile(importVO.getMobile());

                // 转换
                Member member = null;//MemberConvert.INSTANCE.infoToEntity(importVO);

                if (existMember != null) {
                    // 更新
                    member.setId(existMember.getId());
                    member.setMemberNo(existMember.getMemberNo());
                    member.preUpdate();
                    mapper.update(member);
                    respVO.getUpdateData().add("第" + rowNum + "行：" + importVO.getMobile());
                } else {
                    // 新增
                    member.setMemberNo(generateMemberNo());
                    member.setSource("IMPORT");
                    member.setRegisterDate(LocalDateTime.now());
                    initDefaultValues(member);
                    member.preInsert();
                    mapper.insert(member);
                    respVO.getCreateData().add("第" + rowNum + "行：" + importVO.getMobile());
                }
            } catch (Exception e) {
                respVO.getFailureData().put("第" + rowNum + "行", e.getMessage());
            }
            rowNum++;
        }
        return respVO;
    }

    /**
     * 根据手机号查询会员
     */
    @Override
    public Member getByMobile(String mobile) {
        if (StrUtil.isBlank(mobile)) {
            return null;
        }
        LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Member::getMobile, mobile);
        return this.getOne(wrapper);
    }

    /**
     * 根据邮箱查询会员
     */
    @Override
    public Member getByEmail(String email) {
        if (StrUtil.isBlank(email)) {
            return null;
        }
        LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Member::getEmail, email);
        return this.getOne(wrapper);
    }

    /**
     * 根据会员编号查询会员
     */
    @Override
    public Member getByMemberNo(String memberNo) {
        if (StrUtil.isBlank(memberNo)) {
            return null;
        }
        LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Member::getMemberNo, memberNo);
        return this.getOne(wrapper);
    }

    /**
     * 校验手机号是否唯一
     */
    @Override
    public boolean checkMobileUnique(String mobile, String excludeId) {
        Member member = getByMobile(mobile);
        if (member == null) {
            return true;
        }
        // 如果是更新操作，排除自身
        if (StrUtil.isNotBlank(excludeId) && excludeId.equals(member.getId())) {
            return true;
        }
        return false;
    }

    private static final int MEMBER_NO_MAX_RETRY = 20;

    /**
     * 生成 8 位纯数字会员编号（首位非 0），并校验库内唯一。
     */
    @Override
    public String generateMemberNo() {
        for (int i = 0; i < MEMBER_NO_MAX_RETRY; i++) {
            String candidate = buildRandomMemberNo();
            if (getByMemberNo(candidate) == null) {
                return candidate;
            }
        }
        throw new BizErrorException("生成会员码失败，请稍后重试");
    }

    /**
     * 老会员无编号时补生成并写回。
     */
    @Override
    @Transactional(readOnly = false)
    public String ensureMemberNo(String memberId) {
        if (StrUtil.isBlank(memberId)) {
            throw new BizErrorException("会员ID不能为空");
        }
        Member member = get(memberId);
        if (member == null) {
            throw new BizErrorException("会员不存在");
        }
        if (StrUtil.isNotBlank(member.getMemberNo())) {
            return member.getMemberNo();
        }
        String memberNo = generateMemberNo();
        member.setMemberNo(memberNo);
        update(member);
        return memberNo;
    }

    private String buildRandomMemberNo() {
        int value = ThreadLocalRandom.current().nextInt(10_000_000, 100_000_000);
        return String.valueOf(value);
    }

    /**
     * 增加积分
     */
    @Override
    @Transactional(readOnly = false)
    public void addPoints(String memberId, Integer points, String bizType, String bizId, String bizDesc) {
        if (points == null || points <= 0) {
            return;
        }
        Member member = get(memberId);
        int before = member.getAvailablePoints() != null ? member.getAvailablePoints() : 0;
        int totalBefore = member.getTotalPoints() != null ? member.getTotalPoints() : 0;
        member.setTotalPoints(totalBefore + points);
        member.setAvailablePoints(before + points);
        this.update(member);
        memberPointsLogService.recordChange(
                memberId,
                MemberPointsTypeEnum.EARN,
                points,
                before,
                before + points,
                bizType,
                bizId,
                bizDesc);
    }

    @Override
    @Transactional(readOnly = false)
    public String addPointsWithRule(String memberId, Integer points, String bizType, String bizId, String bizDesc,
                                    String ruleId, String ruleName, LocalDateTime expireDate, String operateSource) {
        if (points == null || points <= 0) {
            return null;
        }
        Member member = get(memberId);
        int before = member.getAvailablePoints() != null ? member.getAvailablePoints() : 0;
        int totalBefore = member.getTotalPoints() != null ? member.getTotalPoints() : 0;
        member.setTotalPoints(totalBefore + points);
        member.setAvailablePoints(before + points);
        this.update(member);
        return memberPointsLogService.recordChangeWithRule(
                memberId,
                MemberPointsTypeEnum.EARN,
                points,
                before,
                before + points,
                bizType,
                bizId,
                bizDesc,
                ruleId,
                ruleName,
                expireDate,
                operateSource);
    }

    /**
     * 扣减积分
     */
    @Override
    @Transactional(readOnly = false)
    public void deductPoints(String memberId, Integer points, String bizType, String bizId, String bizDesc) {
        if (points == null || points <= 0) {
            return;
        }
        Member member = get(memberId);
        int before = member.getAvailablePoints() != null ? member.getAvailablePoints() : 0;
        if (before < points) {
            ExceptionUtil.error("可用积分不足");
        }
        int usedBefore = member.getUsedPoints() != null ? member.getUsedPoints() : 0;
        member.setAvailablePoints(before - points);
        member.setUsedPoints(usedBefore + points);
        this.update(member);
        memberPointsLogService.recordChange(
                memberId,
                MemberPointsTypeEnum.SPEND,
                points,
                before,
                before - points,
                bizType,
                bizId,
                bizDesc);
    }

    @Override
    @Transactional(readOnly = false)
    public String deductPointsWithRule(String memberId, Integer points, String bizType, String bizId, String bizDesc,
                                       String ruleId, String ruleName, String operateSource) {
        if (points == null || points <= 0) {
            return null;
        }
        Member member = get(memberId);
        int before = member.getAvailablePoints() != null ? member.getAvailablePoints() : 0;
        if (before < points) {
            ExceptionUtil.error("可用积分不足");
        }
        int usedBefore = member.getUsedPoints() != null ? member.getUsedPoints() : 0;
        member.setAvailablePoints(before - points);
        member.setUsedPoints(usedBefore + points);
        this.update(member);
        return memberPointsLogService.recordChangeWithRule(
                memberId,
                MemberPointsTypeEnum.SPEND,
                points,
                before,
                before - points,
                bizType,
                bizId,
                bizDesc,
                ruleId,
                ruleName,
                null,
                operateSource);
    }

    /**
     * 增加成长值
     */
    @Override
    @Transactional(readOnly = false)
    public void addGrowthValue(String memberId, Integer growthValue, String bizType, String bizDesc) {
        if (growthValue == null || growthValue <= 0) {
            return;
        }
        Member member = get(memberId);
        member.setGrowthValue(member.getGrowthValue() + growthValue);
        this.update(member);
        // 检查是否需要升级
        updateMemberLevel(memberId);
        // TODO: 记录成长值流水
    }

    /**
     * 更新会员等级
     */
    @Override
    @Transactional(readOnly = false)
    public void updateMemberLevel(String memberId) {
        Member member = get(memberId);
        MemberLevel newLevel = memberLevelService.getLevelByGrowthValue(member.getGrowthValue());
        if (newLevel != null && !newLevel.getLevelCode().equals(member.getLevelCode())) {
            member.setLevelId(newLevel.getId());
            member.setLevelCode(newLevel.getLevelCode());
            this.update(member);
            // TODO: 发放升级礼包
        }
    }

    // ==================== 私有方法 ====================

    /**
     * 会员验证
     */
    private void validateMember(Member member) {
        if (StrUtil.isBlank(member.getMobile())) {
            ExceptionUtil.error("手机号不能为空");
        }
        // 校验手机号唯一性
        if (!checkMobileUnique(member.getMobile(), member.getId())) {
            ExceptionUtil.error("手机号已被注册：" + member.getMobile());
        }
    }

    /**
     * 导入数据验证
     */
    private void validateImportData(MemberImportVO importVO, int rowNum) {
        if (StrUtil.isBlank(importVO.getMobile())) {
            throw new RuntimeException("手机号不能为空");
        }
        if (!importVO.getMobile().matches("^1[3-9]\\d{9}$")) {
            throw new RuntimeException("手机号格式不正确");
        }
    }

    /**
     * 初始化默认值
     */
    private void initDefaultValues(Member member) {
        if (member.getStatus() == null) {
            member.setStatus(1);
        }
        if (member.getLevelCode() == null) {
            member.setLevelCode("NORMAL");
        }
        if (StrUtil.isBlank(member.getLevelId()) && "NORMAL".equals(member.getLevelCode())) {
            member.setLevelId("1");
        }
        if (member.getLevelId() == null && member.getLevelCode() != null) {
            MemberLevel defaultLevel = memberLevelService.getByLevelCode(member.getLevelCode());
            if (defaultLevel != null) {
                member.setLevelId(defaultLevel.getId());
            }
        }
        if (member.getIsVip() == null) {
            member.setIsVip(0);
        }
        if (member.getGrowthValue() == null) {
            member.setGrowthValue(0);
        }
        if (member.getTotalPoints() == null) {
            member.setTotalPoints(0);
        }
        if (member.getAvailablePoints() == null) {
            member.setAvailablePoints(0);
        }
        if (member.getFrozenPoints() == null) {
            member.setFrozenPoints(0);
        }
        if (member.getUsedPoints() == null) {
            member.setUsedPoints(0);
        }
        if (member.getExpiredPoints() == null) {
            member.setExpiredPoints(0);
        }
        if (member.getTotalConsumeAmount() == null) {
            member.setTotalConsumeAmount(BigDecimal.ZERO);
        }
        if (member.getTotalConsumeCount() == null) {
            member.setTotalConsumeCount(0);
        }
        if (member.getBalance() == null) {
            member.setBalance(BigDecimal.ZERO);
        }
        if (member.getFrozenBalance() == null) {
            member.setFrozenBalance(BigDecimal.ZERO);
        }
        if (member.getInviteCount() == null) {
            member.setInviteCount(0);
        }
        if (member.getLoginCount() == null) {
            member.setLoginCount(0);
        }
        if (member.getIsRealName() == null) {
            member.setIsRealName(0);
        }
        if (member.getIsCompleteProfile() == null) {
            member.setIsCompleteProfile(0);
        }
        if (member.getGender() == null) {
            member.setGender(0);
        }
        // 生成邀请码
        if (StrUtil.isBlank(member.getInviteCode())) {
            member.setInviteCode(IdUtil.nanoId(8).toUpperCase());
        }
    }

    /**
     * 获取会员可用功能权限码列表（供 Sa-Token StpInterface 使用）
     *
     * @param memberId 会员ID
     * @return 功能权限码列表
     */
    @Override
    @Transactional(readOnly = true)
    public List<String> getMemberFeatureCodes(String memberId) {
        if (StrUtil.isBlank(memberId)) {
            return new ArrayList<>();
        }
        Member member = this.getById(memberId);
        if (member == null) {
            return new ArrayList<>();
        }
        MemberLevel growthLevel = memberLevelService.getByLevelCode(member.getLevelCode());
        if (growthLevel == null) {
            growthLevel = memberLevelService.getByLevelCode("NORMAL");
        }
        int growthLevelSort = growthLevel != null ? (growthLevel.getLevelSort() != null ? growthLevel.getLevelSort() : 1) : 1;
        String tenantId = WebFrameworkUtils.getLoginUserTenantId();
        List<String> features = new ArrayList<>(memberLevelFeatureService.getFeatureCodesByLevelSort(growthLevelSort, tenantId));

        MemberVip activeVip = memberVipService.getActiveVip(memberId);
        if (activeVip != null) {
            MemberLevel vipLevel = memberLevelService.getByLevelCode(activeVip.getLevelCode());
            if (vipLevel != null && vipLevel.getLevelSort() != null) {
                List<String> vipFeatures = memberLevelFeatureService.getFeatureCodesByLevelSort(vipLevel.getLevelSort(), tenantId);
                for (String code : vipFeatures) {
                    if (!features.contains(code)) {
                        features.add(code);
                    }
                }
            }
        }
        return features;
    }

    /**
     * 更新会员状态
     *
     * @param id     会员ID
     * @param status 状态
     */
    @Override
    public void updateStatus(String id, Integer status) {
        Member member = this.get(id);
        member.setStatus(status);
        this.update(member);
    }

    /**
     * Saves or updates member data based on the provided MemberSaveDTO.
     *
     * @param dto the MemberSaveDTO object containing the member information to be saved or updated
     */
    @Override
    public void saveData(MemberSaveDTO dto) {
        Member member = MemberConvert.INSTANCE.toEntity(dto);
        // 设置默认状态
        if (member.getStatus() == null) {
            member.setStatus(1);
        }
        // 新增时设置注册时间、会员编号（app_member.member_no 非空且无默认值；saveOrUpdate 插入路径不经过 save() 的编号逻辑）
        if (StrUtil.isBlank(dto.getId())) {
            member.setRegisterDate(LocalDateTime.now());
            if (StrUtil.isBlank(member.getMemberNo())) {
                member.setMemberNo(generateMemberNo());
            }
        }
        member.setGrowthValue(1);
        this.saveOrUpdate(member);
        dto.setId(member.getId());
    }

    @Override
    @Transactional(readOnly = false)
    public void recordLoginSuccess(String memberId, String loginType) {
        if (StrUtil.isBlank(memberId)) {
            return;
        }
        Member existing = get(memberId);
        if (existing == null) {
            return;
        }
        Member update = new Member();
        update.setId(memberId);
        update.setLastLoginDate(LocalDateTime.now());
        update.setLastLoginIp(ServletUtils.getClientIP());
        if (StrUtil.isNotBlank(loginType)) {
            update.setLastLoginType(loginType);
        }
        int loginCount = existing.getLoginCount() == null ? 0 : existing.getLoginCount();
        update.setLoginCount(loginCount + 1);
        getBaseMapper().updateById(update);
    }

    @Override
    @Transactional(readOnly = false)
    public Member createMemberByMobileForAuth(String mobile, String inviteCode, String source) {
        MemberSaveDTO dto = new MemberSaveDTO();
        dto.setMobile(mobile);
        dto.setSource(source != null ? source : MobileAuthConstants.MEMBER_SOURCE_APP);
        saveData(dto);
        return getByMobile(mobile);
    }

    @Override
    @Transactional(readOnly = false)
    public Member createMemberByEmailForAuth(String email, String inviteCode, String source) {
        Member member = new Member();
        member.setEmail(email);
        member.setSource(source != null ? source : MobileAuthConstants.MEMBER_SOURCE_APP);
        member.setMemberNo(generateMemberNo());
        member.setStatus(MobileAuthConstants.MEMBER_STATUS_NORMAL);
        member.setRegisterDate(LocalDateTime.now());
        save(member);
        return getByEmail(email);
    }

    @Override
    public Member findMemberByAccountForAuth(String account) {
        if (StrUtil.isBlank(account)) {
            return null;
        }
        if (account.matches(MobileAuthConstants.PATTERN_CN_MOBILE)) {
            return getByMobile(account);
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MemberThirdPartyLoginOutcome findOrCreateMemberForThirdParty(
            String source,
            String inviteCode,
            String unionId,
            String openId,
            String nickname,
            String avatar,
            String oauthAppId) {
        MemberThirdPartyLoginOutcome outcome = new MemberThirdPartyLoginOutcome();
        Member member = memberOauthService.resolveMemberForJustAuthSource(source, unionId, openId, oauthAppId);

        if (member == null) {
            outcome.setNewlyCreated(true);
            MemberSaveDTO saveDto = new MemberSaveDTO();
            saveDto.setNickname(nickname);
            saveDto.setAvatar(avatar);
            saveDto.setSource(source);
            saveDto.setMemberNo(generateMemberNo());
            saveData(saveDto);
            member = get(saveDto.getId());
            memberOauthService.upsertJustAuthBinding(member.getId(), source, unionId, openId, oauthAppId);
        } else {
            outcome.setNewlyCreated(false);
            boolean needUpdate = false;
            if (StrUtil.isNotBlank(nickname) && !nickname.equals(member.getNickname())) {
                member.setNickname(nickname);
                needUpdate = true;
            }
            if (StrUtil.isNotBlank(avatar) && !avatar.equals(member.getAvatar())) {
                member.setAvatar(avatar);
                needUpdate = true;
            }
            if (needUpdate) {
                update(member);
            }
            memberOauthService.upsertJustAuthBinding(member.getId(), source, unionId, openId, oauthAppId);
        }

        outcome.setMember(member);
        return outcome;
    }
}
