package cn.freemud.management.service.handle;

import cn.freemud.base.util.DateUtil;
import cn.freemud.management.enums.coupon.CouponThirdChannelEnum;
import cn.freemud.management.enums.coupon.EcologyChannelTypeEnum;
import cn.freemud.management.enums.SettlementTypeEnum;
import cn.freemud.management.enums.coupon.ThirdCouponReportStatusEnum;
import cn.freemud.management.enums.coupon.ThirdCouponReportTypeEnum;
import cn.freemud.management.thirdparty.CouponBackstageClient;
import cn.freemud.management.thirdparty.CouponOfflineClient;
import cn.freemud.management.thirdparty.EcologyAdapterClient;
import cn.freemud.management.thirdparty.request.coupon.RedeemReportQueryRequest;
import cn.freemud.management.thirdparty.request.coupon.ReverseThirdCouponRedeemReportReq;
import cn.freemud.management.thirdparty.request.ecology.adapter.CancelRedeemCouponRequest;
import cn.freemud.management.thirdparty.response.Result;
import cn.freemud.management.thirdparty.response.coupon.RedeemReportQueryResponse;
import cn.freemud.management.thirdparty.response.coupon.SaasPageResponse;
import cn.freemud.management.thirdparty.response.coupon.SaasResponse;
import cn.freemud.management.thirdparty.response.ecology.adapter.CancelRedeemCouponResponse;
import com.alibaba.fastjson.JSONObject;
import com.freemud.application.sdk.api.log.ApiLog;
import com.freemud.application.sdk.api.log.ErrorLog;
import com.freemud.application.sdk.api.ordercenter.entities.v1.OrderBeanV1;
import com.freemud.application.sdk.api.ordercenter.enums.CashTypeEnum;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.OrderInfoReqs;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.OrderPayItemResp;
import com.freemud.application.sdk.api.ordercenter.response.orderInfo.OrderSettlementResp;
import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * &copy; All rights Reserved
 * 三方券订单
 * @author wénkǎi.zhāng 2024-02-29
 * @since 1.0
 */
@Component
public class ThirdCouponOrderHandle {
    @Autowired
    private CouponBackstageClient couponBackstageClient;

    @Autowired
    private EcologyAdapterClient ecologyAdapterClient;

    @Autowired
    private CouponOfflineClient couponOfflineClient;
    /**
     * 判断订单中是否使用了三方券
     * <pre>
     *     1. 小程序订单，使用了三方券抵扣
     *     2. 订单宝订单，使用了三方券支付
     * </pre>
     * @param orderInfo
     * @return 是/否
     */
    public static boolean isThirdCouponOrder(OrderInfoReqs orderInfo) {
        return isThirdCouponOrder(orderInfo.getOrderSettlementDetailList(), orderInfo.getOrderPayItemCreateReqList());
    }

    /**
     * 判断订单中是否使用了三方券
     * <pre>
     *     1. 小程序订单，使用了三方券抵扣
     *     2. 订单宝订单，使用了三方券支付
     * </pre>
     * @param orderBean
     * @return 是/否
     */
    public static boolean isThirdCouponOrder(OrderBeanV1 orderBean) {
        return isThirdCouponOrder(orderBean.getOrderSettlementDetailList(), orderBean.getOrderPayItem());
    }

    /**
     * 判断订单中是否使用了三方券
     * <pre>
     *     1. 小程序订单，使用了三方券抵扣
     *     2. 订单宝订单，使用了三方券支付
     * </pre>
     * @param orderSettlementDetailList
     * @param orderPayItemCreateReqList
     * @return 是/否
     */
    public static boolean isThirdCouponOrder(List<OrderSettlementResp> orderSettlementDetailList, List<OrderPayItemResp> orderPayItemCreateReqList) {
        // 判断是否使用了三方券抵扣
        if (CollectionUtils.isNotEmpty(orderSettlementDetailList)) {
            boolean isThirdCoupon = orderSettlementDetailList.stream()
                    .anyMatch(o ->
                            o.getSettlementType().equals(SettlementTypeEnum.MT_TG_GOODS_COUPON.getSettlementType())
                                    || o.getSettlementType().equals(SettlementTypeEnum.TIKTOK_TG_GOODS_COUPON.getSettlementType())
                    );
            if (isThirdCoupon) {
                return true;
            }
        }

        // 判断是否使用了三方券支付
        if (CollectionUtils.isNotEmpty(orderPayItemCreateReqList)) {
            return orderPayItemCreateReqList.stream().anyMatch(o -> CashTypeEnum.isThirdCoupon(o.getPayChannelType().toString()));
        }

        return false;
    }

    /**
     * 判断是否超过了券冲正时间
     * <pre></pre>
     * @param redeemDate
     * @param channelTypeEnum
     * @return
     */
    public static boolean isCancelTimeout(ThirdCouponOrderHandle.ThirdCouponDto couponDto, @Nullable Date redeemDate) {
        EcologyChannelTypeEnum channelTypeEnum = couponDto.getEcologyChannelType();
        if (redeemDate == null) {
            redeemDate = couponDto.getRedeemTime();
        }
        if (EcologyChannelTypeEnum.MEITUAN.equals(channelTypeEnum)) {
            // 商家核销的美团券不能超过 60天，自助核销的美团券不能超过 24小时
            if (DateUtil.addDays(redeemDate, 60).compareTo(new Date()) < 0) {
                return true;
            }
            // 如果不是逗号分隔的纯数字，认为是加密券号（自助核销的券号是加密的）
            if (couponDto.getCouponCodes().stream().anyMatch(code -> !code.matches("^[0-9,]+$"))) {
                if (redeemDate.getTime() + 24 * 3600_000 < System.currentTimeMillis()) {
                    return true;
                }
            }
        } else if (EcologyChannelTypeEnum.TIKTOK.equals(channelTypeEnum)) {
            // 抖音券不能超过 1 小时（3600秒）
            if (redeemDate.getTime() + 3600_000 < System.currentTimeMillis()) {
                return true;
            }
        }

        return false;
    }

    /**
     * 通过非码订单号查询三方券信息
     * <pre></pre>
     * @param partnerId
     * @param orderCode
     * @return
     */
    @Nullable
    public ThirdCouponDto getCoupon(String partnerId, String orderCode) {
        RedeemReportQueryRequest request = new RedeemReportQueryRequest();
        request.setPartnerId(partnerId);
        request.setOrderCode(orderCode);
        SaasResponse<SaasPageResponse<RedeemReportQueryResponse>> saasResponse = couponBackstageClient.queryCodesInfo(request);
        ApiLog.infoMessage("查询券码服务:req={},resp={}", JSONObject.toJSONString(request), JSONObject.toJSONString(saasResponse));
        if (!saasResponse.getStatusCode().equals(100) || saasResponse.getResult() == null || CollectionUtils.isEmpty(saasResponse.getResult().getList())) {
            ErrorLog.errorDev("查询券码服务失败");
            return null;
        }
        Optional<RedeemReportQueryResponse> first = saasResponse.getResult().getList().stream()
                .filter(resp -> ThirdCouponReportTypeEnum.REDEEM.getType().equals(resp.getRedeemType()) && ThirdCouponReportStatusEnum.SUCCESS.getStatus().equals(resp.getRedeemStatus()))
                .findFirst();
        if (!first.isPresent()) {
            ErrorLog.errorDev("查询券码服务失败，无核销记录");
            return null;
        }
        RedeemReportQueryResponse redeemReport = first.get();
        List<String> couponCodes = Arrays.asList(redeemReport.getCouponCode().split(","));

        boolean canceled = saasResponse.getResult().getList().stream()
                .anyMatch(resp -> ThirdCouponReportTypeEnum.REVERSE.getType().equals(resp.getRedeemType()) && ThirdCouponReportStatusEnum.SUCCESS.getStatus().equals(resp.getRedeemStatus()));
        ThirdCouponDto thirdCouponDto = new ThirdCouponDto();
        thirdCouponDto.setCouponCodes(couponCodes);
        thirdCouponDto.setCanceled(canceled);
        thirdCouponDto.setPartnerId(redeemReport.getPartnerId());
        thirdCouponDto.setStoreId(redeemReport.getStoreId());
        thirdCouponDto.setMemberId(redeemReport.getMemberId());
        thirdCouponDto.setChannel(redeemReport.getChannel());
        thirdCouponDto.setRedeemTime(redeemReport.getRedeemTime());
        if (CouponThirdChannelEnum.MEI_TUAN.getChannel().equals(redeemReport.getChannel())) {
            thirdCouponDto.setEcologyChannelType(EcologyChannelTypeEnum.MEITUAN);
        } else if (CouponThirdChannelEnum.DOU_YIN.getChannel().equals(redeemReport.getChannel())) {
            // 未知渠道的为早期对接抖音时的数据，默认为抖音渠道
            thirdCouponDto.setEcologyChannelType(EcologyChannelTypeEnum.TIKTOK);
        }

        return thirdCouponDto;

    }

    /**
     * 三方券支付冲正
     * <pre></pre>
     * @param request
     * @param orderBean
     */
    public void thirdCouponRefund(String partnerId, String orderCode, String operator) {
        ThirdCouponOrderHandle.ThirdCouponDto coupon = this.getCoupon(partnerId, orderCode);
        if (coupon == null) {
            throw new RuntimeException("三方券信息查询失败，请重试");
        }
        if (coupon.isCanceled()) {
            return;
        }
        if (ThirdCouponOrderHandle.isCancelTimeout(coupon, null)) {
            throw new RuntimeException("核销时间超过可冲正期限，撤销核销失败");
        }
        // 美团、抖音平台三方券
        if (coupon.getEcologyChannelType() != null) {
            CancelRedeemCouponRequest req = new CancelRedeemCouponRequest();
            req.setTxn(orderCode);
            req.setStoreId(coupon.getStoreId());
            req.setMemberId(coupon.getMemberId());
            req.setPartnerId(coupon.getPartnerId());
            req.setChannel(coupon.getEcologyChannelType().getVal());
            req.setOperator(operator);
            coupon.getCouponCodes().forEach(code -> {
                req.setCode(code);
                Result<CancelRedeemCouponResponse> result = ecologyAdapterClient.couponCancel(req);
                ApiLog.infoMessage("冲正三方券:req:{},resp:{}", JSONObject.toJSONString(req), JSONObject.toJSONString(result));
                if (!result.isStatus()) {
                    throw new RuntimeException("撤销核销失败，请重试");
                }
                if (result.getResult().getCancelResult().equals(CancelRedeemCouponResponse.Result.TIME_LIMITED)) {
                    throw new RuntimeException("核销时间超过可冲正期限，撤销核销失败");
                }
                if (!result.getResult().getCancelResult().equals(CancelRedeemCouponResponse.Result.SUCCESS)) {
                    throw new RuntimeException("撤销核销失败，请重试");
                }
            });
        }

        try {
            // 记录冲正明细
            ReverseThirdCouponRedeemReportReq couponRequest = new ReverseThirdCouponRedeemReportReq();
            couponRequest.setPartnerId(coupon.getPartnerId());
            couponRequest.setChannel(coupon.getChannel());
            couponRequest.setOrderCode(orderCode);
            couponRequest.setRedeemStatus(ThirdCouponReportStatusEnum.SUCCESS.getStatus());
            SaasResponse<Object> reverseResp = couponOfflineClient.reverseThirdCouponRedeemReport(couponRequest);
            ApiLog.infoMessage("冲正三方券记录明细:req:{},resp:{}", JSONObject.toJSONString(couponRequest), JSONObject.toJSONString(reverseResp));
        } catch (Exception e) {
            ErrorLog.errorDev("冲正三方券记录明细异常:", e, e.getMessage());
        }
    }

    @Data
    public static class ThirdCouponDto {
        /**
         * 券渠道
         */
        private Short channel;
        /**
         * 券渠道
         */
        @Nullable
        private EcologyChannelTypeEnum ecologyChannelType;
        /**
         * 券号列表
         */
        private List<String> couponCodes;
        /**
         * 是否已冲正订单
         */
        private boolean canceled;

        /**
         * 商户号
         */
        private String partnerId;

        /**
         * 核销门店 id
         */
        private String storeId;

        /**
         * 会员 id
         */
        private String memberId;

        /**
         * 核销或冲正时间
         */
        private Date redeemTime;
    }
}
