package com.czg.service.account.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.account.dto.shopuser.*;
import com.czg.account.entity.*;
import com.czg.account.service.*;
import com.czg.config.RedisCst;
import com.czg.enums.ShopUserFlowBizEnum;
import com.czg.enums.YesNoEnum;
import com.czg.exception.ApiNotPrintException;
import com.czg.order.entity.OrderInfo;
import com.czg.order.service.OrderDetailService;
import com.czg.order.service.OrderInfoService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.account.mapper.ShopConfigMapper;
import com.czg.service.account.mapper.ShopInfoMapper;
import com.czg.service.account.mapper.ShopUserMapper;
import com.czg.system.entity.SysParams;
import com.czg.system.service.SysParamsService;
import com.czg.utils.AssertUtil;
import com.czg.utils.JoinQueryWrapper;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;


/**
 * 商户储值会员 服务层实现。
 *
 * @author Administrator
 * @since 2025-02-08
 */
@DubboService
public class ShopUserServiceImpl extends ServiceImpl<ShopUserMapper, ShopUser> implements ShopUserService {
    @DubboReference
    private SysParamsService sysParamsService;
    @DubboReference
    private OrderInfoService orderInfoService;
    @DubboReference
    private OrderDetailService orderDetailService;

    @Resource
    private ShopUserFlowService shopUserFlowService;
    @Resource
    private UserInfoService userInfoService;
    @Resource
    private RedisService redisService;
    @Resource
    private ShopActivateCouponRecordService shopActivateCouponRecordService;
    @Resource
    private ShopInfoMapper shopInfoMapper;
    @Resource
    private ShopExtendService shopExtendService;
    @Resource
    private FreeDineConfigService freeDineConfigService;
    @Resource
    private ShopConfigMapper shopConfigMapper;

    private ShopUser getUserInfo(Long shopId, Long shopUserId) {
        ShopUser shopUser = queryChain().eq(ShopUser::getShopId, shopId).eq(ShopUser::getId, shopUserId).one();
        if (shopUser == null) {
            throw new ApiNotPrintException("用户信息不存在");
        }

        return shopUser;
    }

    @Override
    public Page<ShopUserDTO> getPage(String key, Integer isVip, BigDecimal amount) {
        PageHelper.startPage(PageUtil.buildPageHelp());
        return PageUtil.convert(new PageInfo<>(mapper.selectPageByKeyAndIsVip(StpKit.USER.getHeadShopId(), isVip, key, amount)));
    }

    @Override
    public Boolean updateInfo(Long shopId, ShopUserEditDTO shopUserEditDTO) {
        if (StrUtil.isNotBlank(shopUserEditDTO.getPhone())) {
            long count = count(new QueryWrapper().eq(ShopUser::getShopId, shopId).eq(ShopUser::getPhone, shopUserEditDTO.getPhone()).ne(ShopUser::getId, shopUserEditDTO.getId()));
            if (count > 0) {
                throw new ApiNotPrintException("手机号已存在");
            }
        }
        ShopUser shopUser = getUserInfo(shopId, shopUserEditDTO.getId());
        BeanUtil.copyProperties(shopUserEditDTO, shopUser);
        return updateById(shopUser);
    }

    @Override
    @Transactional
    public Long updateMoney(Long shopId, ShopUserMoneyEditDTO shopUserEditDTO) {
        shopUserEditDTO.setMoney(shopUserEditDTO.getMoney().setScale(2, RoundingMode.DOWN));
        ShopUser userInfo = getUserInfo(shopId, shopUserEditDTO.getId());

        ShopUserFlow userFlow = new ShopUserFlow();
        int flag;
        if (shopUserEditDTO.getType() == 0) {
            if (shopUserEditDTO.getMoney().compareTo(userInfo.getAmount()) > 0) {
                //如果超额退款 则退为0
                flag = mapper.decrAccount(shopId, shopUserEditDTO.getId(), DateUtil.date().toLocalDateTime(), userInfo.getAmount());
            } else {
                flag = mapper.decrAccount(shopId, shopUserEditDTO.getId(), DateUtil.date().toLocalDateTime(), shopUserEditDTO.getMoney());
            }
        } else {
            flag = mapper.incrAccount(shopId, shopUserEditDTO.getId(), DateUtil.date().toLocalDateTime(), shopUserEditDTO.getMoney());
        }
        if (flag == 0) {
            throw new ApiNotPrintException("增减用户余额操作失败");
        }

        userFlow.setUserId(userInfo.getUserId());
        userFlow.setShopId(userInfo.getShopId());
        userFlow.setAmount(shopUserEditDTO.getType() == 0 ? shopUserEditDTO.getMoney().negate() : shopUserEditDTO.getMoney());
        userFlow.setBalance(shopUserEditDTO.getType() == 0 ? userInfo.getAmount().subtract(shopUserEditDTO.getMoney()) : userInfo.getAmount().add(shopUserEditDTO.getMoney()));
        if (userFlow.getBalance().compareTo(BigDecimal.ZERO) < 0) {
            userFlow.setBalance(BigDecimal.ZERO);
        }
        userFlow.setBizCode(shopUserEditDTO.getBizEnum().getCode());
        userFlow.setRemark(shopUserEditDTO.getRemark());
        userFlow.setRelationId(shopUserEditDTO.getRelationId());
        userFlow.setRechargeId(shopUserEditDTO.getRechargeId());
        shopUserFlowService.save(userFlow);
        //次数
        if (shopUserEditDTO.getType() == 0 && shopUserEditDTO.getBizEnum().equals(ShopUserFlowBizEnum.ORDER_PAY)) {
            ShopUser shopUser = new ShopUser();
            shopUser.setId(userInfo.getId());
            shopUser.setConsumeCount(userInfo.getConsumeCount() + 1);
            shopUser.setConsumeAmount(userInfo.getConsumeAmount().add(shopUserEditDTO.getMoney()));
            updateById(shopUser);
        }
        return userFlow.getId();
    }

    @Override
    public ShopUserSummaryDTO getSummary(Long shopId, Integer isVip) {
        return mapper.selectUserSummary(shopId, isVip);
    }

    @Override
    public ShopUser getShopUserInfo(Long shopId, long userId) {
        ShopConfig shopConfig = shopConfigMapper.selectOneById(shopId);
        if (shopConfig != null && shopConfig.getIsEnableVipSync() == YesNoEnum.YES.value() && shopConfig.getMainId() != null) {
            shopId = shopConfig.getMainId();
        }
        ShopUser shopUser = queryChain().eq(ShopUser::getShopId, shopId).eq(ShopUser::getUserId, userId).one();
        if (shopUser == null) {
            shopUser = new ShopUser();
            UserInfo userInfo = userInfoService.getById(userId);
            BeanUtil.copyProperties(userInfo, shopUser);
            shopUser.setShopId(shopId);
            shopUser.setUserId(userId);
            shopUser.setId(null);
            save(shopUser);
        }
        return shopUser;
    }

    @Override
    @Transactional
    public Boolean add(Long shopId, ShopUserAddDTO shopUserAddDTO) {
        UserInfo userInfo = userInfoService.queryChain().eq(UserInfo::getPhone, shopUserAddDTO.getPhone()).one();
        if (userInfo == null) {
            userInfo = BeanUtil.copyProperties(shopUserAddDTO, UserInfo.class);
            userInfoService.save(userInfo);
        }

        ShopUser shopUser = BeanUtil.copyProperties(shopUserAddDTO, ShopUser.class);
        shopUser.setCode(generateCode(shopId));
        shopUser.setShopId(shopId);
        shopUser.setUserId(userInfo.getId());
        shopUser.setJoinTime(shopUser.getIsVip() != null && shopUser.getIsVip() == 1 ? DateUtil.date().toLocalDateTime() : null);
        return save(shopUser);
    }

    @Override
    public Page<ShopUserVipCardDTO> vipCard(long userInfoId) {
        return mapper.xmlPaginate("selectVipCard", PageUtil.buildPage(), new JoinQueryWrapper().eq(ShopUser::getUserId, userInfoId));
    }

    @Override
    public CzgResult<String> getCode(long userInfoId, long shopId) {
        ShopConfig shopConfig = shopConfigMapper.selectOneById(shopId);
        if (shopConfig != null && shopConfig.getIsEnableVipSync() == YesNoEnum.YES.value() && shopConfig.getMainId() != null) {
            shopId = shopConfig.getMainId();
        }
        ShopUser shopUser = queryChain().eq(ShopUser::getShopId, shopId).eq(ShopUser::getUserId, userInfoId).one();
        AssertUtil.isNull(shopUser, "会员信息不存在");
        if (shopUser.getIsVip().equals(0)) {
            return CzgResult.failure("加入会员后使用");
        }
        String dynamicCode = generatePaymentCode(String.valueOf(shopId), String.valueOf(userInfoId));
        redisService.set(RedisCst.SHOP_USER_DYNAMIC_CODE + shopUser.getShopId() + ":" + dynamicCode, shopUser.getId(), 180);
        return CzgResult.success(dynamicCode);
    }

    public String generatePaymentCode(String shopId, String platformNumber) {
        // 获取当前毫秒时间戳的后四位
        String date = String.format("%04d", System.currentTimeMillis() % 10000);

        // 获取店铺ID的最后2位数字
        String shopIdLastTwoDigits = String.format("%02d", Integer.parseInt(shopId) % 100);

        // 生成一个6位随机数
        String randomPart = RandomUtil.randomNumbers(6);

        // 拼接生成支付码：毫秒后的四位 + 平台号码 + 店铺ID的最后2位 + 随机数

        return date + platformNumber + shopIdLastTwoDigits + randomPart;
    }

    public String generateCode(long shopId) {
        String code = "shop_user_code_val%d".formatted(shopId);
        SysParams sysParam = sysParamsService.getOne(new QueryWrapper().eq(SysParams::getParamCode, code));

        if (sysParam == null) {
            SysParams sysParams = new SysParams()
                    .setParamValue("1")
                    .setParamType(1)
                    .setCreateTime(DateUtil.date().toLocalDateTime())
                    .setParamCode(code);
            sysParamsService.save(sysParams);
            return generateRandomCode(1);
        }

        long parseLong = Long.parseLong(sysParam.getParamValue());
        long l = ++parseLong;
        sysParam.setParamValue(String.valueOf(l));
        sysParamsService.updateById(sysParam);

        return generateRandomCode(l);
    }

    // 使用Hutool生成十六进制代码并随机填充字母
    private String generateRandomCode(long value) {
        // 生成十六进制代码，确保为10位
        String hexCode = String.format("%010X", value);

        // 计算需要补充的字母数量
        int missingLength = 10 - hexCode.length();
        StringBuilder codeBuilder = new StringBuilder(hexCode);

        for (int i = 0; i < missingLength; i++) {
            // 生成随机字母
            char randomChar = RandomUtil.randomChar("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
            codeBuilder.append(randomChar);
        }

        return codeBuilder.toString();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean join(Long shopId, Long userId, ShopUserAddDTO shopUserAddDTO) {
        // 当前用户信息
        UserInfo userInfo = userInfoService.getById(userId);

        ShopUser shopUser = getOne(new QueryWrapper().eq(ShopUser::getShopId, shopId).eq(ShopUser::getUserId, userInfo.getId()));
        if (shopUser == null) {
            shopUser = new ShopUser();
            shopUser.setUserId(userId);
            shopUser.setShopId(shopId);
        }

        // 查询系统添加的会员
        UserInfo oriInfo = userInfoService.getOne(new QueryWrapper().eq(UserInfo::getPhone, shopUserAddDTO.getPhone()));
        if (oriInfo != null && !oriInfo.getId().equals(userId)) {
            // 迁移订单
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setUserId(userId);
            orderInfoService.update(orderInfo, new QueryWrapper().eq(OrderInfo::getUserId, oriInfo.getId()));
            // 删除多余用户信息
            userInfoService.removeById(oriInfo.getId());
            BeanUtil.copyProperties(oriInfo, userInfo, "id", "alipayOpenId", "wechatOpenId");

            ShopUser oldUserInfo = getOne(new QueryWrapper().eq(ShopUser::getShopId, shopId).eq(ShopUser::getUserId, oriInfo.getId()));
            if (oldUserInfo != null) {
                removeById(oldUserInfo.getId());
                BeanUtil.copyProperties(oldUserInfo, shopUser, "id", "userId");
            }
        }

        BeanUtil.copyProperties(shopUserAddDTO, shopUser, "accountPoints", "amount");
        BeanUtil.copyProperties(shopUserAddDTO, userInfo);
        userInfoService.updateById(userInfo);

        if ((shopUser.getIsVip() == null || shopUser.getIsVip() != 1) && shopUser.getId() != null) {
            shopUser.setIsVip(1);
            if (StrUtil.isBlank(shopUser.getCode())) {
                shopUser.setCode(generateCode(shopId));
            }
            shopUser.setJoinTime(DateUtil.date().toLocalDateTime());
            shopUser.setUserId(null);
            shopUser.setShopId(null);
        }
        return saveOrUpdate(shopUser);
    }

    @Override
    public ShopUserDetailDTO getInfo(Long shopId, long userId) {
        ShopConfig shopConfig = shopConfigMapper.selectOneById(shopId);
        if (shopConfig != null && shopConfig.getIsEnableVipSync() == YesNoEnum.YES.value() && shopConfig.getMainId() != null) {
            shopId = shopConfig.getMainId();
        }
        ShopUser shopUser = getOne(new QueryWrapper().eq(ShopUser::getShopId, shopId).eq(ShopUser::getUserId, userId));
        UserInfo userInfo = userInfoService.getById(userId);
        if (userInfo == null) {
            throw new ApiNotPrintException("用户信息不存在");
        }

        long couponNum = 0;
        if (shopUser == null) {
            shopUser = BeanUtil.copyProperties(userInfo, ShopUser.class);
            shopUser.setShopId(shopId);
            shopUser.setId(null);
            shopUser.setUserId(userId);
            save(shopUser);
            shopUser = getById(shopUser.getId());
        } else {
            couponNum = shopActivateCouponRecordService.count(new QueryWrapper().eq(ShopActivateCouponRecord::getShopUserId, shopUser.getId()).eq(ShopActivateCouponRecord::getStatus, 0));
        }
        ShopUserDetailDTO shopUserDetailDTO = BeanUtil.copyProperties(shopUser, ShopUserDetailDTO.class);
        shopUserDetailDTO.setCouponNum(couponNum);

        ShopInfo shopInfo = shopInfoMapper.selectOneById(shopId);
        if (shopInfo != null) {
            shopUserDetailDTO.setShopName(shopInfo.getShopName());
            shopUserDetailDTO.setShopId(shopInfo.getId());
            shopUserDetailDTO.setShopInfo(shopInfo);
            List<ShopExtend> shopExtends = shopExtendService.list(new QueryWrapper().eq(ShopExtend::getShopId, shopInfo.getId()));
            shopUserDetailDTO.setShopExtendList(shopExtends);
        }

        shopUserDetailDTO.setFreeDineConfig(freeDineConfigService.getConfig(shopId));
        shopUserDetailDTO.setPayPwd(userInfo.getPayPwd());
        return shopUserDetailDTO;
    }

    @Override
    public ShopUser getDetail(Integer id, Integer userId) {
        ShopUser shopUser = getOne(new QueryWrapper().eq(ShopUser::getShopId, StpKit.USER.getHeadShopId()).eq(ShopUser::getId, id).eq(ShopUser::getUserId, userId));
        long count = shopActivateCouponRecordService.count(new QueryWrapper().eq(ShopActivateCouponRecord::getShopUserId, shopUser.getId()).eq(ShopActivateCouponRecord::getStatus, 0));
        ShopUserDTO shopUserDTO = BeanUtil.copyProperties(shopUser, ShopUserDTO.class);
        shopUserDTO.setCouponNum(count);
        shopUserDTO.setOrderNumber(orderInfoService.count(new QueryWrapper().eq(OrderInfo::getUserId, userId).eq(OrderInfo::getShopId, StpKit.USER.getShopId(0L)).eq(OrderInfo::getStatus, "done")));
        return shopUserDTO;
    }
}
