package com.liquidnet.service.dragon.channel.strategy.biz;

import com.alibaba.fastjson.JSON;
import com.liquidnet.commons.lang.util.BeanUtil;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.dragon.bo.PayNotifyReqBo;
import com.liquidnet.service.dragon.constant.DragonConstant;
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.PayNotifyDto;
import com.liquidnet.service.dragon.entity.DragonOrders;
import com.liquidnet.service.dragon.utils.DataUtils;
import com.liquidnet.service.dragon.utils.MqHandleUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @author AnJiabin <anjiabin@zhengzai.tv>
 * @version V1.0
 * @Description: TODO
 * @class: DragonPayBiz
 * @Package com.liquidnet.service.dragon.channel.strategy.biz
 * @Copyright: LightNet @ Copyright (c) 2021
 * @date 2021/7/14 14:12
 */
@Slf4j
@Component
public class DragonPayBiz {
    @Autowired
    private MqHandleUtil mqHandleUtil;

    @Autowired
    private DataUtils dataUtils;

    public DragonOrders buildPayOrders(DragonPayBaseReqDto dragonPayBaseReqDto, DragonPayBaseRespDto respDto){
        //构造订单
        DragonOrders orders = new DragonOrders();
//        orders.setMid();
        orders.setOrderId(IDGenerator.nextTimeId());
        orders.setStatus(Integer.valueOf(DragonConstant.PayStatusEnum.STATUS_UNPAID.getCode()));
        orders.setCode(respDto.getCode());
        orders.setType(dragonPayBaseReqDto.getType());
        orders.setPrice(dragonPayBaseReqDto.getPrice());
        orders.setName(dragonPayBaseReqDto.getName());
        orders.setDetail(dragonPayBaseReqDto.getDetail());
        orders.setOrderCode(dragonPayBaseReqDto.getOrderCode());
        orders.setClientIp(dragonPayBaseReqDto.getClientIp());
        orders.setNotifyUrl(dragonPayBaseReqDto.getNotifyUrl());
        orders.setPaymentType((dragonPayBaseReqDto.getDeviceFrom()+dragonPayBaseReqDto.getPayType()).toUpperCase());
//        orders.setPaymentId();
        orders.setPaymentAt(LocalDateTime.now());
//        orders.setFinishedAt();
        orders.setCreatedAt(LocalDateTime.now());
//        orders.setUpdatedAt();

        DragonOrdersDto ordersDto = new DragonOrdersDto();
        BeanUtil.copy(orders,ordersDto);
        //放到redis缓存中
        dataUtils.createPayOrder(orders.getCode(),ordersDto);
        // 持久化到数据库
        boolean insertResult = mqHandleUtil.sendMySqlRedis(
                SqlMapping.get("dragon_orders.insert"),
                new Object[]{orders.getOrderId(),orders.getStatus(), orders.getCode(), orders.getType()
                        , orders.getPrice(), orders.getName(), orders.getDetail()
                        , orders.getOrderCode(), orders.getClientIp()
                        , orders.getNotifyUrl(), orders.getPaymentType(),
                        orders.getPaymentId(), orders.getPaymentAt()
                        , orders.getFinishedAt(), orders.getCreatedAt()
                        , orders.getUpdatedAt(),orders.getDeletedAt()}
                        ,DragonConstant.MysqlRedisQueueEnum.DRAGON_PAY_KEY.getCode()
        );
        return orders;
    }

    /**
     * 更新支付状态
     * @param code
     * @param paymentId
     * @return
     */
    public boolean updateOrderStatus(String code,Integer status,String paymentId){
        try {
            LocalDateTime finishedAt = LocalDateTime.now();
            LocalDateTime updateAt = LocalDateTime.now();
            //t.status = ?  ,t.payment_id = ?,t.finished_at = ?,t.updated_at =? where t.code = ?
            boolean insertResult = mqHandleUtil.sendMySqlRedis(
                    SqlMapping.get("dragon_orders.updateOrderStatus"),
                    new Object[]{status,paymentId,finishedAt, updateAt,code}
                    ,DragonConstant.MysqlRedisQueueEnum.DRAGON_PAY_KEY.getCode()
            );
            if(insertResult) return true;
        } catch (Exception e) {
            log.error("dragon:updateDragonOrderStatus:error msg:{}",e);
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 更新支付通知状态
     * @param code
     * @return
     */
    public boolean updateNotifyStatus(String code,Integer status){
        try {
            LocalDateTime updateAt = LocalDateTime.now();
            //update dragon_orders t set t.notify_status = ? ,t.updated_at =? where t.code = ?
            boolean insertResult = mqHandleUtil.sendMySqlRedis(
                    SqlMapping.get("dragon_orders.updateNotifyStatus"),
                    new Object[]{status,updateAt,code}
                    ,DragonConstant.MysqlRedisQueueEnum.DRAGON_PAY_KEY.getCode()
            );
            if(insertResult) return true;
        } catch (Exception e) {
            log.error("dragon:updateNotifyStatus:error msg:{}",e);
            e.printStackTrace();
        }
        return false;
    }

     public PayNotifyReqBo buildPayNotifyReqBo(DragonOrdersDto dragonOrdersDto){
        PayNotifyReqBo payNotifyReqBo = new PayNotifyReqBo();
        payNotifyReqBo.setNotifyUrl(dragonOrdersDto.getNotifyUrl());
        PayNotifyDto payNotifyDto = new PayNotifyDto();
        payNotifyDto.setStatus(dragonOrdersDto.getStatus());
        payNotifyDto.setType(dragonOrdersDto.getType());
        payNotifyDto.setCode(dragonOrdersDto.getCode());
        payNotifyDto.setPaymentId(dragonOrdersDto.getPaymentId());
        payNotifyDto.setOrderCode(dragonOrdersDto.getOrderCode());
        payNotifyDto.setPrice(dragonOrdersDto.getPrice());
        payNotifyDto.setPaymentType(dragonOrdersDto.getPaymentType());
        payNotifyReqBo.setPayNotifyDto(payNotifyDto);
        return payNotifyReqBo;
    }

    /**
     * 三方异步通知入库
     * @param paymentType
     * @param content
     */
    public void createDragonOrderLogs(String code,String paymentType,String content){
        try {
            String orderId = IDGenerator.nextTimeId();
            LocalDateTime createAt = LocalDateTime.now();
            LocalDateTime updateAt = null;
            LocalDateTime deleteAt = null;
            boolean insertResult = mqHandleUtil.sendMySqlRedis(
                    SqlMapping.get("dragon_order_logs.insert"),
                    new Object[]{code,paymentType,content, createAt, updateAt,deleteAt}
                    ,DragonConstant.MysqlRedisQueueEnum.DRAGON_PAY_NOTIFY_KEY.getCode()
            );
        } catch (Exception e) {
            log.error("dragon:createOrderLog:error msg:{}",e);
            e.printStackTrace();
        }
    }

    /**
     * 商户异步通知入库
     * @param payNotifyReqBo
     * @param notifyParam
     */
    public void createDragonPayNotify(PayNotifyReqBo payNotifyReqBo,String notifyParam){
        PayNotifyDto payNotifyDto = payNotifyReqBo.getPayNotifyDto();
        try {
            String code = payNotifyDto.getCode();
            String orderCode = payNotifyDto.getOrderCode();
            String notifyUrl = payNotifyReqBo.getNotifyUrl();
            String notifyData = notifyParam;
            LocalDateTime createAt = LocalDateTime.now();
            LocalDateTime updateAt = LocalDateTime.now();
            boolean insertResult = mqHandleUtil.sendMySqlRedis(
                    SqlMapping.get("dragon_pay_notify.insert"),
                    new Object[]{code,orderCode,notifyUrl,notifyData, createAt, updateAt}
                    ,DragonConstant.MysqlRedisQueueEnum.PAY_MCH_NOTIFY_KEY.getCode()
            );
            log.info("dragon:createDragonPayNotify:success code:{}",code);
        } catch (Exception e) {
            log.error("dragon:createDragonPayNotify:error msg:{}",e);
            e.printStackTrace();
        }
    }

    /**
     * 商户异步通知失败入库
     * @param payNotifyReqBo
     * @param notifyParam
     */
    public void createDragonPayNotifyFail(PayNotifyReqBo payNotifyReqBo,String notifyParam){
        PayNotifyDto payNotifyDto = payNotifyReqBo.getPayNotifyDto();
        try {
            String code = payNotifyDto.getCode();
            String orderCode = payNotifyDto.getOrderCode();
            String notifyUrl = payNotifyReqBo.getNotifyUrl();
            String notifyData = notifyParam;
            String failDesc = "通知失败";
            LocalDateTime createAt = LocalDateTime.now();
            LocalDateTime updateAt = LocalDateTime.now();
            boolean insertResult = mqHandleUtil.sendMySqlRedis(
                    SqlMapping.get("dragon_pay_notify_fail.insert"),
                    new Object[]{code,orderCode,notifyUrl,notifyData,failDesc,createAt, updateAt}
                    ,DragonConstant.MysqlRedisQueueEnum.PAY_MCH_NOTIFY_ERROR_KEY.getCode()
            );
            log.info("dragon:createDragonPayNotifyFail:success code:{}",code);
        } catch (Exception e) {
            log.error("dragon:createDragonPayNotifyFail:error msg:{}",e);
            e.printStackTrace();
        }
    }


//    public void sendNotifyBackup(PayNotifyReqBo payNotifyReqBo){
//        PayNotifyDto payNotifyDto = payNotifyReqBo.getPayNotifyDto();
//        LocalDateTime nowTime = LocalDateTime.now();
//        MultiValueMap<String, String> params = new LinkedMultiValueMap();
//        params.add("status", payNotifyDto.getStatus().toString());
//        params.add("type", payNotifyDto.getType());
//        params.add("code", payNotifyDto.getCode());
//        params.add("paymentId", payNotifyDto.getPaymentId());
//        params.add("orderCode", payNotifyDto.getOrderCode());
//        params.add("price", payNotifyDto.getPrice().toString());
//        params.add("paymentType", payNotifyDto.getPaymentType());
//        String jsonData = JSON.toJSONString(params);
//        log.info("dragon:notify:post url:{}",payNotifyReqBo.getNotifyUrl());
//        log.info("dragon:notify:post data:{}",jsonData);
//        try {
//            String response = HttpUtil.post(payNotifyReqBo.getNotifyUrl(), params);
//            log.debug("PAY RESPONSE=" + response);
//            if (response.equals("success")) {
//                this.createDragonPayNotify(payNotifyReqBo,jsonData);
//                //更新通知状态-通知成功
//                this.updateNotifyStatus(payNotifyDto.getCode(),Integer.valueOf(DragonConstant.PayStatusEnum.STATUS_SUCCESS.getCode()));
//            } else {
//                this.createDragonPayNotifyFail(payNotifyReqBo,jsonData);
//                //更新通知状态-通知失败
//                this.updateNotifyStatus(payNotifyDto.getCode(),Integer.valueOf(DragonConstant.PayStatusEnum.STATUS_FAIL.getCode()));
//            }
//
//            if(true){
//                throw new ConnectTimeoutException();
//            }
//        } catch (ConnectTimeoutException e) {
//            System.out.println("请求超时");
//
//        }catch (Exception e){
//            e.printStackTrace();
//        }
//    }
    public void sendNotify(PayNotifyReqBo payNotifyReqBo){
        PayNotifyDto payNotifyDto = payNotifyReqBo.getPayNotifyDto();
        LocalDateTime nowTime = LocalDateTime.now();
        CloseableHttpClient httpclient = HttpClients.createDefault();
        String jsonData = "";
        try {
            HttpPost httpPost = new HttpPost(payNotifyReqBo.getNotifyUrl());
            //配置超时
            RequestConfig requestConfig = RequestConfig.custom()
                    .setConnectTimeout(5000).setConnectionRequestTimeout(5000)
                    .setSocketTimeout(5000).build();
            httpPost.setConfig(requestConfig);

            //设置post请求参数
            List<NameValuePair> nvps = new ArrayList<NameValuePair>();
            nvps.add(new BasicNameValuePair("status", payNotifyDto.getStatus().toString()));
            nvps.add(new BasicNameValuePair("type", payNotifyDto.getType()));
            nvps.add(new BasicNameValuePair("code", payNotifyDto.getCode()));
            nvps.add(new BasicNameValuePair("paymentId", payNotifyDto.getPaymentId()));
            nvps.add(new BasicNameValuePair("orderCode", payNotifyDto.getOrderCode()));
            nvps.add(new BasicNameValuePair("price", payNotifyDto.getPrice().toString()));
            nvps.add(new BasicNameValuePair("paymentType", payNotifyDto.getPaymentType()));
            jsonData = JSON.toJSONString(nvps);
            log.info("dragon:notify:post url:{}",payNotifyReqBo.getNotifyUrl());
            log.info("dragon:notify:post data:{}",jsonData);
            httpPost.setEntity(new UrlEncodedFormEntity(nvps));

            //执行post请求
            CloseableHttpResponse responseObj = httpclient.execute(httpPost);
            String response = EntityUtils.toString(responseObj.getEntity(), "utf-8");
            log.debug("PAY RESPONSE=" + response);
            if (response.equals("success")) {
                this.createDragonPayNotify(payNotifyReqBo,jsonData);
                //更新通知状态-通知成功
                this.updateNotifyStatus(payNotifyDto.getCode(),Integer.valueOf(DragonConstant.PayNotifyStatusEnum.NOTIFY_SUCCESS.getCode()));
            } else {
                this.createDragonPayNotifyFail(payNotifyReqBo,jsonData);
                //更新通知状态-通知失败
                this.updateNotifyStatus(payNotifyDto.getCode(),Integer.valueOf(DragonConstant.PayNotifyStatusEnum.NOTIFY_FAIL.getCode()));
            }

        } catch (ConnectTimeoutException e) {
            log.error("dragon:sendNotify 请求超时",e);
            this.createDragonPayNotifyFail(payNotifyReqBo,jsonData);
            //更新通知状态-通知失败
            this.updateNotifyStatus(payNotifyDto.getCode(),Integer.valueOf(DragonConstant.PayNotifyStatusEnum.NOTIFY_EXPIRE.getCode()));

        } catch (Exception e) {
            log.error("dragon:sendNotify 请求失败",e);
            this.createDragonPayNotifyFail(payNotifyReqBo,jsonData);
            //更新通知状态-通知失败
            this.updateNotifyStatus(payNotifyDto.getCode(),Integer.valueOf(DragonConstant.PayNotifyStatusEnum.NOTIFY_FAIL.getCode()));

        }finally {
            //释放连接
            try {
                if (httpclient != null) {
                    httpclient.close();
                }
            } catch (IOException e) {
                log.error("连接无法关闭",e);
            }
        }
    }

    public String getPaymentType(String payType,String deviceFrom){
        return (deviceFrom+payType).toUpperCase();
    }
}
