package com.rf.psychological.douyin.service.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.rf.psychological.douyin.config.DouYinConfig;
import com.rf.psychological.douyin.model.DouYinOrderEntity;
import com.rf.psychological.douyin.service.DouYinOrderService;
import com.rf.psychological.douyin.service.DouYinService;
import com.rf.psychological.douyin.util.SignUtil;
import com.rf.psychological.enums.OrderStatus;
import com.rf.psychological.enums.UserRole;
import com.rf.psychological.group.service.GroupInfoService;
import com.rf.psychological.user.dao.model.UserEntity;
import com.rf.psychological.user.service.UserService;
import com.rf.psychological.utils.Constant;
import com.rf.psychological.utils.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
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.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.*;

/**
 * @Description:
 * @Author: mimang
 * @Date: 2023/8/15
 */
@Slf4j
@Service
@ConditionalOnProperty(prefix="douyin",name = "isDouYin", havingValue = "true")
public class DouYinServiceImpl implements DouYinService {

    @Resource
    private DouYinConfig douYinConfig;

    @Resource
    private UserService userService;

    @Resource
    private GroupInfoService groupInfoService;

    @Resource
    private DouYinOrderService orderInfoService;

    /**
     * 获取到openid
     * @param code login 接口返回的登录凭证
     * @return
     */
    @Override
    public String jscode2session(String code) throws Exception {
        String url = douYinConfig.getSessionUrl();

        Map<String,Object> paramsMap = new HashMap<>();
        paramsMap.put("code",code);
        paramsMap.put("appid",douYinConfig.getAppid());
        paramsMap.put("secret",douYinConfig.getSecret());
        JSONObject data = generateReq(url,paramsMap,"err_no").getObject("data",JSONObject.class);
        return data.getString("openid");
    }

    private JSONObject generateReq(String url,Map<String, Object> params,String errCode) throws Exception{
        //创建httpclient对象
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Accept", "application/json");
        String jsonParams = JSONObject.toJSONString(params);
        StringEntity entity = new StringEntity(jsonParams,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept","application/json");

        CloseableHttpResponse response = client.execute(httpPost);
        JSONObject bodyJson =JSONObject.parseObject( EntityUtils.toString(response.getEntity()));//获取响应体
        int errNo = bodyJson.getInteger(errCode);
        if (errNo != 0){
            throw new Exception(errNo+"---------"+bodyJson.toString());
        }
        log.info(url+"------------"+bodyJson.toString());
        return bodyJson;
    }

    private InputStream generateCode(String url, Map<String, Object> params) throws Exception{
        //创建httpclient对象
        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.setHeader("Accept", "application/json");
        String jsonParams = JSONObject.toJSONString(params);
        StringEntity entity = new StringEntity(jsonParams,"utf-8");
        entity.setContentType("application/json");
        httpPost.setEntity(entity);
        httpPost.setHeader("Accept","application/json");

        CloseableHttpResponse response = client.execute(httpPost);
//        JSONObject bodyJson =JSONObject.parseObject( EntityUtils.toString(response.getEntity()));//获取响应体
//        int errNo = bodyJson.getInteger("errcode");
//        if (errNo != 0){
//            throw new Exception(errNo+"---------"+bodyJson.getString("errmsg"));
//        }
        return response.getEntity().getContent();
    }

    @Override
    public JSONObject douyinLogin(String openid, JSONObject resultJson) {
        UserEntity userEntity = this.userService.findPhoneAndInstitutionNoAndRoleType(openid, Constant.WEB_INSTITUTION_CODE, UserRole.COMMON.getType());
        if(userEntity != null){
            userEntity.setPassword("-");
            resultJson.put("user", userEntity);
            resultJson.put("type", userEntity.getRoleType());
            resultJson.put("improve",false);
        }else{
            //注册
            userEntity = new UserEntity();
            userEntity.setPassword("-");
            userEntity.setGId(this.groupInfoService.findGroupByInstitutionNoAndName(Constant.WEB_INSTITUTION_CODE,Constant.DEFAULT_GROUP_NAME).getId());
            userEntity.setInstitutionName(Constant.WEB_INSTITUTION_NAME);
            userEntity.setInstitutionNo(Constant.WEB_INSTITUTION_CODE);
            userEntity.setUserStatus(Constant.USER_STATUS_NORMAL);
            userEntity.setBirthday("-");
            userEntity.setGender("-");
            userEntity.setPetName("抖音用户");
            userEntity.setProfession("-");
            userEntity.setAdditionInfo("抖音小程序注册用户");
            userEntity.setPhone(openid);
            userEntity.setRoleType(UserRole.COMMON.getType());
            userEntity = this.userService.save(userEntity);
            resultJson.put("improve",true);
        }

        resultJson.put("token", JWTUtil.getTokenByUserInfo(userEntity));
        resultJson.put("user",userEntity);
        resultJson.put("type",userEntity.getRoleType());
        return resultJson;
    }

    /**
     * 获取accessToken
     * @return
     */
    @Override
    public String getAccessToken() throws Exception {
        String url = douYinConfig.getTokenUrl();
        Map<String,Object> paramsMap = new HashMap<>();
        paramsMap.put("appid",douYinConfig.getAppid());
        paramsMap.put("secret",douYinConfig.getSecret());
        paramsMap.put("grant_type","client_credential");
        JSONObject data = generateReq(url,paramsMap,"err_no").getObject("data",JSONObject.class);
        return data.getString("access_token");
    }

    @Override
    public String getRQCode(String appname, String path) throws Exception {
        String url = douYinConfig.getCodeUrl();
        String token = this.getAccessToken();
        Map<String,Object> paramsMap = new HashMap<>();
        paramsMap.put("access_token",token);
        paramsMap.put("appname",appname);
        paramsMap.put("path",path);
        InputStream inputStream = this.generateCode(url,paramsMap);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = -1;
        while ((len = inputStream.read(buffer)) != -1) {
            baos.write(buffer, 0, len);
        }
        return Base64.getEncoder().encodeToString(baos.toByteArray());
    }

    /**
     * 预下单
     * @param totalAmount 金额
     * @param subject 主题
     * @param body 介绍
     * @param resultId 结果Id
     * @return
     */
    @Override
    public Map<String, Object> createOrder(int totalAmount, String subject, String body, String resultId, String path) throws Exception {
        Map<String, Object> map = new HashMap<>();
        //首先检测是否存在未支付订单
        DouYinOrderEntity orderInfo = orderInfoService.findByResultIdAndStatus(resultId, OrderStatus.PROCESSING.name());
        if (orderInfo != null) {
            if (StringUtils.isNotEmpty(orderInfo.getOrderId())) {
                map.put("orderId", orderInfo.getOrderId());
                map.put("orderToken", orderInfo.getOrderToken());
                map.put("orderNo", orderInfo.getOutOrderNo());
                return map;
            }
        } else {
            //如果为空创建新的订单
            orderInfo = orderInfoService.createNewOrder(totalAmount, subject, body, resultId);
        }

        //调用抖音接口生成订单
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("app_id", douYinConfig.getAppid());
        paramMap.put("out_order_no", orderInfo.getOutOrderNo());
        paramMap.put("total_amount", totalAmount);
        paramMap.put("subject", subject);
        paramMap.put("body", body);
        paramMap.put("valid_time", 900);
        paramMap.put("notify_url", douYinConfig.getNotifyUrl());
        if (StringUtils.isNotEmpty(path)) {
            paramMap.put("msg_page", path);
        }
        paramMap.put("sign", SignUtil.requestSign(paramMap));
        JSONObject jsonObject = null;
        try {
            jsonObject = this.generateReq(douYinConfig.getCreateOrderUrl(), paramMap,"err_no").getObject("data", JSONObject.class);

        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
            orderInfoService.deleteByNo(orderInfo.getOutOrderNo());
            return map;
        }
        //更新表单
        orderInfo.setOrderId(jsonObject.getString("order_id"));
        orderInfo.setOrderToken(jsonObject.getString("order_token"));
        orderInfoService.updateOrder(orderInfo);
        map.put("orderId", jsonObject.getString("order_id"));
        map.put("orderToken", jsonObject.getString("order_token"));
        map.put("orderNo", orderInfo.getOutOrderNo());
        return map;
    }

    @Override
    public Map<String, Object> queryOrder(String orderNo) throws Exception {

        Map<String,Object> resultMap = new HashMap();
        //首先查询本地订单
        DouYinOrderEntity order = orderInfoService.findByOutOrderNo(orderNo);
        if (order==null){
            throw new Exception("订单号不存在");
        }
        if (OrderStatus.SUCCESS.equals(order.getOrderStatus())){
            resultMap.put("statusCode",order.getOrderStatus());
            return resultMap;
        }
        //远程查询
        JSONObject resultJson = this.queryOrderByOutOrderNo(orderNo);
        String status = resultJson.getString("order_status");
        order.setOrderStatus(status);
        orderInfoService.updateOrder(order);
        resultMap.put("statusCode",status);
        return resultMap;
    }



    private JSONObject queryOrderByOutOrderNo(String order) throws Exception {
        Map<String,Object> paramMap = new HashMap<>();
        paramMap.put("app_id",douYinConfig.getAppid());
        paramMap.put("out_order_no",order);
        paramMap.put("sign",SignUtil.requestSign(paramMap));
        JSONObject result = this.generateReq(douYinConfig.getQueryOrderUrl(), paramMap,"err_no").getObject("payment_info",JSONObject.class);
        return result;
    }

    /**
     * 检测订单状态，是否超时
     */
    @Override
    public void checkOrderStatus() {
        List<DouYinOrderEntity> list  = orderInfoService.findAllByStatus(OrderStatus.PROCESSING);
        if (CollectionUtils.isEmpty(list)){
            return;
        }
        list.forEach(item->{
            //远程查询
            JSONObject resultJson = null;
            try {
                resultJson = this.queryOrderByOutOrderNo(item.getOutOrderNo());
                String status = resultJson.getString("order_status");
                item.setOrderStatus(status);
                orderInfoService.updateOrder(item);
            } catch (Exception e) {
                //订单号不存在，删除该订单
                log.error(e.getMessage());
                String msg = e.getMessage();
                if (msg.contains("2000")){
                    orderInfoService.deleteByNo(item.getOutOrderNo());
                }
                e.printStackTrace();
            }
        });

    }

    /**
     * 回调信息处理
     * @param msgJson 信息
     * @param resultCode 返回code
     * @return
     */
    @Override
    public JSONObject notifyOrder(JSONObject jsonObject, JSONObject msgJson, String resultCode) {
        JSONObject resultJson = new JSONObject();
        //订单编号
        String outTradeNo = msgJson.getString("cp_orderno");
        DouYinOrderEntity entity = orderInfoService.findByOutOrderNo(outTradeNo);
        if ("payment".equalsIgnoreCase(resultCode)) {
            List<String> sortedString = new ArrayList<>();
            //token
            sortedString.add(SignUtil.TOKEN);
            //时间戳
            sortedString.add(jsonObject.getString("timestamp"));
            //随机数
            sortedString.add(jsonObject.getString("nonce"));
            //msg
            sortedString.add(jsonObject.getString("msg"));
            Collections.sort(sortedString);
//                StringBuilder sb = new StringBuilder();
//                sortedString.forEach(sb::append);
            String msg_signature = jsonObject.getString("msg_signature");
            String sign = SignUtil.callbackSign(sortedString);
            log.info("支付回调接口密钥签名：{}",sign);
            if(!sign.equals(msg_signature)) {//判断签名
                resultJson.put("err_no",8);
                resultJson.put("err_tips","error");
                entity.setOrderStatus(OrderStatus.SUCCESS.name());
            }
            resultJson.put("err_no",0);
            resultJson.put("err_tips","success");
        } else {
            log.error("订单" + outTradeNo + "支付失败");
            resultJson.put("err_no",0);
            resultJson.put("err_tips","error");
            entity.setOrderStatus(OrderStatus.FAIL.name());
        }
        orderInfoService.updateOrder(entity);
        return resultJson;
    }

    @Override
    public DouYinOrderEntity queryOrderByResultId(String resultId) {
        return orderInfoService.findByResultIdAndStatus(resultId,OrderStatus.SUCCESS.name());
    }

    public JSONObject pushOrder(String orderNo,String resultId,String title,String openId,int totalAmount, String path,int orderStatus,String imgPath) throws Exception {
        JSONObject jsonObject = null;
        try {
            List<Map<String,Object>> itemList = new ArrayList<>();
            Map<String,Object> item = new HashMap<>();
            item.put("item_code", resultId);
            item.put("img", imgPath);
            item.put("title", title);
            item.put("amount", 1);
            item.put("price", totalAmount);
            itemList.add(item);

            //生成订单详情
            Map<String,Object> detailMap = new HashMap<>();
            detailMap.put("order_id", orderNo);
            detailMap.put("create_time", DateUtil.current());
            switch (orderStatus){
                case 0:
                    detailMap.put("status", "待支付");
                case 1:
                    detailMap.put("status", "已支付");
                case 2:
                    detailMap.put("status", "已取消");
            }
            detailMap.put("amount", 1);
            detailMap.put("total_price", totalAmount);
            detailMap.put("detail_url", path);
            detailMap.put("item_list", itemList);
            //调用抖音接口生成订单
            Map<String, Object> paramMap = new HashMap<>();
            paramMap.put("access_token", getAccessToken());
            paramMap.put("app_name", douYinConfig.getAppName());
            paramMap.put("app_id", douYinConfig.getAppid());
            paramMap.put("open_id", openId);
            paramMap.put("order_detail", JSONObject.toJSONString(detailMap));
            paramMap.put("order_status", orderStatus);
            paramMap.put("order_type", 0);
            paramMap.put("update_time", DateUtil.currentSeconds());
            jsonObject = this.generateReq(douYinConfig.getPushOrderUrl(), paramMap,"err_code");
            log.info(jsonObject.toJSONString());
        }catch (Exception e){
            e.printStackTrace();
            log.error(e.getMessage());
            throw e;
        }
        return jsonObject;
    }


}
