package com.liquidnet.service.dragon.channel.douyinpay.strategy.impl;

import com.alibaba.fastjson.JSON;
import com.liquidnet.common.exception.LiquidnetServiceException;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.dragon.biz.DragonServiceCommonBiz;
import com.liquidnet.service.dragon.channel.douyinpay.biz.DouYinPayBiz;
import com.liquidnet.service.dragon.channel.douyinpay.constant.DouYinpayConstant;
import com.liquidnet.service.dragon.channel.douyinpay.strategy.IDouYinpayStrategy;
import com.liquidnet.service.dragon.channel.strategy.biz.DragonPayBiz;
import com.liquidnet.service.dragon.channel.wepay.biz.WepayBiz;
import com.liquidnet.service.dragon.channel.wepay.constant.WepayConstant;
import com.liquidnet.service.dragon.channel.wepay.resp.WepayPayRespDto;
import com.liquidnet.service.dragon.channel.wepay.strategy.IWepayStrategy;
import com.liquidnet.service.dragon.constant.DragonConstant;
import com.liquidnet.service.dragon.constant.DragonErrorCodeEnum;
import com.liquidnet.service.dragon.dto.DragonOrdersDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseReqDto;
import com.liquidnet.service.dragon.dto.DragonPayBaseRespDto;
import com.liquidnet.service.dragon.dto.DragonPayOrderQueryRespDto;
import com.liquidnet.service.dragon.utils.DataUtils;
import com.liquidnet.service.dragon.utils.PayDouYinpayUtils;
import com.liquidnet.service.dragon.utils.PayWepayUtils;
import com.liquidnet.service.dragon.utils.XmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import springfox.documentation.spring.web.json.Json;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * @author zhangfuxin
 * @Description:  抖音支付的抽象类
 * @date 2021/11/9 下午1:41
 */
@Slf4j
public abstract class AbstractDouYinPayStrategy implements IDouYinpayStrategy {
    // 订单过期时间(秒); 最小 15 分钟，最大两天
    private int valid_time=60*60*24*2;
    @Autowired
    private DouYinPayBiz douYinPayBiz;

    @Autowired
    private DataUtils dataUtils;

    @Autowired
    private DragonServiceCommonBiz dragonServiceCommonBiz;

    @Autowired
    private DragonPayBiz dragonPayBiz;

    @Override
    public ResponseDto<DragonPayBaseRespDto> dragonPay(DragonPayBaseReqDto dragonPayBaseReqDto) {
        long startTimeTotal = System.currentTimeMillis();
        long startTime = System.currentTimeMillis();
        try {
            //构造请求参数
            SortedMap<String, Object> commonParams = this.buildRequestParamMap(dragonPayBaseReqDto);
            //追加请求参数
            SortedMap<String, Object> parameters = this.appendRequestParam(commonParams,dragonPayBaseReqDto);
            //生成签名
            String sign = PayDouYinpayUtils.getInstance().createSign(parameters);
            parameters.put("sign", sign);
            //map转string
            String data = JSON.toJSONString(parameters);
            log.info("dragonPay:douYinPay:"+dragonPayBaseReqDto.getDeviceFrom()+" request jsondata: {} ",data);
            HttpPost httpost = new HttpPost(this.getRequestUrl());
            httpost.setEntity(new StringEntity(data, "UTF-8"));
            startTime = System.currentTimeMillis();
            CloseableHttpClient httpClient = PayDouYinpayUtils.getInstance().getHttpClient();
            log.info("douYinPay-->request--> getHttpClient耗时:{}",(System.currentTimeMillis() - startTime)+"毫秒");
            startTime = System.currentTimeMillis();
            CloseableHttpResponse response = httpClient.execute(httpost);
            log.info("douYinPay-->request--> execute耗时:{}",(System.currentTimeMillis() - startTime)+"毫秒");
            HttpEntity entity = response.getEntity();
            //接收到返回信息
            String json = EntityUtils.toString(response.getEntity(), "UTF-8");
            EntityUtils.consume(entity);
            log.info("dragonPay:douYinPay:"+dragonPayBaseReqDto.getDeviceFrom()+" response jsonStr: {} ",json);
            //拼接返回参数
            DragonPayBaseRespDto respDto = buildCommonRespDto(dragonPayBaseReqDto);
            Map result=JSON.parseObject(json, HashMap.class);
            if(DouYinpayConstant.DouYinTradeStateEnum.SUCCESS.getCode().equals(result.get("err_no").toString())){
                //成功
                respDto = this.buildResponseDto(respDto,result);
                //支付订单持久化
                dragonServiceCommonBiz.buildPayOrders(dragonPayBaseReqDto,respDto);
                log.info("douYinpay-->dragonPay--> 耗时:{}",(System.currentTimeMillis() - startTimeTotal)+"毫秒");
                return ResponseDto.success(respDto);
            }else {
                throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_PARAM_ERROR.getCode(),DragonErrorCodeEnum.TRADE_PARAM_ERROR.getMessage());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 构造公共返回参数
     * @param dragonPayBaseReqDto
     * @return
     */
    protected DragonPayBaseRespDto buildCommonRespDto(DragonPayBaseReqDto dragonPayBaseReqDto){
        DragonPayBaseRespDto respDto = new DragonPayBaseRespDto();
        respDto.setCode(dragonPayBaseReqDto.getCode());
        respDto.setOrderCode(dragonPayBaseReqDto.getOrderCode());
        DragonPayBaseRespDto.PayData payData = new DragonPayBaseRespDto.PayData();
        respDto.setPayData(payData);
        return respDto;
    }

    /**
     * 构造请求参数
     * @return
     */
    protected SortedMap<String, Object> buildRequestParamMap(DragonPayBaseReqDto dragonPayBaseReqDto){
        SortedMap<String, Object> parameters = new TreeMap<>();
        parameters.put("total_amount", dragonPayBaseReqDto.getPrice().multiply(BigDecimal.valueOf(100L)).intValue());
        //商品描述; 长度限制 128 字节，不超过 42 个汉字
        parameters.put("subject", dragonPayBaseReqDto.getName());
        //商品详情
        parameters.put("body", dragonPayBaseReqDto.getDetail());
        //开发者侧的订单号, 同一小程序下不可重复
        parameters.put("out_order_no", dragonPayBaseReqDto.getCode());
        parameters.put("notify_url", this.getNotifyUrl());
        //订单过期时间(秒); 最小 15 分钟，最大两天
        parameters.put("valid_time",Integer.parseInt(dragonPayBaseReqDto.getExpireTime())*60);
        return parameters;
    };

    /**
     * 追加请求参数
     * @param requestMap
     * @return
     */
    abstract SortedMap<String, Object> appendRequestParam(SortedMap<String, Object> requestMap,DragonPayBaseReqDto dragonPayBaseReqDto);

    /**
     * 构造返回参数
     */
    abstract DragonPayBaseRespDto buildResponseDto(DragonPayBaseRespDto payBaseRespDto,Map result);

    /**
     * 获取请求url
     * @return
     */
    protected abstract String getRequestUrl();

    /**
     * 设置notifyUrl
     */
    protected abstract String getNotifyUrl();

    @Override
    public DragonPayOrderQueryRespDto checkOrderStatus(String code) {
        DragonOrdersDto ordersDto = dataUtils.getPayOrderByCode(code);
        Map<String, Object> resultMaps = douYinPayBiz.tradeQuery(code,this.getAppid());
        DragonPayOrderQueryRespDto respDto = dragonPayBiz.buildPayOrderQueryRespDto(ordersDto);
        Map<String, Object> resultMap= (Map<String, Object>) resultMaps.get("payment_info");
        Object orderStatus = resultMap.get("order_status");
      /*  // 查询失败
        if (null == orderStatus || "FAIL".equals(orderStatus)) {
            throw new LiquidnetServiceException(DragonErrorCodeEnum.TRADE_DOUYINPAY_QUERY_ERROR.getCode(),DragonErrorCodeEnum.TRADE_DOUYINPAY_QUERY_ERROR.getMessage());
        }*/
        // 当trade_state为SUCCESS时才返回result_code
        if ("SUCCESS".equals(orderStatus)) {
            respDto.setStatus(Integer.valueOf(DragonConstant.PayStatusEnum.STATUS_PAID.getCode()));
        }else {
            respDto.setStatus(Integer.valueOf(DragonConstant.PayStatusEnum.STATUS_PAY_FAIL.getCode()));
        }
        return respDto;
    }

    protected abstract String getAppid();
}
