package com.liquidnet.service.goblin.service.impl;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.gson.JsonObject;
import com.liquidnet.commons.lang.util.*;
import com.liquidnet.service.adam.dto.vo.AdamAddressesVo;
import com.liquidnet.service.adam.dto.vo.AdamRscPolymer01Vo;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.UserPathDto;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.GoblinGoodsSpecDto;
import com.liquidnet.service.goblin.dto.manage.GoblinOrderParam;
import com.liquidnet.service.goblin.dto.manage.GoblinOrderSkuParam;
import com.liquidnet.service.goblin.dto.manage.GoblinOrderStoreParam;
import com.liquidnet.service.goblin.dto.manage.vo.GoblinPayInnerResultVo;
import com.liquidnet.service.goblin.dto.manage.vo.SyncOrderParam;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsSkuInfoVo;
import com.liquidnet.service.goblin.entity.GoblinOrderAttr;
import com.liquidnet.service.goblin.entity.GoblinOrderSku;
import com.liquidnet.service.goblin.entity.GoblinStoreOrder;
import com.liquidnet.service.goblin.service.IGoblinAppOrderService;
import com.liquidnet.service.goblin.util.*;
import io.github.classgraph.json.JSONUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Service
@Slf4j
public class GoblinAppOrderServiceImpl implements IGoblinAppOrderService {

    @Autowired
    GoblinRedisUtils redisUtils;
    @Autowired
    GoblinMongoUtils mongoUtils;
    @Autowired
    QueueUtils queueUtils;
    @Autowired
    GoblinOrderUtils orderUtils;

    @Value("${liquidnet.service.order.url-pay.pay}")
    private String payUrl;
    @Value("${liquidnet.service.order.url-pay.check}")
    private String checkUrl;
    @Value("${liquidnet.service.order.url-pay.goblinUrl}")
    private String synUrl;

    @Override
    public ResponseDto<GoblinPayInnerResultVo> checkOrder(GoblinOrderParam param) {
        String uid = CurrentUtil.getCurrentUid();
        List<String> skuAndPreListAndNumber = CollectionUtil.arrayListString();
        try {
            String orderMasterCode = IDGenerator.storeMasterCode();//总订单id
            List<GoblinOrderStoreParam> goblinOrderStoreParamList = param.getGoblinOrderStoreParamList();//分订单
            //获取用户相关
            String addressId;
            if (param.getAddressIds() == null || param.getAddressIds().size() == 0) {
                addressId = "";
            } else {
                addressId = StringUtils.join(param.getAddressIds(), ",");
            }
            AdamRscPolymer01Vo userVo = orderUtils.adamAddressEnterMember(uid, null, addressId);
            AdamAddressesVo addressesVo;
            boolean isMember;
            if (userVo == null) {
                isMember = false;
                addressesVo = null;
            } else {
                addressesVo = userVo.getAddressesVo();
                switch (userVo.getMembership()) {
                    case 10:
                    case 11:
                        isMember = true;
                        break;
                    default:
                        isMember = false;
                        break;
                }
            }
            for (GoblinOrderStoreParam storeParam : goblinOrderStoreParamList) {//商铺维度循环
                String orderId = IDGenerator.nextSnowId();
                String orderCode = IDGenerator.storeCode(orderId);
                for (GoblinOrderSkuParam skuParam : storeParam.getGoblinOrderSkuParamArrayList()) {//商品维度循环
                    String skuId = skuParam.getSkuId();
//                    String spuId = skuParam.getSpuId();
//                    GoblinGoodsInfoVo goblinGoodsInfoVo = redisUtils.getGoodsInfoVo(spuId);
//                    if (goblinGoodsInfoVo == null) {
//                        return null;//参数异常
//                    }
//                    if (!(goblinGoodsInfoVo.getStatus().equals("3") && goblinGoodsInfoVo.getShelvesStatus().equals("3"))) {
//                        return null;//该spu不可购买
//                    }
//                    if (!goblinGoodsInfoVo.getSkuIdList().contains(skuId)) {
//                        return null;//参数异常
//                    }
                    int number = skuParam.getNumber();
                    GoblinGoodsSkuInfoVo skuVo = redisUtils.getGoodsSkuInfoVo(skuId);
                    if (!(skuVo.getStatus().equals("3") && skuVo.getShelvesStatus().equals("3"))) {
                        throw new Exception("不可购买");
                    }

                    // 判断库存
                    String pre = GoblinStatusConst.MarketPreStatus.getPre(skuId);
                    int limitCount = skuVo.getBuyLimit() == 0 ? Integer.MAX_VALUE : skuVo.getBuyLimit();
                    int surplusGeneral = redisUtils.decrSkuStock(pre, skuId, number);
                    skuAndPreListAndNumber.add(skuId + "," + pre + "," + number);
                    //判断限购
                    String res1 = orderUtils.judgeOrderLimit(uid, skuId, number, limitCount);
                    if (!res1.equals("")) {
                        throw new Exception("已超出限购数量");
                    }
                    //库存回滚
                    if (surplusGeneral < 0) {
                        throw new Exception("已售罄");
                    }
                }//GoblinOrderSkuParam
                //下单
                return order(param, storeParam, uid, isMember, addressesVo, orderMasterCode, orderId, orderCode);
            }//GoblinOrderStoreParam
            throw new Exception("参数异常");
        } catch (Exception e) {
            log.error("Kylin Order Pay Error = {}", e);
            //回顾限购 回滚库存
            for (String item : skuAndPreListAndNumber) {
                String[] array = item.split(",");
                String skuId = array[0];
                String pre = array[1];
                int number = Integer.parseInt(array[2]);
                redisUtils.incrSkuStock(pre, skuId, number);
                redisUtils.decrSkuCountByUid(uid, skuId, number);
            }
            log.error("回滚库存");
            if (e.getMessage() == null) {
                return ResponseDto.failure(ErrorMapping.get("20018"));//乱七八糟异常
            } else if (e.getMessage().equals("券不可用")) {
                return ResponseDto.failure(e.getMessage());
            } else if (e.getMessage().equals("不可购买")) {
                return ResponseDto.failure(e.getMessage());
            } else if (e.getMessage().equals("参数异常")) {
                return ResponseDto.failure(e.getMessage());
            } else if (e.getMessage().equals("已售罄")) {
                return ResponseDto.failure(e.getMessage());
            } else if (e.getMessage().equals("已超出限购数量")) {
                return ResponseDto.failure(e.getMessage());
            } else {
                return ResponseDto.failure(ErrorMapping.get("20018"));//乱七八糟异常
            }
        }
    }

    private ResponseDto<GoblinPayInnerResultVo> order(GoblinOrderParam param, GoblinOrderStoreParam storeParam, String uid, boolean isMember, AdamAddressesVo addressesVo, String orderMasterCode, String orderId, String orderCode) throws Exception {
        String platVoucherCode = storeParam.getPlatVoucherCode();
        String storeId = storeParam.getStoreId();
        LinkedList<String> sqls = CollectionUtil.linkedListString();
        Map token = CurrentUtil.getTokenClaims();
        String headerCliSource = CurrentUtil.getHeaderCliSource(), headerCliVersion = CurrentUtil.getHeaderCliVersion();
        String source = headerCliSource == null ? "" : headerCliSource;
        String version = headerCliVersion == null ? "" : headerCliVersion;
        LocalDateTime now = LocalDateTime.now();
        String skuName = "";
        BigDecimal price;//sku应付价格
        BigDecimal priceBase;//sku原价
        BigDecimal storeTotalPrice = BigDecimal.ZERO;//订单总金额
        BigDecimal voucherMarket = BigDecimal.ZERO;//活动优惠金额
        String writeOffCode = ""; //取货码
        for (GoblinOrderSkuParam skuParam : storeParam.getGoblinOrderSkuParamArrayList()) {
            String pre = GoblinStatusConst.MarketPreStatus.getPre(skuParam.getSkuId());
            GoblinGoodsSkuInfoVo skuVo = redisUtils.getGoodsSkuInfoVo(skuParam.getSkuId());
            skuName = skuName.concat(skuVo.getName()).concat(",");
            if (pre != null && pre.contains(GoblinStatusConst.MarketPreStatus.MARKET_PRE_PURCHASE.getValue())) {
                writeOffCode = IDGenerator.getWriteOffCode();
            }
            //获得 商品原价和活动价格
            priceBase = skuVo.getPrice();
            if (isMember) {
                priceBase = skuVo.getPriceMember();
            }
            if (pre != null) {
                GoblinGoodsSkuInfoVo skuMarketVo = redisUtils.getGoodsSkuInfoVo(skuParam.getSkuId().split(pre)[0]);
                price = skuMarketVo.getPrice();
                if (isMember) {
                    price = skuMarketVo.getPriceMember();
                }
            } else {
                price = skuVo.getPrice();
                if (isMember) {
                    price = skuVo.getPriceMember();
                }
            }
            //获得活动优惠价格
            voucherMarket = voucherMarket.add(priceBase.subtract(price));
            storeTotalPrice = storeTotalPrice.add(price);
            //订单sku
            GoblinOrderSku orderSku = GoblinOrderSku.getNew();
            orderSku.setOrderSkuId(IDGenerator.nextTimeId2());
            orderSku.setOrderId(orderId);
            orderSku.setSpuId(skuParam.getSpuId());
            orderSku.setSkuId(skuParam.getSkuId());
            orderSku.setNum(skuParam.getNumber());
            orderSku.setSkuPrice(priceBase);
            orderSku.setSkuPriceActual(price);
            orderSku.setSkuName(skuVo.getName());
            orderSku.setSkuNo(skuVo.getSkuNo());
            orderSku.setSkuImage(skuVo.getSkuPic());
            orderSku.setSkuSpecs(JSON.toJSONString(skuVo.getSkuSpecList()));
            orderSku.setPriceVoucher(priceBase.subtract(price));
            orderSku.setCreatedAt(now);
        }
        //优惠券
        BigDecimal voucherPrice = BigDecimal.ZERO;
        if (platVoucherCode != null && !platVoucherCode.equals("")) {
            HashMap<String, Object> hashMap = orderUtils.useCoupon(platVoucherCode, "购买商品[" + orderCode + "]", storeTotalPrice, "");//todo
            voucherPrice = (BigDecimal) hashMap.get("voucher");
            Integer typeVoucher = (Integer) hashMap.get("type");
            if (typeVoucher.equals(-1)) {
                throw new Exception("券不可用");
            }
        }
        //生成订单
        GoblinStoreOrder storeOrder = GoblinStoreOrder.getNew();
        storeOrder.setMasterOrderCode(orderMasterCode);
        storeOrder.setOrderId(orderId);
        storeOrder.setStoreId(storeId);
        storeOrder.setOrderCode(orderCode);
        storeOrder.setUserId(uid);
        storeOrder.setUserName(StringUtils.defaultString(((String) token.get("nickname")), ""));
        storeOrder.setUserMobile(StringUtils.defaultString(((String) token.get("mobile")), ""));
        storeOrder.setPriceTotal(storeTotalPrice);
        storeOrder.setPriceActual(storeOrder.getPriceTotal().subtract(voucherMarket).subtract(voucherPrice));
        storeOrder.setPriceRefund(BigDecimal.ZERO);
        storeOrder.setPreSalePrice(BigDecimal.ZERO);
        storeOrder.setPriceExpress(BigDecimal.TEN);//todo 快递费 暂时写死
        storeOrder.setPriceModify(BigDecimal.ZERO);
        storeOrder.setPricePoint((BigDecimal.ZERO));
        storeOrder.setPriceCoupon(voucherPrice);
        storeOrder.setPriceRedEnvelope((BigDecimal.ZERO));
        storeOrder.setPriceVoucher(voucherMarket.add(voucherPrice));
        storeOrder.setStatus(0);
        storeOrder.setStatusPreSale(0);
        storeOrder.setStatusEvaluation(0);
        storeOrder.setRedEnvelopeCode("");
        storeOrder.setUcouponId(platVoucherCode);
        storeOrder.setUsePoint((BigDecimal.ZERO));
        storeOrder.setPayType(param.getPayType());
        storeOrder.setCancelReason("");
        storeOrder.setPreDepositPay(0);
        storeOrder.setSource(source);
        storeOrder.setVersion(version);
        storeOrder.setIsMember(isMember ? 1 : 0);
        storeOrder.setOrderType(0);
        storeOrder.setLotteryStatus("0");
        storeOrder.setWriteOffCode(writeOffCode);
        storeOrder.setPayCountdownMinute(5);
        storeOrder.setIpAddress(CurrentUtil.getCliIpAddr());
        storeOrder.setCreatedAt(now);
        //订单attr
        GoblinOrderAttr orderAttr = GoblinOrderAttr.getNew();
        orderAttr.setOrderAttrId(IDGenerator.nextTimeId2());
        orderAttr.setOrderId(orderId);
        orderAttr.setExpressContacts(addressesVo.getName());
        orderAttr.setExpressAddress(addressesVo.getProvince() + "," + addressesVo.getCounty() + "," + addressesVo.getCity());
        orderAttr.setExpressAddressDetail(addressesVo.getAddress());
        orderAttr.setExpressPhone(addressesVo.getPhone());
        orderAttr.setExpressType(1);
        orderAttr.setCreatedAt(now);
        //是否免费
        boolean isFree = false;
        GoblinPayInnerResultVo payInnerResultVo;
        if (storeOrder.getPriceActual().compareTo(BigDecimal.valueOf(0)) > 0) {
            // 调用支付
            LinkedMultiValueMap<String, String> httpData = CollectionUtil.linkedMultiValueMapStringString();
            httpData.add("type", "PRODUCT");
            httpData.add("price", storeOrder.getPriceActual().toString());
            httpData.add("name", redisUtils.getStoreInfoVo(storeParam.getStoreId()).getStoreName());
            httpData.add("detail", skuName);
            httpData.add("orderCode", storeOrder.getOrderCode());
            httpData.add("clientIp", storeOrder.getIpAddress());
            httpData.add("notifyUrl", synUrl);
            httpData.add("createDate", storeOrder.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            httpData.add("expireTime", storeOrder.getPayCountdownMinute().toString());
            httpData.add("payType", storeOrder.getPayType());
            httpData.add("deviceFrom", param.getDeviceFrom());
            if (param.getDeviceFrom().equals("js") || param.getDeviceFrom().equals("applet")) {
                httpData.add("openId", param.getOpenId());
            }
            if (param.getPayType().equals("alipay") && param.getDeviceFrom().equals("wap")) {
                httpData.add("showUrl", param.getShowUrl() + storeOrder.getOrderId());
                httpData.add("returnUrl", param.getReturnUrl() + storeOrder.getOrderId());
            }
            if (param.getPayType().equals("douyinpay")) {
                httpData.add("showUrl", param.getShowUrl() + storeOrder.getOrderId());
                httpData.add("returnUrl", param.getReturnUrl() + storeOrder.getOrderId());
            }
            if (param.getPayType().equals("unionpay")) {
                httpData.add("returnUrl", param.getReturnUrl() + storeOrder.getOrderId());
            }
            String returnData = HttpUtil.post(payUrl, httpData);
            log.info("调用 DRAGON 结果 = " + returnData);
            ResponseDto<GoblinPayInnerResultVo> dto = JsonUtils.fromJson(returnData, new TypeReference<ResponseDto<GoblinPayInnerResultVo>>() {
            });
            payInnerResultVo = GoblinPayInnerResultVo.getNew();
            payInnerResultVo.setCode(dto.getData().getCode());
            payInnerResultVo.setOrderCode(dto.getData().getOrderCode());
            payInnerResultVo.setPayData(dto.getData().getPayData());
            payInnerResultVo.setOrderId(storeOrder.getOrderId());
            payInnerResultVo.setPayType(storeOrder.getPayType());
            payInnerResultVo.setPrice(storeOrder.getPriceActual());
            storeOrder.setPayCode(payInnerResultVo.getCode());
            payInnerResultVo.setShowUrl(param.getShowUrl() + storeOrder.getOrderId());
            payInnerResultVo.setReturnUrl(param.getReturnUrl() + storeOrder.getOrderId());
        } else {
            isFree = true;
            storeOrder.setPayType("FREE");
            storeOrder.setPayCode("FREE_PAY_CODE");
            payInnerResultVo = GoblinPayInnerResultVo.getNew();
            payInnerResultVo.setPrice(BigDecimal.valueOf(0));
            payInnerResultVo.setOrderId(storeOrder.getOrderId());
            payInnerResultVo.setPayType(storeOrder.getPayType());
        }

        //todo vo redisList
        log.info(UserPathDto.setData("下单(唤起支付)", param, payInnerResultVo));
        if (isFree) {
            SyncOrderParam syncOrderParam = SyncOrderParam.getNew();
            syncOrderParam.setOrderCode(storeOrder.getOrderCode());
            syncOrderParam.setPaymentAt(DateUtil.format(LocalDateTime.now(), DateUtil.Formatter.yyyyMMddHHmmss));
            syncOrderParam.setCode(storeOrder.getPayCode());
            syncOrderParam.setPrice(storeOrder.getPriceActual());
            syncOrderParam.setPaymentId("FREE_PAYMENT_ID");
            syncOrderParam.setPaymentType(null);
            syncOrderParam.setStatus(1);
//            syncOrder(syncOrderParam);
            return ResponseDto.success(payInnerResultVo);
        } else {
            return ResponseDto.success(payInnerResultVo);
        }
    }
}
