package com.ningdatech.carapi.irs.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.cache.redis.RedisOps;
import com.ningdatech.carapi.common.contants.IrsConst;
import com.ningdatech.carapi.driver.entity.DriverInfo;
import com.ningdatech.carapi.driver.service.IDriverInfoService;
import com.ningdatech.carapi.irs.entity.DriversLicenseRaw;
import com.ningdatech.carapi.irs.model.dto.irs.DriverLicenseDTO;
import com.ningdatech.carapi.irs.model.dto.irs.ResponseDataDTO;
import com.ningdatech.carapi.irs.service.AbstractLicenseGetByIrsService;
import com.ningdatech.carapi.irs.service.IDriversLicenseRawService;
import com.ningdatech.carapi.irs.service.PullLicenseByIrsService;
import com.ningdatech.carapi.irs.service.RefreshKeyService;
import com.ningdatech.carapi.irs.utils.Md5Utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * DriverLicensePullServiceImpl
 * </p>
 *
 * @author WendyYang
 * @since 2023/5/16
 **/
@Slf4j
@Service("driverLicensePullByIrsService")
public class PullDriverLicenseByIrsServiceImpl extends AbstractLicenseGetByIrsService implements PullLicenseByIrsService {

    public PullDriverLicenseByIrsServiceImpl(IDriverInfoService driverInfoService,
                                             RestTemplate restTemplate,
                                             RefreshKeyService refreshKeyService,
                                             RedisOps redisOps,
                                             IDriversLicenseRawService driversLicenseRawService) {
        super(driverInfoService, restTemplate, refreshKeyService, redisOps, driversLicenseRawService);
    }

    @Override
    public boolean runningStatus() {
        String statusKey = RK_DRIVER_LICENSE + StrPool.COLON + "STATUS";
        return Boolean.TRUE.equals(redisOps.exists(statusKey));
    }

    @Override
    public long getLeftCount() {
        String dataKey = RK_DRIVER_LICENSE + StrPool.COLON + "IDCARD";
        return ObjectUtil.defaultIfNull(redisOps.lLen(dataKey), 0L);
    }

    /**
     * 获取驾驶证信息
     *
     * @param cardId 身份证号
     * @return irs接口返回值
     */
    @Override
    public String getLicenseDetail(String cardId) {
        MultiValueMap<String, Object> reqParam = new LinkedMultiValueMap<>();
        // 附加信息
        reqParam.add("additional", "{\"powerMatters\":\"许可-0000-00\",\"subPowerMatters\":\"许可-0000-0101\",\"accesscardId\":\"33071918111111784523\",\"materialName\":\"社会团体变更登记申请表\",\"sponsorName\":\"阿里巴巴（中国）有限公司\",\"sponsorCode\":\"91330100799655058B\",\"projectId\":\"330000261711151100004\"}");
        reqParam.add("appKey", APP_KEY);
        // 刷新密钥
        String requestSecret = refreshKeyService.getRequestSecret(APP_KEY, APP_SECRET);
        // 请求签名
        Long requestTime = System.currentTimeMillis();
        String sign = Md5Utils.hash(APP_KEY + requestSecret + requestTime);
        // irs驾驶证查询接口
        reqParam.set("requestTime", requestTime);
        reqParam.set("sign", sign);
        reqParam.set("cardId", cardId);

        String res;
        try {
            log.info("请求参数：{}", reqParam);
            res = restTemplate.postForObject(IrsConst.DRIVER_LICENSE_URL, reqParam, String.class);
            log.info("驾驶证查询：{}", res);
        } catch (Exception e) {
            log.error("驾驶证查询：", e);
            res = null;
        }
        return res;
    }

    @Override
    public void pullLicense() {
        String statusKey = RK_DRIVER_LICENSE + StrPool.COLON + "STATUS";
        try {
            if (Boolean.FALSE.equals(redisOps.setNx(statusKey, "RUNNING"))) {
                return;
            }
            pullLicenseDetail();
        } finally {
            redisOps.del(statusKey);
        }
    }

    @Override
    public void pullLicenseDetail() {
        String dataKey = RK_DRIVER_LICENSE + StrPool.COLON + "IDCARDS";
        List<String> currIdcards = redisOps.lPop(dataKey);
        if (CollUtil.isEmpty(currIdcards)) {
            LambdaQueryWrapper<DriverInfo> query = Wrappers.lambdaQuery(DriverInfo.class)
                    .select(DriverInfo::getIdCard);
            List<DriverInfo> driverInfos = driverInfoService.list(query);
            Set<String> idCards = driverInfos.stream()
                    .map(DriverInfo::getIdCard)
                    .filter(IdcardUtil::isValidCard)
                    .collect(Collectors.toSet());
            if (idCards.isEmpty()) {
                return;
            }
            List<List<String>> parts = new ArrayList<>(ListUtil.partition(new ArrayList<>(idCards), LIMIT_BY_DAY));
            currIdcards = parts.remove(0);
            if (!parts.isEmpty()) {
                redisOps.lPush(dataKey, parts.toArray());
            }
        }
        List<String> failedIdcards = currIdcards.stream().filter(idcard -> {
            try {
                String resData = getLicenseDetail(idcard);
                if (StrUtil.isBlank(resData)) {
                    return true;
                }
                ResponseDataDTO<DriverLicenseDTO> response = JSON.parseObject(resData,
                        new TypeReference<ResponseDataDTO<DriverLicenseDTO>>() {
                        });
                if (response.succeed()) {
                    List<DriverLicenseDTO> list = response.getDatas();
                    if (CollUtil.isNotEmpty(list)) {
                        DriverLicenseDTO dl = list.get(0);
                        DriversLicenseRaw raw = new DriversLicenseRaw();
                        raw.setIdcard(idcard);
                        raw.setDriverLicenseDetail(JSONUtil.toJsonStr(dl));
                        LambdaQueryWrapper<DriversLicenseRaw> query = Wrappers
                                .lambdaQuery(DriversLicenseRaw.class)
                                .eq(DriversLicenseRaw::getIdcard, idcard);
                        driversLicenseRawService.saveOrUpdate(raw, query);
                        return false;
                    }
                }
                return true;
            } catch (Exception e) {
                log.error("获取驾驶证信息异常：", e);
                return true;
            }
        }).collect(Collectors.toList());
        if (!failedIdcards.isEmpty()) {
            redisOps.lPush(dataKey, failedIdcards.toArray());
        }
    }

    @Override
    public void initPullLicenseTask() {
        long leftCnt = getLeftCount();
        boolean runningStatus = runningStatus();
        if (runningStatus || leftCnt > 0) {
            startPullLicenseTask(INIT_DELAY_MINUTES);
        }
    }

    @Override
    public void startPullLicenseTask(int delayMinutes) {
        startLicensePullTask(RK_DRIVER_LICENSE, this, delayMinutes);
    }

}
