import com.sdtool.business.dao.MallDao
import com.sdtool.common.api.NoSqlKeysService
import com.sdtool.common.datas.RedisKeys
import com.sdtool.common.entity.mall.MallUser
import com.sdtool.common.entity.mall.MallUserLevel
import com.sdtool.common.tool.ERPUtils
import com.dySweetFishPlugin.redis.RedisService
import com.sweetfish.convert.json.JsonConvert
import org.apache.commons.lang3.StringUtils
import org.apache.logging.log4j.Logger

import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.stream.Collectors

static def createRunnable(RedisService redisService, NoSqlKeysService keysService, MallDao mallDao, JsonConvert jsonConvert, Logger logger, String dataSourceId, long supplierCode) {
    return {
        logger.info("清理用户级别开始...")

        Set<String> processMembers = new HashSet<>()

        List<MallUser> processUserList = new ArrayList<>()

        //下面的代码是伪代码，需要pom升级下框架

        //整体逻辑如下：
        //1、通过hscan获取到用户信息，
        //2、判断用户的过期时间，过期了降级，差一个月的发信息，
        //这里存在几个问题，
        //1、当管理员或其它有权限的操作员手动调整了用户级别，是否需要重新计算过期时间，如果重新计算则理论上不符合事实逻辑，则手动调整级别不重新计算到期时间
        //2、既然不重新计算过期时间，那么最好提供一个手动调整过期时间的功能
        //3、如果管理员手动调整了用户级别，那么在系统自动降级时，是否还需要自动调整为降级设置的级别？如果自动调整，那么手动调整的级别该如何处理？
        //4、是否存在降级链，比如 豪华会员->超级会员->普通会员，其中前面两个都有到期时间，那么自动降级后，比如从豪华会员，降级成超级会员，是否根据超级会员的到期天数重新计算时间，（理论上需要重新计算）
        //5、如果4存在，那么2中的手动调整到期时间又当如何处理？
        //6、提醒机制，是快到期每天提醒一次，用什么提示，还是有什么要求？

        //hscan有可能会得到重复数据，特别是在游标切换的地方
        redisService.hscan(keysService.getRedisKey(RedisKeys.KEY_ERP_MALL_User, supplierCode), 500, { Map<String, String> userMap ->
            LocalDateTime now = LocalDateTime.now()
            userMap.each { user ->
                if (!processMembers.contains(user.key)) {
                    processMembers.add(user.key)

                    MallUser mallUser = jsonConvert.convertFromO(MallUser.class, user.value)

                    if ((mallUser.idLevel > 0L) && (mallUser.levelExpireDateLong > 0L)) {
                        LocalDateTime userExpireTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(mallUser.levelExpireDateLong), ZoneId.systemDefault())
                        if (userExpireTime.isBefore(now)) {
                            //会员到期，需要做降级，降级操作一定要重新计算到期时间，如果新级别没有到期天数，则置为0即可
                            processUserList.add(mallUser)
                        } else if (userExpireTime.isBefore(now.plusMonths(1))) {
                            //如果差一个月到期，则发送消息，由于此脚本是在凌晨执行的，所以发送消息一定是放在消息队列中，由专门给客户发消息的服务搞到白天执行
                            //发消息的实现，最好是把数据放到redis中，然后定时的获取数据发送消息
                            //暂时没有发送消息的渠道，先不发了
                        }
                    }
                }
            }
        })

        if (!processUserList.isEmpty()) {
            List<MallUser> actUserList = new ArrayList<>()

            long[] idLevels = processUserList.findAll { it.idLevel > 0L }.collect { it.idLevel }.unique().toArray() as long[]

            List<MallUserLevel> userLevelList = new ArrayList<>()
            if (idLevels.length > 0) {
                List<String> docList = redisService.hmget(keysService.getRedisKey(RedisKeys.KEY_ERP_MALL_USER_LEVEL, supplierCode), ERPUtils.longArrayToStrArray(idLevels))
                docList = docList.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList())
                docList.forEach(value -> userLevelList.add(jsonConvert.convertFrom(MallUserLevel, value)))
            }

            processUserList.each { mallUser ->
                MallUserLevel srcLevel = userLevelList.find { it.id == mallUser.idLevel }
                if (srcLevel != null) {
                    mallUser.idLevel = srcLevel.idDowngradeLevel
                    mallUser.levelExpireDateLong = 0L
                    mallUser.levelExpireDate = null

                    actUserList << mallUser
                }
            }

            if (!actUserList.isEmpty()) {
                int iData = mallDao.setMallUserIdLevel(processUserList, dataSourceId, supplierCode)
                if (iData > 0) {
                    Map<String, String> redisMap = processUserList.collectEntries { [String.valueOf(it.id), jsonConvert.convertTo(it)] }
                    redisService.hmset(keysService.getRedisKey(RedisKeys.KEY_ERP_MALL_User, supplierCode), redisMap)
                }
            }
        }


        logger.info("清理用户级别结束...")
    } as Runnable
}

//groovy最后一个表达式的值为返回
createRunnable(redisService, keysService, mallDao, jsonConvert, logger, dataSourceId, supplierCode)
