package com.wzj.soopin.member.service.impl;

import cn.dev33.satoken.secure.BCrypt;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzj.soopin.member.convert.MemberConvert;
import com.wzj.soopin.member.domain.bo.MemberBO;
import com.wzj.soopin.member.domain.po.Member;
import com.wzj.soopin.member.domain.po.MemberAccount;
import com.wzj.soopin.member.domain.query.ReferenceMemberQuery;
import com.wzj.soopin.member.domain.vo.MemberVO;
import com.wzj.soopin.member.domain.vo.ReferenceMemberVO;
import com.wzj.soopin.member.mapper.MemberAccountMapper;
import com.wzj.soopin.member.mapper.MemberCartMapper;
import com.wzj.soopin.member.mapper.MemberMapper;
import com.wzj.soopin.member.service.IFansService;
import com.wzj.soopin.member.service.IMemberService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.constant.ResultCode;
import org.dromara.common.core.domain.event.Constants;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.redis.redis.RedisCache;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysTenantVo;
import org.dromara.system.mapper.SysUserMapper;
import org.dromara.system.service.ISysTenantService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 会员信息Service业务层处理
 *
 *
 * @author zcc
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class MemberServiceImpl extends ServiceImpl<MemberMapper,Member> implements IMemberService {

    private final MemberCartMapper memberCartMapper;

    private final RedisCache redisCache;

    private final MemberAccountMapper memberAccountMapper;

    private final MemberConvert memberConvert;

    private final MemberMapper memberMapper;

    private final IFansService fansService;
    private final TencentIMServiceImpl tencentIMServiceImpl;

    private final SysUserMapper sysUserMapper;

    private final ISysTenantService tenantService;

    @Override
    public boolean usernameExists(String username) {
        return baseMapper.countByUsername(username) > 0; // 确保实现
    }


    @Override
    public boolean save(Member entity) {
        super.save(entity);

        MemberAccount account=MemberAccount.builder().memberId(entity.getId()).build();
        memberAccountMapper.insert(account);

        return  true;
    }

    @Override
    public Member findByUsername(String userName) {
        QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", userName);
        return this.baseMapper.selectOne(queryWrapper);
    }
    @Override
    @Cacheable(value = GlobalConstants.MEMBER_KEY, key = "#mobile")
    public Member findByMobile( String mobile) {
        QueryWrapper<Member> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("mobile", mobile);
        return this.baseMapper.selectOne(queryWrapper);
    }

    @CacheEvict(value = GlobalConstants.MEMBER_KEY, key = "#id")
    public int updateMark(MemberBO member) {
        UpdateWrapper<Member> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("mark",member.getMark())
                .set("update_time",LocalDateTime.now())
                .eq("id",member.getId());
        return baseMapper.update(null,updateWrapper);
    }



    @CacheEvict(value = GlobalConstants.MEMBER_KEY, key = "#id")
    public Integer changeStatus(MemberBO bo) {
        UpdateWrapper<Member> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", bo.getId());
        wrapper.set("status", bo.getStatus());
        return baseMapper.update(null, wrapper);
    }



    @Override
    public Member modifyPass(String oldPassword, String newPassword) {
        LoginUser tokenUser = LoginHelper.getLoginUser();
        if (tokenUser == null) {
            throw new ServiceException(ResultCode.USER_NOT_LOGIN);
        }
        Member member = this.getById(tokenUser.getUserId());
        // 判断旧密码输入是否正确
        if (!BCrypt.checkpw(member.getPassword(),oldPassword)) {
            throw new ServiceException(ResultCode.USER_OLD_PASSWORD_ERROR);
        }
        // 修改会员密码
        LambdaUpdateWrapper<Member> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
        lambdaUpdateWrapper.eq(Member::getId, member.getId());
        lambdaUpdateWrapper.set(Member::getPassword, BCrypt.hashpw(newPassword));
        this.update(lambdaUpdateWrapper);
        return member;
    }

    @Override
    public boolean changeMobile(String mobile) {
        LoginUser tokenUser = LoginHelper.getLoginUser();
        Member member = this.getById(tokenUser.getUserId());

        // 修改会员手机号
        LambdaUpdateWrapper<Member> lambdaUpdateWrapper = Wrappers.lambdaUpdate();
        lambdaUpdateWrapper.eq(Member::getId, member.getId());
        lambdaUpdateWrapper.set(Member::getPhoneHidden, mobile);
        return this.update(lambdaUpdateWrapper);
    }
    /**
     * 更新会员状态
     * 支持设置封禁时长
     *
     * @param memberIds 会员ID列表
     * @param disabled  是否禁用
     * @param banDays   封禁天数，null表示永久封禁
     * @return 操作结果代码
     */
    @Override
    public ResultCode updateMemberStatus(List<String> memberIds, Boolean disabled, Integer banDays) {
        if (memberIds == null || memberIds.isEmpty()) {
            return ResultCode.USER_NOT_EXIST;
        }

        try {
            UpdateWrapper<Member> updateWrapper = new UpdateWrapper<>();
            updateWrapper.in("id", memberIds);

            if (Boolean.TRUE.equals(disabled)) {
                // 计算解封时间
                Date banEndTime = null;
                if (banDays != null && banDays > 0) {
                    // 使用 Calendar 设置解封日期
                    Calendar calendar = Calendar.getInstance();
                    calendar.add(Calendar.DAY_OF_MONTH, banDays);
                    banEndTime = calendar.getTime();
                }
                // 设置封禁状态和解封时间
                updateWrapper.set("delete_flag", true);
                updateWrapper.set("ban_end_time", banEndTime);

                // 记录操作日志
                log.info("封禁会员: memberIds={}, banDays={}, banEndTime={}",
                    memberIds, banDays, banEndTime);
            } else {
                // 解除封禁
                updateWrapper.set("delete_flag", false);
                updateWrapper.set("ban_end_time", null);

                // 记录操作日志
                log.info("解封会员: memberIds={}", memberIds);
            }

            boolean result = this.update(updateWrapper);

            // 如果更新失败，检查记录是否存在
            if (!result) {
                long count = this.count(new QueryWrapper<Member>().in("id", memberIds));
                if (count == 0) {
                    log.warn("更新会员状态失败: 未找到指定会员, memberIds={}", memberIds);
                    return ResultCode.USER_NOT_EXIST;
                } else {
                    log.warn("更新会员状态失败: 更新操作失败, memberIds={}", memberIds);
                    return ResultCode.ERROR;
                }
            }

            return ResultCode.SUCCESS;
        } catch (Exception e) {
            log.error("更新会员状态异常", e);
            return ResultCode.ERROR;
        }
    }

    /**
     * 定时任务：检查并解除到期的封禁账号
     * 每天凌晨执行
     */
    @Scheduled(cron = "0 0 0 * * ?")
    public void checkAndUnbanMembers() {
        log.info("开始执行会员自动解封任务");
        Date now = new Date();

        // 查找到期需要解封的会员数量
        QueryWrapper<Member> countWrapper = new QueryWrapper<>();
        countWrapper.eq("disabled", true)
            .isNotNull("ban_end_time")
            .le("ban_end_time", now);
        long count = this.count(countWrapper);

        if (count > 0) {
            // 解除封禁
            UpdateWrapper<Member> updateWrapper = new UpdateWrapper<>();
            updateWrapper.set("disabled", false)
                .set("ban_end_time", null)
                .eq("disabled", true)
                .isNotNull("ban_end_time")
                .le("ban_end_time", now);

            boolean result = this.update(updateWrapper);
            log.info("会员自动解封任务完成，解封会员数量：{}，处理结果：{}", count, result);
        } else {
            log.info("会员自动解封任务完成，无需要解封的会员");
        }
    }


    @Override
    public String getPhoneDecrypted(String phoneEncrypted) {
        return phoneEncrypted;
    }


    @Override
    @Cacheable (cacheNames = GlobalConstants.MEMBER_KEY , key = "#id")
    public Member getById(Serializable id) {
        return super.getById(id);
    }


    @Override
    public MemberVO getMemberInfo(Serializable id) {
        MemberVO memberVO = memberConvert.toVO(getById(id));
        //获取粉丝数量
        return memberVO;

    }


    @Override
    public MemberVO getLoginMemberInfo() {
        LoginUser tokenUser = LoginHelper.getLoginUser();
        return this.getMemberInfo(tokenUser.getUserId());
    }
    @Override
    public String updateWechat(MemberBO bo) {

        String openId=bo.getAvatar();
        //到微信去验证
        String token=bo.getPassword();

        return openId;
    }

    /**
     * 不带租户的获取会员信息
     *
     * @param query
     * @param page
     * @return
     */
    @Override
    public IPage<MemberVO> getMemberPageList(MemberBO query, Page<Member> page) {
        IPage<MemberVO> memeberPage= memberMapper.getMember(page, query);
        //检查是否是朋友
        LoginUser tokenUser = LoginHelper.getLoginUser();
        if (tokenUser != null) {
            List<MemberVO> records = memeberPage.getRecords();
            for (MemberVO memberVO : records) {
//
//                boolean followFlag = fansService.queryDoIFollowVloger(tokenUser.getUserId(), memberVO.getId());
//                if(followFlag){
//                    memberVO.setFollowFlag(YesOrNo.YES.type);
//                }else{
//                    memberVO.setFollowFlag(YesOrNo.NO.type);
//                }
                memberVO.setDoIFollowVloger(fansService.queryDoIFollowVloger(tokenUser.getUserId(), memberVO.getId()));

            }
        }
        return memeberPage;
    }

    @Override
    public void syncInfo() {

        //分页拉取用户信息
        Page<Member> memberPage=memberMapper.selectPage(new Page<>(1,100),null);
        List<Member> records = memberPage.getRecords();
        Map<Long,Member> memberMap = new HashMap<>(records.size());
        records.stream().forEach(member -> memberMap.put(member.getId(),member));
        List<String> ids=records.stream().map(member -> member.getId()+"").collect(Collectors.toList());
        JSONArray jsonArray=tencentIMServiceImpl.checkTencentIMAccount(ids);
        if(jsonArray!=null){
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject o=jsonArray.getJSONObject(i);
                String userID=o.getStr("UserID");
                String accountStatus=o.getStr("AccountStatus");
                if(accountStatus.equals("NotImported")){
                    //不存在，创建
                    tencentIMServiceImpl.createTencentIMAccount(memberMap.get(Long.valueOf(userID)));
                }
            }
        }
        return;
    }

    @Override
    public Page<ReferenceMemberVO> getByReference(ReferenceMemberQuery query) {
        Assert.isTrue(query.getCurrent() != null  && query.getSize() != null, "分页参数不能为空");
        SysUser sysUser = sysUserMapper.selectReferneceByTenantId(TenantHelper.getTenantId());
        SysTenantVo referenceTenant = tenantService.queryByTenantId(TenantHelper.getTenantId());
        Assert.isTrue(StrUtil.isNotBlank(referenceTenant.getAgencyTenantId()), () -> new ServiceException("当前租户无绑定会员"));
        SysTenantVo agencyTenant = tenantService.queryByTenantId(referenceTenant.getAgencyTenantId());
        Member member = memberMapper.selectOne(Wrappers.lambdaQuery(Member.class).eq(Member::getUserId, sysUser.getUserId()).last("LIMIT 1"));
        Assert.notNull(member, () -> new ServiceException("团长未绑定会员账户"));
        LambdaQueryWrapper<Member> lambdaQueryWrapper = Wrappers.lambdaQuery(Member.class)
            .eq(Member::getSpreadUid, member.getId())
            .like(StrUtil.isNotEmpty(query.getNickname()), Member::getNickname, query.getNickname())
            .like(StrUtil.isNotEmpty(query.getPhone()), Member::getPhoneHidden, query.getPhone())
            .orderByDesc(Member::getSpreadTime);
        if (query.getSpreadTime() != null) {
            lambdaQueryWrapper.ge(Member::getSpreadTime, LocalDateTimeUtil.beginOfDay(query.getSpreadTime()));
            lambdaQueryWrapper.le(Member::getSpreadTime, LocalDateTimeUtil.endOfDay(query.getSpreadTime()));
        }
        Page<Member> page = this.page(Page.of(query.getCurrent(), query.getSize()), lambdaQueryWrapper);
        List<ReferenceMemberVO> list = page.getRecords().stream().map(m -> {
            ReferenceMemberVO referenceMemberVO = BeanUtil.copyProperties(m, ReferenceMemberVO.class);
            referenceMemberVO.setAgencyTenantName(agencyTenant.getAgencyName());
            referenceMemberVO.setSpreadUserName(sysUser.getNickName());
            return referenceMemberVO;
        }).toList();
        Page<ReferenceMemberVO> objectPage = Page.of(page.getCurrent(), page.getSize(), page.getTotal());
        objectPage.setRecords(list);
        return objectPage;
    }

    @Override
    public void smsCode(String templateId) {
        String phoneNumber = LoginHelper.getLoginUser().getPhoneNumber();
        String key = GlobalConstants.CAPTCHA_CODE_KEY + phoneNumber;
        String code = RandomUtil.randomNumbers(4);
        RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
        LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
        map.put("code", code);
        SmsBlend smsBlend = SmsFactory.getSmsBlend("config2");
        SmsResponse smsResponse = smsBlend.sendMessage(phoneNumber, templateId, map);
        if (!smsResponse.isSuccess()) {
            log.error("短信验证码发送异常 => {}", smsResponse);
            throw new ServiceException("短信验证码发送异常");
        }
    }

    @Override
    public void revoked(String smsCode) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        String phoneNumber = loginUser.getPhoneNumber();
        String code = RedisUtils.getCacheObject(GlobalConstants.CAPTCHA_CODE_KEY + phoneNumber);
        Assert.isTrue(StrUtil.equals(smsCode, code), () -> new ServiceException("短信验证码错误"));
        memberMapper.updateById(Member.builder().id(loginUser.getUserId()).status(Constants.MEMBER_ACCOUNT_STATUS.FORBIDDEN).build());
    }
}
