package cn.freemud.service.mccafe.impl;

import cn.freemud.adapter.CouponAdapter;
import cn.freemud.adapter.OrderAdapter;
import cn.freemud.base.constant.Version;
import cn.freemud.base.entity.BaseResponse;
import cn.freemud.base.log.LogTreadLocal;
import cn.freemud.constant.ResponseCodeConstant;
import cn.freemud.entities.dto.QueryOrdersResponseDto;
import cn.freemud.enums.ResponseResult;
import cn.freemud.management.entities.dto.request.order.*;
import cn.freemud.enums.CouponReqTypeEnum;
import cn.freemud.enums.MCCafeChannelEnum;
import cn.freemud.management.entities.dto.response.coupon.McdNetBatchQueryResponse;
import cn.freemud.management.entities.dto.response.coupon.McdNetCouponInfoRespDto;
import cn.freemud.management.entities.dto.response.coupon.McdNetCouponProductRespDto;
import cn.freemud.management.enums.OrderSource;
import cn.freemud.management.thirdparty.CouponOfflineMCCafeClient;
import cn.freemud.service.mccafe.CouponClientService;
import cn.freemud.utils.LogUtil;
import cn.freemud.utils.ResponseUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.freemud.application.sdk.api.couponcenter.offline.response.CouponBaseResponse;
import com.freemud.application.sdk.api.couponcenter.offline.response.CouponQueryResponse;
import com.freemud.application.sdk.api.couponcenter.offline.response.CouponRedeemResponse;
import com.freemud.application.sdk.api.couponcenter.offline.service.OfflineCouponSdkService;
import com.freemud.application.sdk.api.log.ErrorLog;
import com.freemud.application.sdk.api.ordercenter.enums.OrderClientType;
import com.freemud.application.sdk.api.productcenter.response.menu.GetMenuCategoryByIdsResponse;
import com.freemud.application.sdk.api.service.EmailAlertService;
import com.freemud.sdk.api.assortment.order.enums.*;
import com.freemud.sdk.api.assortment.order.request.order.CreateOrderAccountRequest;
import com.freemud.sdk.api.assortment.order.response.order.QueryOrdersResponse;
import com.google.common.base.Throwables;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class CouponClientServiceImpl implements CouponClientService {

    @Autowired
    private CouponOfflineMCCafeClient couponOfflineMCCafeClient;

    @Autowired
    private CouponAdapter couponAdapter;

    @Autowired
    private OrderAdapter orderAdapter;

    @Autowired
    private OfflineCouponSdkService offlineCouponSdkService;

    @Autowired
    private EmailAlertService emailAlertService;

    @Override
    public CouponRedeemResponse redeem(QueryOrdersResponse.DataBean.OrderBean orderBean, List<CreateOrderAccountRequest> accounts) {
        if (null == orderBean || CollectionUtils.isEmpty(accounts)) {
            return null;
        }
        Optional<CreateOrderAccountRequest> accountRequest = accounts.stream().filter(
                account -> account.getAccountType().equals(QueryOrderAccountType.COUPON)
                ||  account.getAccountType().equals(QueryOrderAccountType.PRODUCT_COUPON)
                ||  account.getAccountType().equals(QueryOrderAccountType.DISCOUNT_COUPON)).findFirst();
        if (!accountRequest.isPresent() || accountRequest.get().getPrice() == 0) {
            return null;
        }
        CreateOrderAccountRequest accountBean = accountRequest.get();
        List<MCCafeProductRedeemVo> products = new ArrayList<>();
        //商品券核销核销参数
        if (QueryOrderAccountType.PRODUCT_COUPON.equals(accountBean.getAccountType())) {
            for (int i = 0; i < orderBean.getProductList().size(); i++) {
                QueryOrdersResponse.DataBean.OrderBean.ProductBean productBean = orderBean.getProductList().get(i);
                String pid = StringUtils.isNotBlank(productBean.getSpecification()) ? productBean.getSpecification() : productBean.getProductId();
                if (!org.springframework.util.CollectionUtils.isEmpty(orderBean.getProductList().get(i).getDiscountList())) {
                    List<QueryOrdersResponse.DataBean.OrderBean.ProductBean.ProductDiscount> discounts = orderBean.getProductList().get(i).getDiscountList().stream().
                            filter(productDiscount -> productDiscount.getDiscountId().equals(accountBean.getAccountId())).collect(Collectors.toList());
                    for (QueryOrdersResponse.DataBean.OrderBean.ProductBean.ProductDiscount productDiscount : discounts) {
                        if (productDiscount.getDiscountType() == null || productDiscount.getDiscountType() == 0) {
                            continue;
                        }
                        MCCafeProductRedeemVo mcCafeProductRedeemVo = new MCCafeProductRedeemVo();
                        mcCafeProductRedeemVo.setPid(pid);
                        mcCafeProductRedeemVo.setKeyProductCode(productBean.getCustomerCode());
                        mcCafeProductRedeemVo.setCustomer_code(productBean.getCustomerCode());
                        mcCafeProductRedeemVo.setConsume_num(productDiscount.getDiscountQty());
                        mcCafeProductRedeemVo.setSeq(i + 1);
                        products.add(mcCafeProductRedeemVo);
                    }
                }
            }
        }
        MCCafeCouponRequest mcCafeCouponRequest = new MCCafeCouponRequest();
        mcCafeCouponRequest.setVer(Integer.valueOf(Version.VERSION_1));
        mcCafeCouponRequest.setReqtype(CouponReqTypeEnum.REDEEM.getCode());
        mcCafeCouponRequest.setPartnerId(Integer.parseInt(orderBean.getCompanyId()));
        mcCafeCouponRequest.setStore_id(orderBean.getShopId());
        mcCafeCouponRequest.setStation_id("-1");
        mcCafeCouponRequest.setOperator_id("-1");
        // 订单号
        mcCafeCouponRequest.setTrans_id(orderBean.getOid());
        mcCafeCouponRequest.setChannel(OrderClientType.ALIPAY.getIndex().toString().equals(orderBean.getOrderClient())?MCCafeChannelEnum.MOCOFFEE_ZFB.getName():MCCafeChannelEnum.MOCOFFEE_WX.getName());
        List<MCCafeTransactionVo> transactions = new ArrayList<>();
        MCCafeTransactionVo mcCafeTransactionVo = new MCCafeTransactionVo();
        mcCafeTransactionVo.setCode(accountBean.getAccountId());
        mcCafeTransactionVo.setTotalAmount(-accountBean.getPrice());
        if (CollectionUtils.isNotEmpty(products)) {
            mcCafeTransactionVo.setProducts(products);
        }
        transactions.add(mcCafeTransactionVo);
        mcCafeCouponRequest.setTransactions(transactions);
        mcCafeCouponRequest.setSign("skip");

        mcCafeCouponRequest.setAppFlag("kgd.N");
        mcCafeCouponRequest.setBusiness_date(cn.freemud.base.util.DateUtil.convert2Str(new Date(), cn.freemud.base.util.DateUtil.FORMAT_yyyyMMdd));

        return couponOfflineMCCafeClient.redeem(mcCafeCouponRequest);
    }

    @Override
    public CouponRedeemResponse redeem(MCCafeCouponRequest mcCafeCouponRequest) {
        return couponOfflineMCCafeClient.redeem(mcCafeCouponRequest);
    }

    @Override
    public CouponRedeemResponse redeemBatch(QueryOrdersResponse.DataBean.OrderBean orderBean, List<CreateOrderAccountRequest> accounts) {
        if (null == orderBean || CollectionUtils.isEmpty(accounts)) {
            return null;
        }
        List<CreateOrderAccountRequest> accountList = accounts.stream().filter(
                account -> (account.getAccountType().equals(QueryOrderAccountType.COUPON)
                        ||  account.getAccountType().equals(QueryOrderAccountType.PRODUCT_COUPON)
                        ||  account.getAccountType().equals(QueryOrderAccountType.DISCOUNT_COUPON)) && account.getPrice() != 0l).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(accountList)) {
            return null;
        }

        List<MCCafeCouponRequest> list =
                accountList.stream().map(accountBean -> couponAdapter.convert2MCCafeCouponRequest(orderBean, accountBean)).collect(Collectors.toList());

        CouponRedeemResponse couponRedeemResponse = new CouponRedeemResponse();
        redeem:
        for (MCCafeCouponRequest request : list) {
            retry:
            for(int i=0;i<3;i++) {
                couponRedeemResponse = redeem(request);
                if(ResponseCodeConstant.RESPONSE_SUCCESS.equals(couponRedeemResponse.getStatusCode())) {
                    continue redeem;
                }
            }
        }

        return couponRedeemResponse;
    }

    @Override
    public List<CouponRedeemResponse> redeemBatch(QueryOrdersResponseDto.DataBean.OrderBean orderBean) {
        if (null == orderBean || CollectionUtils.isEmpty(orderBean.getAccountList())) {
            return null;
        }
        List<QueryOrdersResponseDto.DataBean.OrderBean.AccountBean> accountList = orderBean.getAccountList().stream().filter(
                account -> (orderAdapter.getQueryOrderAccountType(OldOrderAccountType.getByCode(account.getType())).equals(QueryOrderAccountType.COUPON)
                        ||  orderAdapter.getQueryOrderAccountType(OldOrderAccountType.getByCode(account.getType())).equals(QueryOrderAccountType.PRODUCT_COUPON)
                        ||  orderAdapter.getQueryOrderAccountType(OldOrderAccountType.getByCode(account.getType())).equals(QueryOrderAccountType.DISCOUNT_COUPON)
                        ||  orderAdapter.getQueryOrderAccountType(OldOrderAccountType.getByCode(account.getType())).equals(QueryOrderAccountType.FREIGHT_COUPON))
                        ).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(accountList)) {
            return null;
        }

        MCCafeCouponRequest mcCafeCouponRequest = MCCafeCouponRequest.builder()
                .ver(88)
                .reqtype(CouponReqTypeEnum.BATCH_QUERY.getCode())
                .partnerId(Integer.parseInt(orderBean.getCompanyId()))
                .store_id(orderBean.getShopId())
                .station_id("1")
                .operator_id(orderBean.getUserId())
                .channel(OrderSource.ALIPAY.getSource().equals(orderBean.getSource())?MCCafeChannelEnum.MOCOFFEE_ZFB.getName():MCCafeChannelEnum.MOCOFFEE_WX.getName())
                .couponlist(accountList.stream().map(o -> new MCCafeCouponVo(o.getAccountId())).collect(Collectors.toList()))
                .sign("skip")
                .build();
        McdNetBatchQueryResponse mcdNetBatchQueryResponse = batchQuery(mcCafeCouponRequest);
        if (mcdNetBatchQueryResponse == null || !ResponseCodeConstant.RESPONSE_SUCCESS.equals(mcdNetBatchQueryResponse.getStatusCode())
                || CollectionUtils.isEmpty(mcdNetBatchQueryResponse.getCouponlist())) {
            LogUtil.error("获取优惠券详情失败，无法核销", mcCafeCouponRequest, mcdNetBatchQueryResponse);
            return null;
        }

        Map<String, McdNetBatchQueryResponse.Coupon> couponMap = mcdNetBatchQueryResponse.getCouponlist().stream()
                .collect(Collectors.toMap(McdNetBatchQueryResponse.Coupon::getCode, Function.identity(), (k1, k2) -> k1));

        List<MCCafeCouponRequest> list =
                accountList.stream().map(accountBean -> couponAdapter.convert2MCCafeCouponRequest(orderBean, accountBean, couponMap.get(accountBean.getAccountId()))).filter(o -> o!=null).collect(Collectors.toList());

        List<CouponRedeemResponse> couponRedeemResponseList = new ArrayList<>();
        List<CouponRedeemResponse> couponRedeemResponseListAll = new ArrayList<>();
        redeem:
        for (MCCafeCouponRequest request : list) {
            CouponRedeemResponse couponRedeemResponse = null;
            retry:
            for(int i=0;i<3;i++) {
                couponRedeemResponse = redeem(request);
                if(ResponseCodeConstant.RESPONSE_SUCCESS.equals(couponRedeemResponse.getStatusCode())) {
                    couponRedeemResponseListAll.add(couponRedeemResponse);
                    continue redeem;
                }
            }
            couponRedeemResponseList.add(couponRedeemResponse);
            couponRedeemResponseListAll.add(couponRedeemResponse);
        }
        if(CollectionUtils.isNotEmpty(couponRedeemResponseList)) {
            LogUtil.info(LogTreadLocal.getTrackingNo(), "麦咖啡核销券失败",
                    JSON.toJSONString(list), JSON.toJSONString(couponRedeemResponseListAll));
        }

        return couponRedeemResponseList;
    }

    @Override
    public CouponRedeemResponse cancelRedeem(QueryOrdersResponse.DataBean.OrderBean orderBean, List<CreateOrderAccountRequest> accounts) {
        MCCafeCouponRequest mcCafeCouponRequest = new MCCafeCouponRequest();
        return couponOfflineMCCafeClient.cancelRedeem(mcCafeCouponRequest);
    }

    @Override
    public CouponQueryResponse query(MCCafeCouponRequest mcCafeCouponRequest) {
        return couponOfflineMCCafeClient.query(mcCafeCouponRequest);
    }

    @Override
    public McdNetBatchQueryResponse batchQuery(MCCafeCouponRequest mcCafeCouponRequest) {
        return couponOfflineMCCafeClient.batchQuery(mcCafeCouponRequest);
    }

    @Override
    public CouponBaseResponse lock(QueryOrdersResponse.DataBean.OrderBean orderBean, List<CreateOrderAccountRequest> accounts) {
        if (null == orderBean || CollectionUtils.isEmpty(accounts)) {
            return null;
        }
        Optional<CreateOrderAccountRequest> accountRequest = accounts.stream().filter(
                account -> account.getAccountType().equals(QueryOrderAccountType.COUPON)
                ||  account.getAccountType().equals(QueryOrderAccountType.PRODUCT_COUPON)
                ||  account.getAccountType().equals(QueryOrderAccountType.DISCOUNT_COUPON)).findFirst();
        if (!accountRequest.isPresent() || accountRequest.get().getPrice() == 0) {
            return null;
        }
        CreateOrderAccountRequest accountBean = accountRequest.get();
        MCCafeCouponLockRequest couponCodeVerificationDto = new MCCafeCouponLockRequest();
        couponCodeVerificationDto.setVer(Integer.valueOf(Version.VERSION_1));
        couponCodeVerificationDto.setReqType(CouponReqTypeEnum.LOCK.getCode());
        couponCodeVerificationDto.setPartnerId(orderBean.getCompanyId());
        couponCodeVerificationDto.setStoreId(orderBean.getShopId());
        // 订单号
        couponCodeVerificationDto.setTransId(orderBean.getOid());
        couponCodeVerificationDto.setCoupon(accountBean.getAccountId());
        couponCodeVerificationDto.setOfferId(accountBean.getAccountId());
        couponCodeVerificationDto.setNumber("1");
        couponCodeVerificationDto.setChannel(OrderClientType.ALIPAY.getIndex().toString().equals(orderBean.getOrderClient())
                ? MCCafeChannelEnum.MOCOFFEE_ZFB.getName():MCCafeChannelEnum.MOCOFFEE_WX.getName());
        couponCodeVerificationDto.setOperatorId("-1");
        couponCodeVerificationDto.setStationId("-1");
        couponCodeVerificationDto.setSign("skip");

        return couponOfflineMCCafeClient.lock(couponCodeVerificationDto);
    }

    @Override
    public CouponBaseResponse lock(MCCafeCouponLockRequest mcCafeCouponLockRequest) {
        return couponOfflineMCCafeClient.lock(mcCafeCouponLockRequest);
    }

    @Override
    public CouponBaseResponse lockBatch(QueryOrdersResponse.DataBean.OrderBean orderBean, List<CreateOrderAccountRequest> accounts) {
        if (null == orderBean || CollectionUtils.isEmpty(accounts)) {
            return null;
        }
        List<CreateOrderAccountRequest> accountList = accounts.stream().filter(
                account -> (account.getAccountType().equals(QueryOrderAccountType.COUPON)
                        ||  account.getAccountType().equals(QueryOrderAccountType.PRODUCT_COUPON)
                        ||  account.getAccountType().equals(QueryOrderAccountType.DISCOUNT_COUPON)) && account.getPrice() != 0l).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(accountList)) {
            return null;
        }

        List<MCCafeCouponLockRequest> list =
                accountList.stream().map(accountBean -> couponAdapter.convert2MCCafeCouponLockRequest(orderBean, accountBean)).collect(Collectors.toList());

        CouponBaseResponse baseResponse = new CouponBaseResponse();
        lock:
        for (MCCafeCouponLockRequest request : list) {
            retry:
            for(int i=0;i<3;i++) {
                baseResponse = lock(request);
                if(ResponseCodeConstant.RESPONSE_SUCCESS.equals(baseResponse.getStatusCode())) {
                    continue lock;
                }
            }
        }

        return baseResponse;
    }

    @Override
    public List<CouponBaseResponse> lockBatch(QueryOrdersResponseDto.DataBean.OrderBean orderBean) {
        if (null == orderBean || CollectionUtils.isEmpty(orderBean.getAccountList())) {
            return null;
        }
        List<QueryOrdersResponseDto.DataBean.OrderBean.AccountBean> accountList = orderBean.getAccountList().stream().filter(
                account -> (orderAdapter.getQueryOrderAccountType(OldOrderAccountType.getByCode(account.getType())).equals(QueryOrderAccountType.COUPON)
                        ||  orderAdapter.getQueryOrderAccountType(OldOrderAccountType.getByCode(account.getType())).equals(QueryOrderAccountType.PRODUCT_COUPON)
                        ||  orderAdapter.getQueryOrderAccountType(OldOrderAccountType.getByCode(account.getType())).equals(QueryOrderAccountType.DISCOUNT_COUPON))
        ).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(accountList)) {
            return null;
        }

        List<MCCafeCouponLockRequest> list =
                accountList.stream().map(accountBean -> couponAdapter.convert2MCCafeCouponLockRequest(orderBean, accountBean)).collect(Collectors.toList());

        List<CouponBaseResponse> baseResponseList = new ArrayList<>();
        List<CouponBaseResponse> baseResponseListAll = new ArrayList<>();
        lock:
        for (MCCafeCouponLockRequest request : list) {
            CouponBaseResponse baseResponse = null;
            retry:
            for(int i=0;i<3;i++) {
                baseResponse = lock(request);
                if(ResponseCodeConstant.RESPONSE_SUCCESS.equals(baseResponse.getStatusCode())) {
                    baseResponseListAll.add(baseResponse);
                    continue lock;
                }
            }
            baseResponseList.add(baseResponse);
            baseResponseListAll.add(baseResponse);
        }

        if(CollectionUtils.isNotEmpty(baseResponseList)) {
            LogUtil.info(LogTreadLocal.getTrackingNo(), "麦咖啡冻结券失败",
                    JSON.toJSONString(list), JSON.toJSONString(baseResponseListAll));
        }

        return baseResponseList;
    }

    @Override
    public CouponBaseResponse unlock(MCCafeCouponLockRequest mcCafeCouponLockRequest) {
        return couponOfflineMCCafeClient.unlock(mcCafeCouponLockRequest);
    }

    @Override
    public BaseResponse callbackNotify(QueryOrdersResponseDto.DataBean.OrderBean orderBean) {
        if (CollectionUtils.isEmpty(orderBean.getAccountList())) {

            return ResponseUtil.success();
        }
        List<QueryOrdersResponseDto.DataBean.OrderBean.AccountBean> accountBeanList = orderBean.getAccountList().stream().filter(account -> account.getType().equals(OldOrderAccountType.COUPON.getCode()) || account.getType().equals(OldOrderAccountType.PRODUCT_COUPON.getCode())
                || account.getType().equals(OldOrderAccountType.DISCOUNT_COUPON.getCode())).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(accountBeanList)) {
            return ResponseUtil.success();
        }
        String orderCode = orderBean.getOid();
        String partnerId = orderBean.getCompanyId();

        List<String> failedList = new ArrayList<>();
        for(QueryOrdersResponseDto.DataBean.OrderBean.AccountBean accountBean : accountBeanList) {
            String couponCode = accountBean.getAccountId();
            try {
                //移除卡包失败，邮件报警
                com.freemud.application.sdk.api.base.BaseResponse baseResponse = offlineCouponSdkService.callbackNotify(couponCode, orderCode, partnerId,"");
                if (!Objects.equals(baseResponse.getCode(), cn.freemud.enums.ResponseResult.SUCCESS.getCode())) {
                    emailAlertService.sendEmailAlert("券码移除卡包失败", String.format("request:%s \r\nresponse:%s","券码号："+couponCode+"订单号："+orderCode, JSONObject.toJSONString(baseResponse)));
                    failedList.add(couponCode);
                }
            } catch (Exception ex) {
                emailAlertService.sendEmailAlert("券码移除卡包异常", String.format("request:%s \r\nexception:%s", "券码号："+couponCode+"订单号："+orderCode, Throwables.getStackTraceAsString(ex)));
                ErrorLog.printErrorLog("verification_error", "/callbackNotify", orderCode, ex);
                failedList.add(couponCode);
            }
        }
        if(CollectionUtils.isNotEmpty(failedList)) {
            return ResponseUtil.error(cn.freemud.enums.ResponseResult.COUPON_CALLBACK_FAIL.getCode(), "优惠券移除卡包失败："+failedList.toString());
        }
        return ResponseUtil.success();
    }
}
