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.ResponseUtil;
import com.freemud.application.sdk.api.ordercenter.entities.v1.OrderBeanV1;
import com.freemud.application.sdk.api.ordercenter.entities.v1.ProductBeanV1;
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.request.OrderCreateRequestVO;
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.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
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;

    @Autowired
    private EcologyAdminApplicationClient ecologyAdminApplicationClient;

    @Autowired
    private RedisCache redisCache;

    /**
     * 组装 订单创建上报数据 对象
     *
     * @param createPrepayRequestDto
     * @param prepayOrder
     */
    public BaseResponse reportOrder(CreatePrepayRequestDto createPrepayRequestDto,
                                    CreateOrderResponseVo prepayOrder, String scene, String productPath) {

        // 组装 request
        OrderCreateRequestVO requestVO = this.getOrderCreateRequest(createPrepayRequestDto, prepayOrder, scene, productPath);

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

        WeChatClient weChatClient = new WeChatClient();
        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() + "，创建视频号订单异常，请稍后再试。");
        }
        if ("0".equals(weChatBaseResponse.getErrcode())) {
            // 调用成功
            OrderCreateResponseVO data = weChatBaseResponse.getData();
            WeChatReportVO weChatReportVO = new WeChatReportVO(requestVO, data);
            return ResponseUtil.success(weChatReportVO);
        }

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

            if (weChatBaseResponse == null) {
                // 调用失败
                return ResponseUtil.error(ResponseResult.SYSTEM_BUSINESS_ERROR.getCode(), "错误码" + ResponseResult.SYSTEM_BUSINESS_ERROR.getCode() + "，创建视频号订单异常，请稍后再试。");
            }
            if ("0".equals(weChatBaseResponse.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.setAdd(redisKey, accessToken);
        redisCache.updateTTL(redisKey, 2, TimeUnit.HOURS);
    }

    /**
     * 获取 token
     *
     * @param wxAppId
     * @param partnerId
     * @return
     */
    private 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,
                                                       String productPath) {
        OrderCreateRequestVO requestVO = new OrderCreateRequestVO();
        OrderBeanV1 orderBean = createPrepayRequestDto.getProductOrderBean();

        Long gmtCreate = orderBean.getGmtCreate();
        requestVO.setCreate_time(DateUtil.convert2Str(new Date(gmtCreate), DateUtil.FORMAT_YYYY_MM_DD_HHMMSS));

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

        requestVO.setPath(path);
        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, productPath);
        requestVO.setOrder_detail(orderDetail);

        return requestVO;
    }

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

        // payinfo
        OrderCreateRequestVO.PayInfo payInfo = new OrderCreateRequestVO.PayInfo();
        payInfo.setPay_method_type(0);
        payInfo.setPrepay_id(prepayOrder.getPayId());
        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);

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