/**
 * Copyright 2015-现在 广州市领课网络科技有限公司
 */
package com.roncoo.education.util.polyv;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.URLUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.roncoo.education.util.config.SystemUtil;
import com.roncoo.education.util.tools.JSUtil;
import com.roncoo.education.util.tools.MD5Util;
import com.roncoo.education.util.tools.SHA1Util;
import org.apache.commons.collections4.map.HashedMap;
import org.apache.http.HttpResponse;
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.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
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.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * 保利威视工具类
 *
 * @author wujing
 */
public final class PolyvUtil {

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

    private static final String KEY = "rc-education"; // 长度为12
    private static final String CHARSET_UTF_8 = "UTF-8";

    private PolyvUtil() {
    }

    /**
     * 获取code
     *
     * @param polyvCode
     * @return
     */
    public static String getPolyvCode(PolyvCode polyvCode) {
        try {
            return URLUtil.encodeQuery(Base64.encode(SecureUtil.des(Base64.decode(KEY)).encrypt(JSUtil.toJSONString(polyvCode))), StandardCharsets.UTF_8);
        } catch (Exception e) {
            logger.error("保利威视，加密出错", e);
            return "";
        }
    }

    /**
     * code解密
     *
     * @param code
     * @return
     */
    public static PolyvCode decode(String code) {
        try {
            return JSUtil.parseObject(new String(SecureUtil.des(Base64.decode(KEY)).decrypt(Base64.decode(URLDecoder.decode(code, CHARSET_UTF_8)))), PolyvCode.class);
        } catch (Exception e) {
            logger.error("保利威视，解密出错", e);
            return null;
        }
    }

    @SuppressWarnings("unchecked")
    public static PolyvSignResult getSignForH5(PolyvSign bo, String useid, String secretkey) {
        // 根据时间戳、vid、密钥生成sign值
        String ts = String.valueOf(System.currentTimeMillis());
        // 获取播放token
        Map<String, Object> map = new HashedMap<>();
        map.put("userId", useid);
        map.put("videoId", bo.getVid());
        map.put("ts", ts);
        map.put("viewerIp", bo.getIp());
        map.put("viewerName", bo.getUserNo());
        map.put("extraParams", "HTML5");
        map.put("viewerId", bo.getUserNo());
        logger.info("保利威视，map：map={}", map);
        String concated = "extraParams" + map.get("extraParams") + "ts" + map.get("ts") + "userId" + map.get("userId") + "videoId" + map.get("videoId") + "viewerId" + map.get("viewerId") + "viewerIp" + map.get("viewerIp") + "viewerName" + map.get("viewerName");
        map.put("sign", MD5Util.MD5(secretkey + concated + secretkey).toUpperCase());
        String result = post(SystemUtil.POLYV_GETTOKEN, map);
        logger.info("保利威视，获取token接口：result={}", result);
        Map<String, Object> resultMap = JSUtil.parseObject(result, HashMap.class);
        int code = Integer.valueOf(resultMap.get("code").toString()).intValue();
        if (code != 200) {
            return null;
        }
        Map<String, Object> data = (Map<String, Object>) resultMap.get("data");
        if (data == null || data.isEmpty()) {
            return null;
        }
        PolyvSignResult dto = new PolyvSignResult();
        dto.setSign(MD5Util.MD5(secretkey + bo.getVid() + ts));
        dto.setTs(ts);
        dto.setToken(data.get("token").toString());
        return dto;
    }

    public static UploadFileResult getVideo(String vid, String secretkey, String useid) {
        Map<String, Object> param = new TreeMap<String, Object>();
        param.put("vid", vid);
        param.put("format", "json");
        param.put("ptime", String.valueOf(System.currentTimeMillis()));// 当前13位毫秒级时间戳
        StringBuilder signStr = new StringBuilder();
        for (Map.Entry<String, Object> entry : param.entrySet()) {
            signStr.append("&").append(entry.getKey()).append("=").append(entry.getValue());
        }
        signStr = signStr.deleteCharAt(0);
        signStr.append(secretkey);
        param.put("sign", SHA1Util.getSign(signStr.toString()));
        String s = post("http://api.polyv.net/v2/video/{userid}/get-video-msg".replace("{userid}", useid), param);
        try {
            @SuppressWarnings("unchecked")
            Map<String, Object> m = JSUtil.parseObject(s, HashMap.class);
            if (m.get("code").toString().equals("200")) {
                // 成功
                return JSUtil.parseArray(JSUtil.toJSONString(m.get("data")), UploadFileResult.class).get(0);
            }
            logger.error("获取视频失败，原因为：{}", s);
        } catch (Exception e) {
            logger.error("获取视频失败异常，结果={}，参数={}", s, param);
        }
        return null;
    }

    /**
     * 上传视频 http://dev.polyv.net/2014/videoproduct/v-api/v-api-upload/uploadfile/
     *
     * @param file
     * @return
     */
    public static UploadFileResult uploadFile(File file, UploadFile uploadFile, String writetoken) {
        Map<String, Object> param = new HashMap<String, Object>();
        param.put("writetoken", writetoken);
        param.put("JSONRPC", "{\"title\": \"" + uploadFile.getTitle() + "\", \"tag\": \"" + uploadFile.getTag()
                + "\", \"desc\": \"" + uploadFile.getDesc() + "\"}");
        param.put("cataid", uploadFile.getCataid());
        if (StringUtils.hasText(uploadFile.getWatermark())) {
            param.put("watermark", uploadFile.getWatermark());
        }
        String result = postFile(SystemUtil.POLYV_UPLOADVIDEO, param, file);
        try {
            JSONObject json = JSONUtil.parseObj(result);
            if ("0".equals(json.getStr("error"))) {
                return JSUtil.parseArray(json.getStr("data"), UploadFileResult.class).get(0);
            }
        } catch (Exception e) {
            logger.error(e.toString(), e);
        }
        logger.error("保利威视，上传视频失败，原因={}", result);
        return null;
    }

    /**
     * 删除视频
     */
    public static String deleteFile(String vid, String useid, String secretkey) {
        SortedMap<String, String> paramMap = new TreeMap<>();
        paramMap.put("userid", useid);// 用户ID
        paramMap.put("vid", vid);// 视频ID
        paramMap.put("ptime", String.valueOf(System.currentTimeMillis()));// 当前13位毫秒级时间戳
        StringBuilder signStr = new StringBuilder();
        for (Map.Entry<String, String> entry : paramMap.entrySet()) {
            signStr.append("&").append(entry.getKey()).append("=").append(entry.getValue());
        }
        signStr = signStr.deleteCharAt(0);
        signStr.append(secretkey);
        String sign = SHA1Util.getSign(signStr.toString());
        paramMap.put("sign", sign);
        String url = SystemUtil.POLYV_DELETEVIDEO.replace("{userid}", useid);
        HttpPost httpPost = new HttpPost(url.trim());
        RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000)
                .setConnectionRequestTimeout(3600000).setSocketTimeout(3600000).build();
        httpPost.setConfig(requestConfig);
        List<BasicNameValuePair> nvps = new ArrayList<>();
        for (Map.Entry<String, String> entry : paramMap.entrySet()) {
            nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
        }
        StringEntity se = null;
        try {
            se = new UrlEncodedFormEntity(nvps, CHARSET_UTF_8);
            httpPost.setEntity(se);
            HttpResponse httpResponse = HttpClientBuilder.create().build().execute(httpPost);
            return EntityUtils.toString(httpResponse.getEntity(), CHARSET_UTF_8);
        } catch (Exception e) {
            logger.error("保利威视，删除视频失败");
        }
        return null;
    }

    /**
     * 上传问题接口
     */
    public static QuestionResult uploadQuestion(Question question, String writetoken) {
        try {
            String url = SystemUtil.POLYV_QUESTION;
            HttpPost httpPost = new HttpPost(url.trim());
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000)
                    .setConnectionRequestTimeout(3600000).setSocketTimeout(3600000).build();
            httpPost.setConfig(requestConfig);
            JSONArray choices = new JSONArray();
            for (String value : question.getAnswerList()) {
                JSONObject answer = new JSONObject();
                answer.set("answer", value);
                choices.add(answer);
            }
            JSONObject righeAnswer = new JSONObject();
            righeAnswer.set("answer", question.getRightAnswer());
            righeAnswer.set("right_answer", question.getRight());
            choices.add(righeAnswer);
            List<BasicNameValuePair> nvps = new ArrayList<>();
            nvps.add(new BasicNameValuePair("method", "saveExam"));
            nvps.add(new BasicNameValuePair("writetoken", writetoken));
            nvps.add(new BasicNameValuePair("vid", question.getVid()));
            nvps.add(new BasicNameValuePair("examId", question.getExamId()));
            nvps.add(new BasicNameValuePair("seconds", String.valueOf(question.getSeconds())));
            nvps.add(new BasicNameValuePair("question", question.getQuestion()));
            nvps.add(new BasicNameValuePair("choices", choices.toString()));
            nvps.add(new BasicNameValuePair("skip", String.valueOf(question.isSkip())));
            nvps.add(new BasicNameValuePair("answer", question.getAnswer()));
            nvps.add(new BasicNameValuePair("wrongShow", String.valueOf(question.getWrongShow())));
            nvps.add(new BasicNameValuePair("wrongTime", String.valueOf(question.getWrongTime())));
            StringEntity se = new UrlEncodedFormEntity(nvps, CHARSET_UTF_8);
            httpPost.setEntity(se);
            HttpResponse httpResponse = HttpClientBuilder.create().build().execute(httpPost);
            String resultStr = EntityUtils.toString(httpResponse.getEntity(), CHARSET_UTF_8);
            return JSUtil.parseObject(resultStr, QuestionResult.class);
        } catch (Exception e) {
            logger.error("添加问题失败！");
        }
        return null;
    }

    /**
     * 获取sign
     *
     * @param paramMap
     * @return
     */
    public static String getSign(Map<String, Object> paramMap, String secretkey) {
        if (paramMap.isEmpty()) {
            return "";
        }
        SortedMap<String, Object> smap = new TreeMap<String, Object>(paramMap);
        StringBuffer stringBuffer = new StringBuffer();
        for (Map.Entry<String, Object> m : smap.entrySet()) {
            String value = String.valueOf(m.getValue());
            if (StringUtils.hasText(value)) {
                stringBuffer.append(m.getKey()).append("=").append(value).append("&");
            }
        }
        stringBuffer.delete(stringBuffer.length() - 1, stringBuffer.length());
        String argPreSign = stringBuffer.append("&paySecret=").append(secretkey).toString();
        return MD5Util.MD5(argPreSign).toUpperCase();
    }

    /**
     * @param url
     * @param param
     * @return
     */
    public static String post(String url, Map<String, Object> param) {
        CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().build();
        try {
            HttpPost httpPost = new HttpPost(url.trim());
            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(10000)
                    .setConnectionRequestTimeout(3600000).setSocketTimeout(3600000).build();
            httpPost.setConfig(requestConfig);
            List<NameValuePair> list = new ArrayList<>();
            for (Map.Entry<String, Object> m : param.entrySet()) {
                list.add(new BasicNameValuePair(m.getKey(), m.getValue().toString()));
            }
            httpPost.setEntity(new UrlEncodedFormEntity(list, "utf-8"));
            HttpResponse httpResponse = closeableHttpClient.execute(httpPost);
            return EntityUtils.toString(httpResponse.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                closeableHttpClient.close();
            } catch (IOException e) {
            }
        }
        return "";
    }

    private static String postFile(String url, Map<String, Object> param, File file) {
        CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().build();
        try {
            HttpPost httpPost = new HttpPost(url.trim());
            httpPost.setConfig(RequestConfig.custom().setConnectTimeout(10000).setConnectionRequestTimeout(3600000)
                    .setSocketTimeout(3600000).build());
            MultipartEntityBuilder entity = MultipartEntityBuilder.create();
            entity.addPart("Filedata", new FileBody(file));
            ContentType contentType = ContentType.create("text/plain", Charset.forName(CHARSET_UTF_8));
            for (Map.Entry<String, Object> m : param.entrySet()) {
                entity.addPart(m.getKey(), new StringBody(m.getValue().toString(), contentType));
            }
            httpPost.setEntity(entity.build());
            return EntityUtils.toString(closeableHttpClient.execute(httpPost).getEntity(), CHARSET_UTF_8);
        } catch (Exception e) {
            logger.error("上传到保利威视失败，url={},param={}", url, param, e);
        } finally {
            try {
                closeableHttpClient.close();
            } catch (IOException e) {
            }
        }
        return "";
    }

}
