package cn.freemud.handler;

import cn.freemud.base.entity.BaseResponse;
import cn.freemud.base.util.DateUtil;
import cn.freemud.constant.RedisKeyConstant;
import cn.freemud.entities.dto.order.CreatePrepayRequestDto;
import cn.freemud.entities.dto.wechat.GetAuthorizerRequestDto;
import cn.freemud.entities.dto.wechat.GetTokenResponseDto;
import cn.freemud.entities.live.WeChatReportVO;
import cn.freemud.entities.vo.CreateOrderResponseVo;
import cn.freemud.enums.ResponseResult;
import cn.freemud.interceptor.ServiceException;
import cn.freemud.redis.RedisCache;
import cn.freemud.service.thirdparty.EcologyAdminApplicationClient;
import cn.freemud.utils.AppLogUtil;
import cn.freemud.utils.ResponseUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.freemud.application.sdk.api.ordercenter.entities.v1.OrderBeanV1;
import com.freemud.application.sdk.api.ordercenter.entities.v1.ProductBeanV1;
import com.freemud.application.sdk.api.ordercenter.enums.MarketTypeEnum;
import com.freemud.thirdparty.wechat.WeChatClient;
import com.freemud.thirdparty.wechat.constant.WeChatConstant;
import com.freemud.thirdparty.wechat.entities.WeChatBaseResponse;
import com.freemud.thirdparty.wechat.entities.vo.NullFieldVo;
import com.freemud.thirdparty.wechat.entities.vo.request.OrderCreateRequestVO;
import com.freemud.thirdparty.wechat.entities.vo.request.OrderDeliverySendRequestVO;
import com.freemud.thirdparty.wechat.entities.vo.request.OrderSycnPayRequestVO;
import com.freemud.thirdparty.wechat.entities.vo.response.OrderCreateResponseVO;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author : xh.Z
 * @email : fisherman0510@163.com
 * @Date : 2021/11/16 上午11:25
 * @description :  微信直播 卖券商品 数据处理
 */
@Component
public class WeChatLiveMsgHandle {

    @Value("${wechat.live.order.path:}")
    private String path;

    @Value("${wechat.live.order.product.path:}")
    private String productPath;

    @Autowired
    private EcologyAdminApplicationClient ecologyAdminApplicationClient;

    @Autowired
    private RedisCache redisCache;

    private List<String> refresList = Arrays.asList("42001", "40001");

    /**
     * @param orderBean
     * @param flag      1:支付成功,2:支付失败,3:用户取消,4:超时未支付;5:商家取消;10:其他原因取消
     */
    public void reportOrderStatus(OrderBeanV1 orderBean, int flag) {
        if (Objects.nonNull(orderBean)
                && Objects.equals(orderBean.getMarketingType(), MarketTypeEnum.WE_CHAT_LIVE_SELL.getIndex())) {
            OrderSycnPayRequestVO request = new OrderSycnPayRequestVO();
            String orderId = orderBean.getOid();

            request.setOut_order_id(orderId);
            String extInfo = orderBean.getExtInfo();
            JSONObject jsonObject = JSON.parseObject(extInfo);
            if (Objects.isNull(jsonObject)) {
                return;
            }
            // 需要拿到 openid
            Object openid = jsonObject.get("openid");
            request.setOpenid(Objects.isNull(openid) ? "" : openid.toString());
            if (flag == 1) {

//                Object payTransId = jsonObject.get("payTransId");
//                request.setTransaction_id(Objects.isNull(payTransId) ? "" : payTransId.toString());
                request.setTransaction_id(orderId);

                Object payDate = jsonObject.get("payDate");
                request.setPay_time(Objects.isNull(payDate) ? "" : payDate.toString());
            }
            request.setAction_type(flag);

            // 获取 session
            String accessToken = this.getAccessToken(orderBean.getAppId(), orderBean.getParentCode());

            WeChatClient weChatClient = new WeChatClient();
            WeChatBaseResponse<NullFieldVo> weChatBaseResponse = weChatClient.orderApply(accessToken, request, WeChatConstant.OrderMethod.ORDER_PAY);

            if (refresList.contains(weChatBaseResponse.getErrcode())) {
                accessToken = this.refreshAccessToken(orderBean.getAppId(), orderBean.getParentCode());
                weChatBaseResponse = weChatClient.orderApply(accessToken, request, WeChatConstant.OrderMethod.ORDER_PAY);
            }
            AppLogUtil.printLog("视频直播订单数据上报", JSON.toJSONString(request), JSON.toJSONString(weChatBaseResponse));

            if ("0".equals(weChatBaseResponse.getErrcode())) {
                // 1 支付成功进行发货
                if (flag == 1) {
                    // 如果是支付成功, 同步发配送信息
                    OrderDeliverySendRequestVO requestVO = new OrderDeliverySendRequestVO();
                    requestVO.setOut_order_id(orderId);
                    requestVO.setOpenid(Objects.isNull(openid) ? "" : openid.toString());
                    requestVO.setFinish_all_delivery(1);
                    weChatBaseResponse = weChatClient.orderApply(accessToken, requestVO, WeChatConstant.OrderMethod.ORDER_SEND);
                    AppLogUtil.printLog("视频直播发货数据上报-发货", JSON.toJSONString(requestVO), JSON.toJSONString(weChatBaseResponse));
                }
            }
        }
    }


    /**
     * 组装 订单创建上报数据 对象
     *
     * @param createPrepayRequestDto
     * @param prepayOrder
     */
    public BaseResponse reportOrder(CreatePrepayRequestDto createPrepayRequestDto,
                                    CreateOrderResponseVo prepayOrder, String scene) {
        // 组装 request
        OrderCreateRequestVO requestVO = this.getOrderCreateRequest(createPrepayRequestDto, prepayOrder, scene);

        // 获取 session
        String accessToken = this.getAccessToken(createPrepayRequestDto.getWxAppId(), createPrepayRequestDto.getPartnerId());

        WeChatClient weChatClient = new WeChatClient();
        // fisherman 调用sdk
        WeChatBaseResponse<OrderCreateResponseVO> weChatBaseResponse = weChatClient.orderApply(accessToken, requestVO, WeChatConstant.OrderMethod.ORDER_ADD);

        if (weChatBaseResponse == null) {
            // 调用失败
            return ResponseUtil.error(ResponseResult.SYSTEM_BUSINESS_ERROR.getCode(), "错误码" + ResponseResult.SYSTEM_BUSINESS_ERROR.getCode() + "，创建视频号订单异常，请稍后再试。");
        }
        AppLogUtil.printLog("视频直播订单创建", JSON.toJSONString(requestVO), JSON.toJSONString(weChatBaseResponse));
        if ("0".equals(weChatBaseResponse.getErrcode())) {
            // 调用成功
            OrderCreateResponseVO data = weChatBaseResponse.getData();
            WeChatReportVO weChatReportVO = new WeChatReportVO(requestVO, data);
            return ResponseUtil.success(weChatReportVO);
        }

        // 处理 token失败的情况 42001 表示 accesstoken 有问题 重新调用一遍
        if (refresList.contains(weChatBaseResponse.getErrcode())) {
            String accessTokenNew = this.refreshAccessToken(createPrepayRequestDto.getWxAppId(), createPrepayRequestDto.getPartnerId());
            WeChatBaseResponse<OrderCreateResponseVO> agResponse = weChatClient.orderApply(accessTokenNew, requestVO, WeChatConstant.OrderMethod.ORDER_ADD);

            if (agResponse == null) {
                // 调用失败
                return ResponseUtil.error(ResponseResult.SYSTEM_BUSINESS_ERROR.getCode(), "错误码" + ResponseResult.SYSTEM_BUSINESS_ERROR.getCode() + "，创建视频号订单异常，请稍后再试。");
            }
            if ("0".equals(agResponse.getErrcode())) {
                // 调用成功
                OrderCreateResponseVO data = agResponse.getData();
                WeChatReportVO weChatReportVO = new WeChatReportVO(requestVO, data);
                return ResponseUtil.success(weChatReportVO);
            }
            return ResponseUtil.error(agResponse.getErrcode(), "错误码" + agResponse.getErrmsg() + "，创建视频号订单异常，请稍后再试。");

        }
        // 全部失败 直接抛出异常
        return ResponseUtil.error(weChatBaseResponse.getErrcode(), "错误码" + weChatBaseResponse.getErrmsg() + "，创建视频号订单异常，请稍后再试。");
    }

    private String refreshAccessToken(String wxAppId, String partnerId) {
        String dbAccessToken = this.getDBAccessToken(wxAppId, partnerId);
        String redisKey = RedisKeyConstant.SAAS_ACCESSTOKEN_APPID + wxAppId;
        this.putRedis(redisKey, dbAccessToken);
        return dbAccessToken;
    }

    private String getDBAccessToken(String wxAppId, String partnerId) {
        GetAuthorizerRequestDto request = new GetAuthorizerRequestDto();
        request.setAuthorizerAppid(wxAppId);
        request.setPartnerId(partnerId);
        GetTokenResponseDto authorizerAccessToken = ecologyAdminApplicationClient.getAuthorizerAccessToken(request);
        if (authorizerAccessToken == null || authorizerAccessToken.getResult() == null || StringUtils.isBlank(authorizerAccessToken.getResult().getAccessToken())) {
            throw new ServiceException(ResponseResult.SYSTEM_BUSINESS_ERROR.getCode(), "获取生态accessToken失败");
        }
        String accessToken = authorizerAccessToken.getResult().getAccessToken();
        return accessToken;
    }


    private void putRedis(String redisKey, String accessToken) {
        // 存redis  + 过期时间
        redisCache.save(redisKey, accessToken);
        redisCache.updateTTL(redisKey, 2, TimeUnit.MINUTES);
    }

    /**
     * 获取 token
     *
     * @param wxAppId
     * @param partnerId
     * @return
     */
    public String getAccessToken(String wxAppId, String partnerId) {
        String redisKey = RedisKeyConstant.SAAS_ACCESSTOKEN_APPID + wxAppId;
        Object value = redisCache.getValue(redisKey);
        // 该操作 无需关注 重入情况
        if (Objects.isNull(value)) {
            String accessToken = this.getDBAccessToken(wxAppId, partnerId);
            // 存redis  + 过期时间
            this.putRedis(redisKey, accessToken);
            return accessToken;
        }
        return value.toString();

    }

    private OrderCreateRequestVO getOrderCreateRequest(CreatePrepayRequestDto createPrepayRequestDto,
                                                       CreateOrderResponseVo prepayOrder,
                                                       String scene) {
        OrderCreateRequestVO requestVO = new OrderCreateRequestVO();
        OrderBeanV1 orderBean = createPrepayRequestDto.getProductOrderBean();

        Long gmtCreate = orderBean.getGmtCreate();
        Date createTime;
        if (gmtCreate == null) {
            createTime = new Date();
        } else {
            createTime = new Date(gmtCreate);
        }
        requestVO.setCreate_time(DateUtil.convert2Str(createTime, DateUtil.FORMAT_YYYY_MM_DD_HHMMSS));

        requestVO.setOut_order_id(orderBean.getOid());
        requestVO.setOpenid(createPrepayRequestDto.getOpenId());

        requestVO.setPath(path + orderBean.getOid());
        requestVO.setScene(Integer.valueOf(scene));

        OrderCreateRequestVO.DeliveryDetail deliveryDetail = new OrderCreateRequestVO.DeliveryDetail();
        deliveryDetail.setDelivery_type(2);
        requestVO.setDelivery_detail(deliveryDetail);

        // 组装商品参数
        OrderCreateRequestVO.OrderDetail orderDetail = this.getOrderDetail(orderBean, prepayOrder);
        requestVO.setOrder_detail(orderDetail);

        return requestVO;
    }

    private OrderCreateRequestVO.OrderDetail getOrderDetail(OrderBeanV1 orderBean, CreateOrderResponseVo prepayOrder) {
        OrderCreateRequestVO.OrderDetail detail = new OrderCreateRequestVO.OrderDetail();

        // payinfo
        OrderCreateRequestVO.PayInfo payInfo = new OrderCreateRequestVO.PayInfo();
        payInfo.setPay_method_type(0);
        payInfo.setPrepay_id(prepayOrder.getPackageX());
        String gmtCreate = prepayOrder.getTimestamp();
        payInfo.setPrepay_time(DateUtil.convert2Str(new Date(Long.parseLong(gmtCreate + "000")), DateUtil.FORMAT_YYYY_MM_DD_HHMMSS));
        detail.setPay_info(payInfo);

        // priceinfo
        OrderCreateRequestVO.PriceInfo priceInfo = new OrderCreateRequestVO.PriceInfo();
        priceInfo.setOrder_price(orderBean.getSettlementAmount());
        priceInfo.setFreight(0L);
        detail.setPrice_info(priceInfo);

        // list productinfo
        List<ProductBeanV1> productList = orderBean.getProductList();
        List<OrderCreateRequestVO.ProductInfo> productInfos = new ArrayList<>(productList.size());
        productList.forEach(p -> {
            OrderCreateRequestVO.ProductInfo productInfo = new OrderCreateRequestVO.ProductInfo();
            productInfo.setOut_product_id(p.getProductId());
            productInfo.setOut_sku_id(p.getProductId());
            productInfo.setProduct_cnt(p.getNumber());
            productInfo.setSale_price(p.getSalePrice());
            productInfo.setReal_price(p.getSalePrice());
            productInfo.setHead_img(p.getPicture());
            productInfo.setTitle(p.getProductName());
            // fisherman 虚拟商品的 path 未知
            productInfo.setPath(productPath + p.getProductId());

            productInfos.add(productInfo);
        });
        detail.setProduct_infos(productInfos);
        return detail;
    }
}
