package cn.pluss.platform.leshua.impl;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.*;

import cn.pluss.platform.dto.RealFansDTO;
import cn.pluss.platform.entity.*;
import cn.pluss.platform.exception.MsgException;
import cn.pluss.platform.leshua.*;
import cn.pluss.platform.mapper.MerchantOrderMapper;
import cn.pluss.platform.mapper.UserAppMapper;
import cn.pluss.platform.systemConfig.SystemConfigService;
import cn.pluss.platform.util.*;
import cn.pluss.platform.vo.MerchantOrderVO;
import cn.pluss.platform.wap.MerchantLeshuaDTO;
import cn.pluss.platform.wap.XmlUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;

import cn.pluss.platform.api.Result;
import cn.pluss.platform.api.ResultGenerator;
import cn.pluss.platform.mapper.SystemConfigMapper;
import cn.pluss.platform.merchant.MerchantBaseInfoService;

import javax.servlet.http.HttpServletRequest;

/**
 * @author yuchen
 * 
 * @Description
 */
@RequiredArgsConstructor
@Service("leshuaService")
public class LeshuaServiceImpl implements LeshuaService {

    private static final Logger logger = LoggerFactory.getLogger(LeshuaServiceImpl.class);

    /**
     *
     */
    private CloseableHttpClient httpclient = HttpClients.createDefault();

    HttpClientHelper httpClientHelper = new HttpClientHelper();


    private final SystemConfigMapper systemConfigMapper;

    private final MerchantBaseInfoService merchantBaseInfoService;

    private final UserAppMapper userAppMapper;


    private final SystemConfigService systemConfigService;

    private final MerchantOrderMapper merchantOrderMapper;


    /**
     * 进件调用请求(不上传图片)
     *
     * @param url  地址
     * @param data 数据
     * @return
     */
    @Override
    public Result<Object> requestApi(String url, JSONObject data) {
        return requestApi(url, data, null);
    }


    /**
     * 进件调用请求调用请求上传图片
     *
     * @param url      地址
     * @param data     数据
     * @param pictures 图片
     * @return
     */
    @Override
    public Result<Object> requestApi(String url, JSONObject data, Map<String, File> pictures) {
        logger.info("请求地址:{}" + url);
        logger.info("请求参数:{}" + data);
        String sign = getSign(data);// 获取签名值
        String result = "";
        HttpPost httppost = new HttpPost(url);
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
        multipartEntityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        multipartEntityBuilder.setCharset(Charset.forName("UTF-8"));
        multipartEntityBuilder.addPart("agentId", new StringBody("7389852", ContentType.APPLICATION_JSON));// 代理商编号
        multipartEntityBuilder.addPart("version", new StringBody("2.0", ContentType.APPLICATION_JSON));// 版本
        SimpleDateFormat dateFm = new SimpleDateFormat("yyyyMMddHHmmssSSS");
        String reqSerialNo = dateFm.format(new Date()) + StringUtil.genRandomNum(5);
        multipartEntityBuilder.addPart("reqSerialNo", new StringBody(reqSerialNo, ContentType.APPLICATION_JSON));// 请求流水号
        multipartEntityBuilder.addPart("data", new StringBody(data.toJSONString(), ContentType.APPLICATION_JSON));// 数据内容
        multipartEntityBuilder.addPart("sign", new StringBody(sign, ContentType.APPLICATION_JSON));// 签名值
        if (pictures != null) {// 图片文件
            for (String picName : pictures.keySet()) {
                multipartEntityBuilder.addPart(picName, new FileBody(pictures.get(picName)));
            }
        }
        HttpEntity reqEntity = multipartEntityBuilder.build();
        httppost.setEntity(reqEntity);
        try {
            CloseableHttpResponse response = httpclient.execute(httppost);
            logger.info(response + "");
            HttpEntity resEntity = response.getEntity();
            if (resEntity != null) {
                result = EntityUtils.toString(resEntity, "UTF-8");
            }
        } catch (IOException e) {
            logger.error("Exception:{}", e);
        }
        logger.info("返回参数:{}" + result);
        Result<Object> r = JSONObject.parseObject(result, new TypeReference<Result<Object>>() {
        });
        return r;
    }

    /**
     * 进件获取签名值
     *
     * @param data
     * @return
     */
    private String getSign(JSONObject data) {
        String sign = "";
        String jsonData = data.toJSONString();
        StringBuffer sb = new StringBuffer("lepos");
        sb.append("60E3F31EDEC8061C33721737B36FA86D").append(jsonData);// key每个渠道商不一样
        try {
            String md5 = DigestUtils.md5Hex(sb.toString().getBytes("UTF-8"));
            sign = Base64.encodeBase64String(md5.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            logger.error("Exception:{}", e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
        }
        logger.info("待签参数:{}" + sb);
        logger.info("签名值:{}" + sign);
        return sign;
    }

    @Override
    public String requestPay(Map<String, String> reqMap, String apiKey, boolean isCheckRespSign) throws Exception {
        return this.request(LeshuaParam.getPAYURL(), reqMap, apiKey, true);
    }

    public String request(String serviceUrl, Map<String, String> reqMap, String apiKey, boolean isCheckRespSign)
            throws Exception {
        long costTimeStart = System.currentTimeMillis();
        // 根据API给的签名规则进行签名
        String sign = LeshuaSignature.getMD5Sign(reqMap, reqExcludedSignParams(), apiKey);
        reqMap.put("sign", sign);

        String respStr = httpClientHelper.postForm(serviceUrl, reqMap, HttpClientHelper.ACCEPT_TYPE_XML);
        long totalTimeCost = System.currentTimeMillis() - costTimeStart;
        // 打印回包数据
        logger.info("接口：{}，请求耗时：{}ms，请求参数：{}，\n乐刷返回的数据如下：{}", totalTimeCost, reqMap, respStr);

        if (isCheckRespSign) {
            if (respStr.contains("<sign>") && !LeshuaSignature.checkIsSignValidFromResponseString(respStr, resExcludedSignParams(), apiKey)) {
                logger.error("接口：{}，订单号：{}，验签失败，数据可能被篡改了！！！", reqMap.get("third_order_id"));
                throw new Exception("验签失败");
            }
        }
        return respStr;
    }

    /**
     * 请求参数不参与计算签名的参数
     *
     * @return
     */
    protected Set<String> reqExcludedSignParams() {
        Set<String> exludedSignParams = new HashSet<String>(1);
        exludedSignParams.add("sign");
        return exludedSignParams;
    }

    /**
     * 响应结果不参与计算签名的参数
     *
     * @return
     */
    protected Set<String> resExcludedSignParams() {
        Set<String> exludedSignParams = new HashSet<String>(2);
        exludedSignParams.add("sign");
        exludedSignParams.add("resp_code");
        return exludedSignParams;
    }

    @Override
    public String leshuaImgUpload(String path) throws Exception {
        Map<String, File> reqMap = new HashMap<String, File>(16);
        JSONObject data = new JSONObject(1);
        Properties prop = System.getProperties();
        String os = prop.getProperty("os.name");
        if (os.startsWith("win") || os.startsWith("Win")) {
            if (path.contains("https") || path.contains("http") || path.contains("www.")) {
                // windows目录
                int lastIndexOf = path.lastIndexOf(".");
                File img = File.createTempFile(StringUtil.getBillno(), "." + path.substring(lastIndexOf + 1),
                        new File("C:\\"));
                URL url2 = new URL(path);
                InputStream inputStream = url2.openStream();
                OutputStream oss = new FileOutputStream(img);
                int bytesRead = 0;
                byte[] buffer = new byte[8192];
                while ((bytesRead = inputStream.read(buffer, 0, 8192)) != -1) {
                    oss.write(buffer, 0, bytesRead);
                }
                oss.close();
                inputStream.close();
                String fileMD5 = DigestUtils.md5Hex(FileUtil.fileToByte(path));
                reqMap.put("media", img);
                data.put("fileMD5", fileMD5);
            } else {
                File file = new File(path);
                String fileMD5 = DigestUtils.md5Hex(FileUtil.File2byte2(path));
                reqMap.put("media", file);
                data.put("fileMD5", fileMD5);
            }
        } else {
            SystemConfig systemConfig = new SystemConfig();
            systemConfig.setPropertyKey("upload_save_path");
            SystemConfig querySystemConfig = systemConfigMapper.querySystemConfig(systemConfig);
            String propertyValue = querySystemConfig.getPropertyValue();
            System.out.println("======== shangchuan tupian =图片liunx服务器保存地址 =========" + JSONObject.toJSONString(querySystemConfig));
            System.out.println("======== shangchuan tupian =图片liunx服务器保存地址 =========" + propertyValue);
            String[] split = path.split("/");
            path = split[split.length - 1];
            path = propertyValue + "/" + path;
            System.out.println("======== shangchuan tupian =图片liunx服务器保存地址 =========" + path);
            File file = new File(path);
            String fileMD5 = DigestUtils.md5Hex(FileUtil.File2byte2(path));
            reqMap.put("media", file);
            data.put("fileMD5", fileMD5);
        }
//        Result<Object> result = this.requestApi(ParametersUtil.LESHUA_API + "/picture/upload", data, reqMap);
//        if ("000000".equals(result.getRespCode())) {
//            JSONObject data2 = (JSONObject) result.getData();
//            String url = data2.getString("photoUrl");
//            logger.info("======== shangchuan tupian =fanhui jieguo =========" + JSONObject.toJSONString(result));
//            return url;
//        } else {
//            throw new MsgException(result);
//        }

        return null;
    }

    @Override
    public Result<Map<String, Object>> openMerchantService(Map<String, Object> map) {
//        try {
//            String id = (String) map.get("id");//merchantBaseInfo.id
//            MerchantBaseInfo merchantBaseInfo = new MerchantBaseInfo();
//            merchantBaseInfo.setId(Long.valueOf(id));
//            merchantBaseInfo = merchantBaseInfoService.queryMerchantBaseInfo(merchantBaseInfo);
//            String userId = merchantBaseInfo.getUserId();
//            UserApp userApp = new UserApp();
//            userApp.setUserId(Long.parseLong(userId));
//            userApp = userAppMapper.queryUserApp(userApp);
//            if (!"3".equals(userApp.getLeshuaStatus())) {
//                return ResultGenerator.genFailResult("该商户尚未开通乐刷支付");
//            }
//            String rate = (String) map.get("rate");//例如 0.0038
//            Double leshuaRate = Double.parseDouble(rate) * 10000;
//            JSONObject dat = new JSONObject(4);
//            dat.put("merchantId", userApp.getLeshuaMchId());
//            JSONObject fee = new JSONObject();// 费率参数对象
//            fee.put("openType", 1);
//            JSONObject weixin = new JSONObject(4);// 微信支付费率
//            JSONObject wxt1 = new JSONObject(4);// 微信支付T1费率
//            wxt1.put("rate", leshuaRate);
//            weixin.put("t1", wxt1);
//            fee.put("weixin", weixin);
//            JSONObject alipay = new JSONObject(4);// 支付宝支付费率
//            JSONObject alipayt1 = new JSONObject(4);// 支付宝支付T1费率
//            alipayt1.put("rate", leshuaRate);
//            alipay.put("t1", alipayt1);
//            fee.put("alipay", alipay);
//            dat.put("fee", fee);
//            Result<Object> res = requestApi(LeshuaParam.getREGISTERURL() + "/merchant/open", dat);
//            if ("000000".equals(res.getRespCode())) {
////				 NumberFormat nf=NumberFormat.getPercentInstance();
////				 Number m=nf.parse(rate);
//                merchantBaseInfo.setLeshuaRate(Double.valueOf(rate));
//                merchantBaseInfoService.updateMerchantBaseInfo(merchantBaseInfo);
//                return ResultGenerator.genSuccessResult();
//            }
//        } catch (Exception e) {
//            e.printStackTrace();
//            return ResultGenerator.genFailResult("修改错误");
//        }
        return ResultGenerator.genFailResult("修改失败");
    }

    /**
     * 乐刷交易结果查询
     * @param
     * @param mchId
     * @return
     */
    @Override
    public Map<String, Object> requestTransQuery(MerchantOrder orderInfo,String mchId) throws Exception{
        Map<String, Object> result = new HashMap<>(2);
        String nonceStr = StringUtil.genRandomNum(32);
        Map<String,String> params = new HashMap<>(4);
        params.put("service","query_status");
        params.put("merchant_id",mchId);
        params.put("third_order_id",orderInfo.getOrderNumber());
        params.put("nonce_str",nonceStr);
        String sign = LeshuaSignature.getMD5Sign(params, new HashSet<>(1), ParametersUtil.leshuapaykey);
        params.put("sign",sign);
        logger.info("请求地址:{}" + LeshuaParam.getPAYURL());
        logger.info("请求参数:{}" + params);
        long costTimeStart = System.currentTimeMillis();
        String respStr = httpClientHelper.postForm(LeshuaParam.getPAYURL(), params, HttpClientHelper.ACCEPT_TYPE_XML);
        long totalTimeCost = System.currentTimeMillis() - costTimeStart;
        // 打印回包数据
        logger.info("乐刷交易查询接口，请求耗时：{}ms，请求参数：{}，\n乐刷返回的数据如下：{}", totalTimeCost, params, respStr);
        if(StringUtil.isEmpty(respStr)){
            result.put("code", "0");
            result.put("msg", "乐刷接口请求异常！");
            return result;
        }
        Map<String, Object> resultMap = XmlUtil.toMapLeshua(respStr);
        String resp_code = (String)resultMap.get("resp_code");
        if(!"0".equals(resp_code)){
            result.put("code", "0");
            result.put("msg", "乐刷"+resultMap.get("resp_msg"));
            return result;
        }
        String result_code = (String)resultMap.get("result_code");
        if(!"0".equals(result_code)){
            result.put("code", "0");
            result.put("msg", "乐刷"+resultMap.get("error_msg"));
            return result;
        }
        RealFansDTO realFansDTO = new RealFansDTO();
        String status = (String)resultMap.get("status");
        //支付成功
        if("2".equals(status)){
            String leshuaOrderId = (String)resultMap.get("leshua_order_id");
            String payTime = (String)resultMap.get("pay_time");
            SimpleDateFormat sFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String openid = (String) resultMap.get("openid");// 微信openid
            String sub_openid = (String) resultMap.get("sub_openid");//支付宝
            String amountpaid = (String) resultMap.get("amount");// 订单金额
            String pay_way = (String) resultMap.get("pay_way");// 支付类型
            //主扫 会员充值
            if("1".equals(orderInfo.getOrderType()) || "3".equals(orderInfo.getOrderType())){
                orderInfo.setStatus("1");
                orderInfo.setTransDt(sFormat.parse(payTime));
                orderInfo.setThirdTransNo(leshuaOrderId);
                merchantOrderMapper.updateById(orderInfo);
                //被扫
            }else if("2".equals(orderInfo.getOrderType())){
                Map<String, Object> map = new HashMap<>(16);
                BigDecimal amountPay = (new BigDecimal(amountpaid).divide(new BigDecimal("100"))).setScale(2);// 将分转换成元-实际支付金额:元
                realFansDTO.setConSumMoney(String.valueOf(amountPay));
                realFansDTO.setConsumTime(payTime);
                realFansDTO.setLogo(orderInfo.getUserImg());
                realFansDTO.setNickName(orderInfo.getNickName());
                realFansDTO.setMerchantCode(orderInfo.getMerchantCode());
                realFansDTO.setOrderNumber(orderInfo.getOrderNumber());
                realFansDTO.setTradeNumber(leshuaOrderId);
                if ("ZFBZF".equals(pay_way)) {
                    realFansDTO.setPayWay("2-0");
                    realFansDTO.setSoleId(sub_openid);
                } else if ("WXZF".equals(pay_way)) {
                    realFansDTO.setPayWay("2-1");
                    realFansDTO.setSoleId(openid);
                }
                map.put("realFansDTO", realFansDTO);
                logger.info("=============乐刷补单realFansDTO================" + JSONObject.toJSONString(realFansDTO));
                //realFansService.saveRealFansAndFansConsSumRecords(map);
                result.put("data",map);
            }
            result.put("code", "1");
            result.put("msg", "补单成功！");
            return result;
        }else if("6".equals(status) ||"0".equals(status)){
            result.put("code", "2");
            result.put("msg", "乐刷订单与我方订单状态一致，无需补单！");
            return result;
        }
        result.put("code", "1");
        result.put("msg", "无需补单！");
        return  result;
    }

    /**
     * 参数转换
     */
    private MerchantLeshuaDTO converParameter(Map<String,String> params,HttpServletRequest request) {
        //乐刷参数转换
        MerchantLeshuaDTO lsDto = new MerchantLeshuaDTO();
        lsDto.setComsumeMoney(Double.parseDouble(params.get("comsumeMoney")));
        lsDto.setLeshuaMchId(params.get("leshuaMchId"));
        lsDto.setMerchantCode(params.get("merchantCode"));
        lsDto.setStoreId(params.get("storeId"));
        lsDto.setPayWay(params.get("payWay"));
        lsDto.setUserImg(params.get("userImg"));
        lsDto.setNickName(params.get("nickName"));
        lsDto.setRemark(params.get("remark"));
        lsDto.setOpenId(params.get("openid"));
        lsDto.setIsMember(params.get("isMember"));
        lsDto.setRadioPay(params.get("radioPay"));
        lsDto.setIp(IpUtils.getIpAddr(request));
        return lsDto;
    }

    @Override
    public Map<String,Object> tradePay(Map<String,String> params, HttpServletRequest request,MerchantStore store, String orderNumber) throws Exception {
        MerchantLeshuaDTO merchantLeshuaDTO = converParameter(params, request);
        Map<String, String> reqMap = new HashMap<>(16);
        reqMap.put("service", "get_tdcode");
        reqMap.put("pay_way", merchantLeshuaDTO.getPayWay());
        reqMap.put("amount", merchantLeshuaDTO.getComsumeMoney() * 100 + "");
        reqMap.put("merchant_id", merchantLeshuaDTO.getLeshuaMchId());
        reqMap.put("third_order_id", orderNumber);
        Map<String, Object> result = new HashMap<>();
        reqMap.put("jspay_flag", "2");
        reqMap.put("notify_url", URLEncoder.encode(ParametersUtil.domain + "/wap/notify/leshuaCallBack", "utf-8"));
        reqMap.put("jump_url", URLEncoder.encode(ParametersUtil.domain + "/wap/merchant/jumpUrl?leshuaMchId="
                + merchantLeshuaDTO.getLeshuaMchId() + "&orderNumber=" + orderNumber, "utf-8"));
        reqMap.put("client_ip", merchantLeshuaDTO.getIp());
        reqMap.put("body", StringUtil.isNotEmpty(store.getStoreName()) ? store.getStoreName():"leshuaPay");
        reqMap.put("nonce_str", StringUtil.genRandomNum(32));
        try {
            String apKey = "60E3F31EDEC8061C33721737B36FA86D";
            System.out.println("reqMap===========================" + JSONObject.toJSONString(reqMap));
            String requestPay = requestPay(reqMap, apKey, true);
            System.out.println("requestPay===========================" + requestPay);
            Map<String, Object> mapLeshua = XmlUtil.toMapLeshua(requestPay);
            // 判断商户被冻结等情况
            if (mapLeshua.get("result_code") != null && !"0".equals(mapLeshua.get("result_code").toString())) {
                result.put("code", "0");
                result.put("msg", mapLeshua.get("error_msg"));
                return result;
            }
            result.put("code","1");
            result.put("msg","下单成功");
            result.put("data",mapLeshua);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            result.put("code", "0");
            result.put("msg", "系统繁忙，请稍后再试");
            return result;
        }
    }

    public List<ActivityConsumReturn> comsumeMoneyByDesc(List<ActivityConsumReturn> list) {
        list.sort((o1, o2) -> (int) (o2.getComsumeMoney() - o1.getComsumeMoney()));
        return list;
    }


    @Override
    public Map<String, Object> leshuaReturn(MerchantOrderVO queryMerchantOrder, String leshuaMchId) {
        Map<String,Object> result = new HashMap<>(6);
        Map<String, String> reqMap = new HashMap<>(16);
        String merchant_refund_id = StringUtil.getBillno();
        reqMap.put("service", "unified_refund");
        reqMap.put("merchant_id", leshuaMchId);
        reqMap.put("third_order_id", queryMerchantOrder.getOrderNumber());
        reqMap.put("refund_amount", queryMerchantOrder.getConsumeFee() * 100 + "");
        reqMap.put("merchant_refund_id", merchant_refund_id);// 退款随机字符 在查询退款的时候需要用到
        reqMap.put("nonce_str", StringUtil.genRandomNum(32));
        reqMap.put("notify_url", systemConfigService.querySystemConfigValue("LeshuaRefundBack"));

        String requestPay;
        try {
            requestPay = requestPay(reqMap, "60E3F31EDEC8061C33721737B36FA86D", true);
            Map<String, Object> map = XmlUtil.toMapLeshua(requestPay);
            String resp_code = (String) map.get("resp_code");
            if ("0".equals(resp_code)) {
                // 0表示通信成功
                String result_code = (String) map.get("result_code");
                if ("0".equals(result_code)) {
                    // 0表示业务成功
                    Date refundTime = DateUtils.parse(map.get("refund_time").toString(), "yyyy-MM-dd HH:mm:ss");
                    result.put("code","1");
                    result.put("refundTime",refundTime);
                    result.put("status","2");
                    result.put("msg","退款成功");
                    result.put("refundNo",merchant_refund_id);
                    return result;
//                    merchantOrderService.getProfit(queryMerchantOrder);
//                    Date refundTime = DateUtils.parse(map.get("refund_time").toString(), "yyyy-MM-dd HH:mm:ss");
//                    queryMerchantOrder.setUpdateTime(refundTime);
//                    queryMerchantOrder.setStatus("2");
//                    return ResultGenerator.genSuccessResult("退款成功");
                } else {
                    result.put("code","0");
                    result.put("status","3");
                    result.put("msg",(String) map.get("error_msg"));
                    return result;
                }
            } else {
                // 0表示业务成功
                result.put("code","0");
                result.put("status","3");
                result.put("msg","退款失败");
                return result;
            }
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            result.put("code","0");
            result.put("status","3");
            result.put("msg","退款失败");
            return result;
        }
//        finally {
////            queryMerchantOrder.setId(null);
////            queryMerchantOrder.setLeshuaMerchantRefundId(merchant_refund_id);
////            queryMerchantOrder.setUpdateTime(new Date());
////            merchantOrderService.saveMerchantOrder(queryMerchantOrder);
//        }
    }
}
