package com.xy.job;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xy.collections.list.JArrayList;
import com.xy.collections.map.JHashMap;
import com.xy.collections.map.JMap;
import com.xy.device.EnumDeviceCharging;
import com.xy.dto.DeviceChangeStatusDTO;
import com.xy.dto.MercArrearageConfigDto;
import com.xy.dto.MercMsgInfoDto;
import com.xy.dto.be.MercDto;
import com.xy.entity.DeviceCharging;
import com.xy.entity.DeviceInfo;
import com.xy.enums.MsgConfigId;
import com.xy.mapper.DeviceChargingMapper;
import com.xy.service.AlipayDeviceService;
import com.xy.service.DeviceInfoServiceImpl;
import com.xy.service.MercArrearageConfigService;
import com.xy.service.MercMsgInfoService;
import com.xy.service.be.MercFeignService;
import com.xy.sys.EnumMercCostMsgConfig;
import com.xy.utils.*;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 设备管理费job
 */
@Slf4j
@Component
@AllArgsConstructor
public class DeviceChargingJob {

    private DeviceChargingMapper deviceChargingMapper;

    private MercMsgInfoService mercMsgInfoService;

    private DeviceInfoServiceImpl deviceInfoService;

    private MercArrearageConfigService mercArrearageConfigService;

    private MercFeignService mercFeignService;

    private AlipayDeviceService alipayDeviceService;

    /**
     * 管理费设备停机
     *
     * @return
     */
    @XxlJob("deviceChargingHalt")
    public ReturnT<String> deviceChargingHalt() {
        LocalDateTime now = LocalDateTime.now();
        int day = SysDictUtils.getValue(EnumDeviceCharging.Code.CODE.getCode(), EnumDeviceCharging.ARREARAGE_DAY.getCode(), Integer.class);
        String timeout = DataTime.getStringAround(0, 0, (~(day - 1)), 0, 0, 0, DataTime.toString(now));
        LambdaQueryWrapper<DeviceCharging> lambdaQueryWrapper = new LambdaQueryWrapper<DeviceCharging>()
                .select(DeviceCharging::getDeviceId, DeviceCharging::getTimeout)
                .le(DeviceCharging::getTimeout, timeout);
        //查询白名单
        MercArrearageConfigDto.SelectList selectList = new MercArrearageConfigDto.SelectList();
        selectList.setType(1);
        List<MercArrearageConfigDto.Vo> data = mercArrearageConfigService.list(selectList).getData();
        JMap<Long, MercArrearageConfigDto.Vo> mercArrearageConfigJMaps = new JArrayList<>(data).toMap(MercArrearageConfigDto.Vo::getMercId).cover();
        //递归处理
        RecursionUtils.recursion(current -> {
            //查询已过期设备管理费
            IPage<DeviceCharging> iPage = deviceChargingMapper.selectPage(Page.of(current, 200), lambdaQueryWrapper);
            List<DeviceCharging> records = iPage.getRecords();
            if (!Emptys.check(records)) {
                return false;
            }
            JMap<Long, DeviceCharging> deviceChargingsJMaps = new JArrayList<>(records).toMap(DeviceCharging::getDeviceId).cover();
            //查询未冻结设备
            LambdaQueryWrapper<DeviceInfo> deviceInfoLambdaQueryWrapper = new LambdaQueryWrapper<DeviceInfo>()
                    .select(DeviceInfo::getDeviceId, DeviceInfo::getMercId)
                    .in(DeviceInfo::getDeviceId, deviceChargingsJMaps.getKeys())
                    .eq(DeviceInfo::getActiveState, 1)
                    .eq(DeviceInfo::getFreezeStatus, 1);
            List<DeviceInfo> deviceInfos = deviceInfoService.list(deviceInfoLambdaQueryWrapper);
            //冻结设备
            if (Emptys.check(deviceInfos)) {
                List<DeviceInfo> updateDeviceInfos = new ArrayList<>();
                deviceInfos.forEach(deviceInfo -> {
                    //验证白名单
                    MercArrearageConfigDto.Vo mercArrearageConfig = mercArrearageConfigJMaps.get(deviceInfo.getMercId());
                    if (Emptys.check(mercArrearageConfig)) {
                        DeviceCharging deviceCharging = deviceChargingsJMaps.get(deviceInfo.getDeviceId());
                        String newTime = DataTime.getStringAround(0, 0, (-mercArrearageConfig.getArrearageDay()), 0, 0, 0, DataTime.toString(now));
                        //过期时间 > (当前时间 - 配置天)
                        if (DataTime.stringContrast(DataTime.toString(deviceCharging.getTimeout()), newTime) > 0) {
                            return;
                        }
                    }
                    updateDeviceInfos.add(deviceInfo
                            .setDeviceId(deviceInfo.getDeviceId())
                            .setFreezeStatus(2)
                            .setUpdateTime(now)
                    );
                    //支付宝刷脸柜停机
                    if (deviceInfo.getDeviceType() == 5) {
                        alipayDeviceService.changeStatus(new DeviceChangeStatusDTO()
                                .setTerminalId(String.valueOf(deviceInfo.getDeviceId()))
                                .setOperatorId("1")
                                .setStatus(2)
                        );
                    }
                });
                if (Emptys.check(updateDeviceInfos)) {
                    deviceInfoService.updateBatchById(updateDeviceInfos);
                }
            }
            return true;
        });
        return ReturnT.SUCCESS;
    }

    /**
     * 设备管理费过期消息
     *
     * @return
     */
    @XxlJob("deviceChargingTimeout")
    public ReturnT<String> deviceChargingTimeout() {
        String now = DataTime.getSring();
        String tel = SysDictUtils.getValue(EnumMercCostMsgConfig.Code.CODE.getCode(), EnumMercCostMsgConfig.CUSTOM_TEL.getCode(), String.class);
        String mmiTime = DataTime.getStringAround(0, -1, 0, 0, 0, 0, now);
        //数据逻辑
        FunctionUtils.ParamsResult<Tuple.Tuple4<Integer, JMap<String, Object>, JMap<String, Object>, Integer>, Boolean> datas = tuple -> {
            Integer current = tuple.getV1();
            JMap<String, Object> params = tuple.getV2();
            JMap<String, Object> msg = tuple.getV3();
            Integer workType = tuple.getV4();
            //查询数据
            IPage<Long> longIPage = deviceChargingMapper.deviceChargingTimeout(Page.of(current, 100), params);
            List<Long> mercIds = longIPage.getRecords();
            if (!Emptys.check(mercIds)) {
                return false;
            }

            List<MercDto.Vo> mercList = R.feignCheckData(mercFeignService.listMerc(new MercDto.ListDTO().setIds(mercIds)));
            Map<Long, MercDto.Vo> mercMap = mercList.stream().collect(Collectors.toMap(MercDto.Vo::getId, m -> m));
            List<Long> cmMercIds = new ArrayList<>();
            List<Long> mxrMercIds = new ArrayList<>();
            //遍历mercMap 区分喵星人、创米商户
            for (Map.Entry<Long, MercDto.Vo> entry : mercMap.entrySet()) {
                Long mercId = entry.getKey();
                String mercCode = entry.getValue().getMercCode();
                if (MercAuthUtils.sendMsgToCM(mercCode)) {
                    cmMercIds.add(mercId);
                } else {
                    mxrMercIds.add(mercId);
                }
            }
            //发送消息
            if (CollUtil.isNotEmpty(mxrMercIds)) {
                MsgUtils.sendMsg(MsgConfigId.FEE_NOTIFY.getId(), mercIds)
                        .official(userInfo -> new MsgUtils.MsgInfo(userInfo.getMpOpenid(), msg))
                        .mxr(userInfo -> new MsgUtils.MsgInfo(String.valueOf(userInfo.getAuthorizeUserId()), msg))
                        .builder();
            }
            //创米商户
            if (CollUtil.isNotEmpty(cmMercIds)) {
                MsgUtils.sendMsg(MsgConfigId.CM_FEE_NOTIFY.getId(), mercIds)
                        .official(userInfo -> new MsgUtils.MsgInfo(userInfo.getMpOpenid(), msg))
                        .mxr(userInfo -> new MsgUtils.MsgInfo(String.valueOf(userInfo.getAuthorizeUserId()), msg))
                        .builder();
            }

            //写入记录
            mercMsgInfoService.save(new MercMsgInfoDto.Save()
                    .setMercId(mercIds)
                    .setType(1)
                    .setWorkType(workType)
            );
            return true;
        };
        //即将过期
        FunctionUtils.NoParamsNoResult timeout1 = () -> {
            int day = SysDictUtils.getValue(EnumDeviceCharging.Code.CODE.getCode(), EnumDeviceCharging.N_200.getCode(), Integer.class);
            String end = DataTime.getStringAround(0, 0, day, 0, 0, 0, now);
            JMap<String, Object> map = new JHashMap<String, Object>()
                    .set("mmiTime", mmiTime)
                    .set("workType", 1)
                    .set("begin", now)
                    .set("end", end);
            JMap<String, Object> sendParams = new JHashMap<String, Object>()
                    .set("content", String.format("尊敬的客户，您有%s即将到期，为避免设备停机，请及时续费，客服电话%s", "设备管理费", tel));
            RecursionUtils.recursion(current -> datas.run(new Tuple.Tuple4<>(current, map, sendParams, 1)));
        };
        //欠费
        FunctionUtils.NoParamsNoResult timeout2 = () -> {
            int day = SysDictUtils.getValue(EnumDeviceCharging.Code.CODE.getCode(), EnumDeviceCharging.ARREARAGE_DAY.getCode(), Integer.class);
            String time1 = DataTime.getStringAround(0, 0, day, 0, 0, 0, now);
            JMap<String, Object> map = new JHashMap<String, Object>()
                    .set("mmiTime", mmiTime)
                    .set("workType", 2)
                    .set("end", now);
            JMap<String, Object> sendParams = new JHashMap<String, Object>()
                    .set("content", String.format("尊敬的客户，截止%s您的%s已欠费，如您在%s前未完成续费，您的设备将停止交易，客服电话%s", now, "设备管理费", time1, tel));
            RecursionUtils.recursion(current -> datas.run(new Tuple.Tuple4<>(current, map, sendParams, 2)));
        };
        timeout1.run();
        timeout2.run();
        return ReturnT.SUCCESS;
    }

}
