package com.younike.system.task;

import com.younike.common.network.HttpClientUtils;
import com.younike.common.utils.StringUtils;
import com.younike.common.utils.id.IDGenerate;
import com.younike.hlpay.dto.RSA;
import com.younike.hlpay.dto.SettleResponseVo;
import com.younike.hlpay.dto.SettleVo;
import com.younike.hlpay.util.BeanUtils;
import com.younike.hlpay.util.JSONUtil;
import com.younike.system.domain.MerchantSettleInfo;
import com.younike.system.domain.MerchantSettleRecord;
import com.younike.system.domain.Order;
import com.younike.system.service.IMerchantSettleInfoService;
import com.younike.system.service.IMerchantSettleRecordService;
import com.younike.system.service.IOrderService;
import lombok.extern.log4j.Log4j2;
import org.apache.http.client.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import static com.younike.hlpay.constant.HeliPayContants.SETTLE_PRIVATE_KEY;
import static com.younike.hlpay.constant.HeliPayContants.SETTLE_REQUEST_URL;

/**
 * 结算任务
 *
 * @author chenpengfei
 */
@Component("settleTask")
@Log4j2
public class SettleTask {

    @Autowired
    private IOrderService orderService;

    @Autowired
    private IMerchantSettleInfoService merchantSettleInfoService;

    private IMerchantSettleRecordService merchantSettleRecordService;

    public static final BigDecimal MIN_SETTLE_AMOUNT = new BigDecimal(5);


    public void settle(){
        LocalDate today = LocalDate.now();
        Date settleDate = Date.from(today.minusDays(2).atStartOfDay(ZoneId.systemDefault()).toInstant());
        log.info("合利宝结算截止时间 " + DateUtils.formatDate(settleDate, "yyyy-MM-dd HH:mm:ss"));
        // 查询所有「可支付」「未结算」订单，以商家进行分组
        Map<Long, List<Order>> preSettledOrders = orderService.selectPreSettleOrders(settleDate);
        if (preSettledOrders != null && preSettledOrders.size() > 0) {
            Set<Long> merchantIds = preSettledOrders.keySet();
            // 查询店铺合利宝信息
            List<MerchantSettleInfo> shopHlbs = merchantSettleInfoService.listByIds(merchantIds);
            if (shopHlbs == null || shopHlbs.size() == 0 ) {
                log.error("合利宝结算错误 -- 待结算商家合利宝信息异常（缺失）" + merchantIds.toString());
                return;
            }
            Map<Long, String> hlbMap = shopHlbs.stream().collect(Collectors.toMap(MerchantSettleInfo::getMerchantId, MerchantSettleInfo::getMerchantNo));
            if (shopHlbs.size() != merchantIds.size()) {
                log.error("合利宝结算错误 -- 存在商家合利宝信息不全 " + merchantIds.toString());
            }
            List<MerchantSettleRecord> merchantSettleRecords = new ArrayList<>();
            List<Long> orderList =  new ArrayList<>();
            for (Map.Entry<Long, List<Order>> entry : preSettledOrders.entrySet()) {
                // 遍历各商家待支付订单，合利宝结算
                BigDecimal settleAmount = entry.getValue().stream().map(Order::getShopAmount).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
                List<Long> orders = entry.getValue().stream().map(Order::getOrderId).collect(Collectors.toList());
                // 合利宝商家编码
                String customerNum = hlbMap.get(entry.getKey());
                if (StringUtils.isEmpty(customerNum)) {
                    log.error("合利宝结算错误 -- 商家合利宝信息为空 " + entry.getKey());
                    continue;
                }
                if (MIN_SETTLE_AMOUNT.compareTo(settleAmount) > 0) {
                    log.error("合利宝结算错误 -- 商家结算金额小于最小结算金额 " + settleAmount.toString());
                    continue;
                }
                // 结算记录ID
                String settleId = IDGenerate.nextId();
                // 合利宝支付对象
                SettleVo settleVo = new SettleVo();
                settleVo.setP1_bizType("MerchantSettlement");
                settleVo.setP2_orderId(settleId);
                settleVo.setP3_customerNumber(customerNum);
                settleVo.setP4_amount(settleAmount.toString());
                settleVo.setP5_summary("商家自动结算");
                settleVo.setSignType("RSA");

                String P1_bizType = "MerchantSettlement";
                String P2_orderId = settleId;
                String P3_customerNumber = customerNum;
                String P4_amount = settleAmount.toString();
                String P5_summary = "商家自动结算";
                String signType = "RSA";
                String split = "&";
                StringBuffer sb = new StringBuffer();
                sb.append(split).append(P1_bizType).append(split).append(P2_orderId).append(split)
                        .append(P3_customerNumber).append(split).append(P4_amount).append(split).append(P5_summary)
                        .append(split).append(signType);

                Map<String, Object> map = null;
                try {
                    map = BeanUtils.convertBean(settleVo, new LinkedHashMap());
                    log.info("签名原文串：" + sb.toString());
                    String sign = RSA.sign(sb.toString(), RSA.getPrivateKey(SETTLE_PRIVATE_KEY));
                    log.info("签名串：" + sign);
                    map.put("sign", sign);
                    log.info("发送参数：" + map);
                    String response = HttpClientUtils.sendFormRequest(SETTLE_REQUEST_URL, map);
                    log.info("结算请求结果：" + response);
                    SettleResponseVo settleResponseVo = JSONUtil.fromJson(response, SettleResponseVo.class);
                    MerchantSettleRecord shopHlbSettle = new MerchantSettleRecord();
                    shopHlbSettle.setSettleId(settleId);
                    shopHlbSettle.setMerchantId(entry.getKey());
                    shopHlbSettle.setAmount(settleAmount);
                    shopHlbSettle.setRetCode(settleResponseVo.getRt2_retCode());
                    shopHlbSettle.setRetMsg(settleResponseVo.getRt3_retMsg());
                    merchantSettleRecords.add(shopHlbSettle);
                    orderList.addAll(orders);
                } catch (IntrospectionException e) {
                    e.printStackTrace();
                    throw new RuntimeException("合利宝结算失败 -- " + e.getMessage());
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    throw new RuntimeException("合利宝结算失败 -- " + e.getMessage());
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                    throw new RuntimeException("合利宝结算失败 -- " + e.getMessage());
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException("合利宝结算失败 -- " + e.getMessage());
                }
            }

            // 插入合利宝结算记录
            if (merchantSettleRecordService.saveBatch(merchantSettleRecords)) {
                // 更新订单结算字段
                List<Order> updated = new ArrayList<>();
                for (Long orderId : orderList) {
                    Order order = new Order();
                    order.setOrderId(orderId);
                    order.setIsSettle(1);
                    updated.add(order);
                }
                if (!orderService.updateBatchById(updated)) {
                    throw new RuntimeException("合利宝结算失败 -- 更新订单状态失败");
                }
            } else {
                throw new RuntimeException("合利宝结算失败 -- 插入结算记录失败");
            }
        } else {
            log.info("本次无可结算订单");
        }
    }
}
