package com.bailuntec.job;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.bailuntec.domain.constant.CommonConstant;
import com.bailuntec.domain.constant.Constant;
import com.bailuntec.domain.entity.DcBaseStock;
import com.bailuntec.domain.entity.JobPointLog;
import com.bailuntec.domain.enumerate.PlatformType;
import com.bailuntec.domain.example.DcBaseWarehouseExample;
import com.bailuntec.domain.pojo.StockInfoData;
import com.bailuntec.domain.pojo.StockInfoPOJO;
import com.bailuntec.mapper.DcBaseStockMapper;
import com.bailuntec.mapper.DcBaseWarehouseMapper;
import com.bailuntec.support.PointJob;
import com.bailuntec.utils.OkHttpUtil;
import com.bailuntec.utils.PropertiesUtil;
import com.bailuntec.utils.SessionUtil;
import com.dangdang.ddframe.job.api.ShardingContext;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Slf4j
public class StockSyncJob extends PointJob {
    private static final String secret = "SCGAPPSECRET5D7C969233948CE053FC4A50477C3FC02A4118A7";
    private static final String appKey = "BAILUN9BB992ED";
    private OkHttpClient client = OkHttpUtil.getInstance();
    private PropertiesUtil constPropertiesUtil = PropertiesUtil.getInstance("const");

    @Override
    public void executeJob(ShardingContext shardingContext, JobPointLog jobPointLog) {
        HashMap<String, String> map = new HashMap<>(8);
        map.put("appKey", appKey);
        map.put("beginTime", DateTimeFormatter.ofPattern(CommonConstant.TIME_FORMAT).format(jobPointLog.getStartTime().minusDays(1L)));
        map.put("pageSize", jobPointLog.getPageSize().toString());
        int totalPage = 0;
        try {
            DcBaseWarehouseMapper baseWarehouseMapper = SessionUtil.getSession().getMapper(DcBaseWarehouseMapper.class);
            int countWarehouse = (int) baseWarehouseMapper.countByExample(DcBaseWarehouseExample.newAndCreateCriteria().andWarehouseExtendNameNotEqualTo("").andSystemFlagNotEqualTo(PlatformType.FBA.value()).example());
            if (countWarehouse % Constant.STOCKS_LIMIT > 0) {
                totalPage = countWarehouse / Constant.STOCKS_LIMIT + 1;
            } else {
                totalPage = countWarehouse / Constant.STOCKS_LIMIT;
            }
        } catch (Exception e) {
            throw new RuntimeException("Mybatis操作DB失败", e);
        } finally {
            SessionUtil.closeSession();
        }
        for (int i = 0; i < totalPage; i++) {
            String warehouseStr = null;
            try {
                DcBaseWarehouseMapper baseWarehouseMapper = SessionUtil.getSession().getMapper(DcBaseWarehouseMapper.class);
                warehouseStr = baseWarehouseMapper.getWarehouseCodeStr(i * Constant.STOCKS_LIMIT, Constant.STOCKS_LIMIT);
            } catch (Exception e) {
                throw new RuntimeException("Mybatis操作DB失败", e);
            } finally {
                SessionUtil.closeSession();
            }
            handleRealtimeInventory(warehouseStr, jobPointLog, map);
        }
        jobPointLog.setStartTime(jobPointLog.getEndTime());
        jobPointLog.setEndTime(jobPointLog.getEndTime().plusDays(jobPointLog.getIntervalTime()).isAfter(LocalDateTime.now()) ? LocalDateTime.now() : jobPointLog.getEndTime().plusDays(jobPointLog.getIntervalTime()));
    }

    public void handleRealtimeInventory(String warehouseStr, JobPointLog jobPointLog, HashMap<String, String> map) {
        if (StringUtils.isNotBlank(warehouseStr)) {
            //查出仓库, 轮询
            for (int j = 0; j < 32; j++) {
                Integer code = null;
                Integer pageNo = 1;
                List<StockInfoPOJO> list = null;
                map.put("dbId", String.valueOf(j));
                Response response = null;
                do {
                    map.put("LocalDateTime", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()));
                    map.put("pageNo", pageNo.toString());
                    map.put("stockCodes", warehouseStr);
                    map.put("sign", createSign(map));
                    String stockStr = null;
                    try {
                        Request request = new Request.Builder()
                                .url(OkHttpUtil.attachHttpGetParams(constPropertiesUtil.getPropertyAsString("IIS_URL"), map))
                                .get()
                                .build();
                        response = client.newCall(request).execute();
                        stockStr = response.body().string();
                    } catch (Exception e) {
                        throw new RuntimeException("调用环球IIS库存数据接口失败,响应404, 参数" + map);
                    } finally {
                        if (response != null) {
                            response.close();
                        }
                    }
                    if (StringUtils.isNotBlank(stockStr)) {
                        JSONObject jsonObject1 = JSON.parseObject(stockStr);
                        code = jsonObject1.getIntValue("code");
                        if (code != null && code == 0) {
                            StockInfoData stockInfoData = jsonObject1.getObject("data", new TypeReference<StockInfoData>() {
                            });
                            list = stockInfoData.getList();
                            if (list != null && list.size() > 0) {
                                for (StockInfoPOJO stockInfoPOJO : list) {
                                    DcBaseStock dcBaseStock = new DcBaseStock();
                                    try {
                                        BeanUtils.copyProperties(dcBaseStock, stockInfoPOJO);
                                    } catch (IllegalAccessException e) {
                                        throw new RuntimeException("BeanUtils.copyProperties失败", e);
                                    } catch (InvocationTargetException e) {
                                        throw new RuntimeException("BeanUtils.copyProperties失败", e);
                                    }
                                    if (stockInfoPOJO.getCreatedTime() != null) {
                                        dcBaseStock.setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(stockInfoPOJO.getCreatedTime().longValue()), ZoneId.systemDefault()));
                                    }
                                    if (stockInfoPOJO.getUpdatedTime() != null) {
                                        dcBaseStock.setUpdateTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(stockInfoPOJO.getUpdatedTime().longValue()), ZoneId.systemDefault()));
                                    }
                                    try {
                                        DcBaseStockMapper baseStockMapper = SessionUtil.getSession().getMapper(DcBaseStockMapper.class);
                                        baseStockMapper.upsertSelective(dcBaseStock);
                                        SessionUtil.getSession().commit();
                                    } catch (Exception e) {
                                        e.printStackTrace();
                                        throw new RuntimeException("Mybatis操作DB失败", e);
                                    } finally {
                                        SessionUtil.closeSession();
                                    }
                                }
                            }
                        }
                    }
                    map.remove("sign");
                    if (list != null && list.size() == jobPointLog.getPageSize().intValue()) {
                        pageNo++;
                    }
                } while (code != null && code == 0 && list != null && list.size() == jobPointLog.getPageSize().intValue());
            }
        }
    }

    /**
     * @Description :根据签名算法得出签名---参数按照参数名ASCII码从小到大排序（字典序）
     **/
    public String createSign(Map<String, String> parameters) {
        StringBuffer keyS = new StringBuffer();
        List<Map.Entry<String, String>> infoIds = new ArrayList<>(parameters.entrySet());
        // 对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序）
        Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() {
            public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
                return (o1.getKey()).compareTo(o2.getKey());
            }
        });
        // 构造签名键值对的格式
        for (Map.Entry<String, String> item : infoIds) {
            if (item.getKey() != null || item.getKey() != "") {
                String key = item.getKey();
                String val = item.getValue();
                if (!(val == "" || val == null)) {
                    keyS.append(key + val);
                }
            }
        }
        String md5Str = getMD5Str(keyS.toString() + secret);
        return md5Str;

    }

    public String getMD5Str(String str) {
        try {
            // 生成一个MD5加密计算摘要
            MessageDigest md = MessageDigest.getInstance("MD5");
            // 计算md5函数
            md.update(str.getBytes());
            // digest()最后确定返回md5 hash值，返回值为8为字符串。因为md5 hash值是16位的hex值，实际上就是8位的字符
            // BigInteger函数则将8位的字符串转换成16位hex值，用字符串来表示；得到字符串形式的hash值
            return new BigInteger(1, md.digest()).toString(16);
        } catch (Exception e) {
            throw new RuntimeException("MD5加密出现错误，" + e.toString());
        }
    }
}
