package com.palmnest.application.core.util;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.collections.ListUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.log4j.Logger;

import cn.superdesk.libs.common.json.JsonUtils;

import com.alibaba.fastjson.JSONObject;
import com.palmnest.application.dto.WxArticle;
import org.junit.Assert;
import org.springframework.util.CollectionUtils;

@Slf4j
public class WechatMsgMassUtils {

	private static Logger logger = Logger.getLogger(WechatMsgMassUtils.class);

	//上传其他素材地址-永久
	private static String WxAddMaterialUrl      = "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE";
//	//上传图文素材地址-永久----2022-02-15日，微信开发者团队下线了该接口
//	private static String AddNewsUrl            = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN";

	//新建草稿  ----由于2022-02-15日，微信开发者团队下线了以上注释的接口，因此替换成这个接口，新建草稿
	private static String AddNewsUrl            = "https://api.weixin.qq.com/cgi-bin/draft/add?access_token=ACCESS_TOKEN";
	//上传图文消息地址-临时
	private static String UploadNewsUrl         = "https://api.weixin.qq.com/cgi-bin/media/uploadnews?access_token=ACCESS_TOKEN";
	//根据openid进行群发
	private static String SendMassMessageUrl    = "https://api.weixin.qq.com/cgi-bin/message/mass/send?access_token=ACCESS_TOKEN";
	//根据标签进行群发【订阅号与服务号认证后均可用】
	private static String SendMassMessageAllUrl = "https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN";
	//修改永久图文地址   ----2022-02-15日，微信开发者团队下线了该接口
	private static String UpdateNewsUrl         = "https://api.weixin.qq.com/cgi-bin/material/update_news?access_token=ACCESS_TOKEN";
	//上传图文消息内的图片获取URL
	private static String UploadimgUrl          = "https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN";
	//预览接口
	private static String Preview               = "https://api.weixin.qq.com/cgi-bin/message/mass/preview?access_token=ACCESS_TOKEN";
	//删除素材接口
	private static String DeleteNews            = "https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=ACCESS_TOKEN";

	/**
	 * 获取授权token
	 *
	 * @param developId developId
	 * @return
	 */
	public static Map<String, String> GetAccessToken(String developId) {
		Map<String, String> resultMap = new HashMap<>();
		try {
			//String get_url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
			String get_url = "https://superdesk-app-test.superdesk.cn/api/wechat/front/accesstoken?developId=" + developId;
			Map<String, Object> paramMap = new HashMap<>();
			paramMap.put("developId", developId);
			String jsonStr = HttpKit.get(get_url);
			logger.info("###### result:" + jsonStr);
			resultMap.put("code", "200");
			resultMap.put("data", jsonStr);
		} catch (Exception e) {
			System.out.println(e.getMessage());
			resultMap.put("code", "400");
			resultMap.put("msg", e.getMessage());
		}
		return resultMap;
	}

	/**
	 * 上传图文消息内的图片获取URL
	 * 图片仅支持jpg/png格式，大小必须在1MB以下
	 *
	 * @param access_token 微信授权
	 * @param file_path    文件路径地址
	 * @return
	 */
	public static Map<String, String> UploadimgWithMedia(String access_token, String file_path) {
		Map<String, String> resultMap = new HashMap<>();
		String post_url = UploadimgUrl.replace("ACCESS_TOKEN", access_token);
		File file = new File(file_path);
		try {
			if (!file.exists() || !file.isFile()) {
				resultMap.put("code", "400");
				resultMap.put("msg", "文件不存在");
				return resultMap;
			}
			URL urlObj = new URL(post_url);
			// 连接
			HttpURLConnection con = (HttpURLConnection) urlObj.openConnection();
			/**
			 * 设置关键值
			 */
			con.setRequestMethod("POST"); // 以Post方式提交表单，默认get方式
			con.setDoInput(true);
			con.setDoOutput(true);
			con.setUseCaches(false); // post方式不能使用缓存
			// 设置请求头信息
			con.setRequestProperty("charset", "UTF-8");
			con.setRequestProperty("accept", "application/json");
			con.setRequestProperty("Content-length", String.valueOf(file.length()));
			// 设置边界
			String BOUNDARY = "----------" + System.currentTimeMillis();
			con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
			// 请求正文信息
			// 第一部分：
			StringBuilder sb = new StringBuilder();
			sb.append("--"); // 必须多两道线
			sb.append(BOUNDARY);
			sb.append("\r\n");
			sb.append("Content-Disposition: form-data;name=\"file\";filename=\""
					+ file.getName() + "\"\r\n");
			sb.append("Content-Type:application/octet-stream\r\n\r\n");
			byte[] head = sb.toString().getBytes("utf-8");
			// 获得输出流
			OutputStream out = new DataOutputStream(con.getOutputStream());
			// 输出表头
			out.write(head);
			// 文件正文部分
			// 把文件已流文件的方式 推入到url中
			DataInputStream in = new DataInputStream(new FileInputStream(file));
			int bytes = 0;
			byte[] bufferOut = new byte[1024];
			while ((bytes = in.read(bufferOut)) != -1) {
				out.write(bufferOut, 0, bytes);
			}
			in.close();
			// 结尾部分
			byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");// 定义最后数据分隔线
			out.write(foot);
			out.flush();
			out.close();
			// 读取返回数据
			StringBuffer strBuf = new StringBuffer();
			BufferedReader reader = new BufferedReader(new InputStreamReader(
					con.getInputStream()));
			String line = null;
			while ((line = reader.readLine()) != null) {
				strBuf.append(line).append("\n");
			}
			String res = strBuf.toString();
			System.out.println(res);
			reader.close();
			resultMap.put("code", "200");
			resultMap.put("data", res);

		} catch (Exception e) {
			resultMap.put("code", "400");
			resultMap.put("msg", e.getMessage());
		}
		return resultMap;
	}


	/**
	 * 新增其他类型永久素材
	 *
	 * @param filePath    文件路径
	 * @param accessToken 公众号接口唯一凭证
	 * @param type        图片（image）、语音（voice）、视频（video）和缩略图（thumb）
	 * @return
	 * @throws Exception
	 */
	public static Map<String, String> uploadMaterial(String filePath, String accessToken, String type, String video_title, String video_info) throws Exception {
		File file = new File(filePath);
		if (!file.exists() || !file.isFile()) {
			throw new IOException("文件不存在！");
		}
		String url = WxAddMaterialUrl.replace("ACCESS_TOKEN", accessToken).replace("TYPE", type);
		URL urlObj = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) urlObj.openConnection();
		conn.setRequestMethod("POST");
		conn.setDoInput(true);
		conn.setDoOutput(true);
		conn.setUseCaches(false);   // 使用post提交需要设置忽略缓存
		conn.setRequestProperty("Connection", "Keep-Alive");
		conn.setRequestProperty("Charset", "UTF-8");

		String BOUNDARY = "----------" + System.currentTimeMillis();
		conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
		StringBuilder sb = new StringBuilder();
		sb.append("--");    // 必须多两道线
		sb.append(BOUNDARY);
		sb.append("\r\n");
		sb.append("Content-Disposition:form-data;name=\"media\";filename=\"" + file.getName() + "\";filelength=\"" + file.length() + "\"\r\n");
		if (type.equals("video")) {
			sb.append("Content-Type:video/mp4 \r\n\r\n");
		} else {
			sb.append("Content-Type:application/octet-stream\r\n\r\n");
		}

		byte[] head = sb.toString().getBytes("utf-8");
		OutputStream out = new DataOutputStream(conn.getOutputStream());
		out.write(head);


		DataInputStream in = new DataInputStream(new FileInputStream(file));
		int bytes = 0;
		byte[] bufferOut = new byte[1024 * 1024 * 10]; // 10M
		while ((bytes = in.read(bufferOut)) != -1) {
			out.write(bufferOut, 0, bytes);
		}
		in.close();


		if (type.equals("video")) {
			out.write(("--" + BOUNDARY + "\r\n").getBytes("utf-8"));
			out.write("Content-Disposition: form-data; name=\"description\";\r\n\r\n".getBytes("utf-8"));
			out.write(String.format("{\"title\":\"%s\", \"introduction\":\"%s\"}", video_title, video_info).getBytes("utf-8"));
			out.write(("\r\n--" + BOUNDARY + "--\r\n\r\n").getBytes("utf-8"));
		}

		byte[] foot = ("\r\n--" + BOUNDARY + "--\r\n").getBytes("utf-8");
		out.write(foot);
		out.flush();
		out.close();
		StringBuffer buffer = new StringBuffer();
		BufferedReader reader = null;
		String result = null;
		try {
			reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
			String line = null;
			while ((line = reader.readLine()) != null) {
				buffer.append(line);
			}
			if (result == null) {
				result = buffer.toString();
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			reader.close();
		}
		JSONObject json = JSONObject.parseObject(result);
		System.out.println(json);
		log.info("---------WechatMsgMassUtils-uploadMaterial-json:\n{}",JsonUtils.toJson(json));
		String mediaId = "";
		Map<String, String> resultMap = new HashMap<>();
		if (StringUtil.isNotEmpty(json.getString("errcode"))) {
			resultMap.put("errcode", json.getString("errcode"));
			resultMap.put("errmsg", json.getString("errmsg"));
		} else {
			resultMap.put("media_id", json.getString("media_id"));
			resultMap.put("url", json.getString("url"));
		}
		log.info("---------WechatMsgMassUtils-uploadMaterial-resultMap:\n{}",JsonUtils.toJson(resultMap));
		return resultMap;

	}

	/**
	 * 上传图文消息素材-临时
	 *
	 * @param access_token
	 * @param wxArticle
	 * @return
	 */
	public static Map<String, String> UploadNewsWithMedia(String access_token, List<WxArticle> wxArticle) {
		Map<String, String> resultMap = new HashMap<>();
		try {
			String post_url = UploadNewsUrl.replace("ACCESS_TOKEN", access_token);
			Map<String, Object> paramMap = new HashMap<>();
			paramMap.put("articles", wxArticle);
			String jsonStr = HttpKit.Post(JSONObject.toJSONString(paramMap), post_url);
			logger.info("###### result-UploadNewsWithMedia:" + jsonStr);
			resultMap.put("code", "200");
			resultMap.put("data", jsonStr);
		} catch (Exception e) {
			System.out.println(e.getMessage());
			resultMap.put("code", "400");
			resultMap.put("msg", e.getMessage());
		}
		return resultMap;
	}

	/**
	 * 上传图文素材-永久
	 *
	 * @param access_token
	 * @param wxArticle
	 * @return
	 */
	public static Map<String, String> UploadNewsWithMediaForever(String access_token, List<WxArticle> wxArticle) {
		Map<String, String> resultMap = new HashMap<>();
		try {

			String post_url = AddNewsUrl.replace("ACCESS_TOKEN", access_token);
			log.info("UploadNewsWithMediaForever-post_url:{}",post_url);
			Map<String, Object> paramMap = new HashMap<>();
			paramMap.put("articles", wxArticle);
			log.info("UploadNewsWithMediaForever-paramMap:{}",JsonUtils.toJson(paramMap));
			String jsonStr = HttpKit.Post(JSONObject.toJSONString(paramMap), post_url);
			logger.info("###### result-UploadNewsWithMediaForever:" + jsonStr);
			JSONObject json = JSONObject.parseObject(jsonStr);
			if (StringUtil.isNotEmpty(json.getString("errcode"))) {
				resultMap.put("code", json.getString("errcode"));
				resultMap.put("msg", json.getString("errmsg"));
			} else {
				resultMap.put("code", "200");
				resultMap.put("media_id", json.getString("media_id"));
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
			resultMap.put("code", "400");
			resultMap.put("msg", e.getMessage());

		}
		return resultMap;
	}


	/**
	 * 根据OpenID列表群发【订阅号不可用，服务号认证后可用】
	 *
	 * @param access_token
	 * @param openIds             openId集合 最少2个 最多10000个
	 * @param type                mpnews（图文）text（文本）voice（语音）image（图片）video（视频）
	 * @param mediaId             媒体ID
	 * @param send_ignore_reprint 图文消息被判定为转载时，是否继续群发。 1为继续群发（转载），0为停止群发
	 * @return
	 */
	public static Map<String, String> SendMassMSGWithOpenId(String type, String access_token, List<String> openIds, String mediaId,
															String v_title, String v_description, int send_ignore_reprint,int isPublicUser) {
		Map<String, String> resultMap = new HashMap<>();
		try {

			if (type.equals("video")) {
				String resJsonStr = getMediaIdByVideo(access_token, mediaId, v_title, v_description);
				JSONObject json_video = JSONObject.parseObject(resJsonStr);
				mediaId = json_video.getString("media_id");
			}

			String post_url = SendMassMessageUrl.replace("ACCESS_TOKEN", access_token);
			Map<String, Object> paramMap = new HashMap<>();

			Map<String, String> mediaIdMap = new HashMap<>();
			mediaIdMap.put("media_id", mediaId);
			if (type.equals("video")) {
				mediaIdMap.put("title", v_title);
				mediaIdMap.put("description", v_description);
			}
			if (type.equals("video")) {
				paramMap.put("mpvideo", mediaIdMap);
			} else {
				paramMap.put("mpnews", mediaIdMap);
			}
			if (type.equals("video")) {
				paramMap.put("msgtype", "mpvideo");
			} else {
				paramMap.put("msgtype", type);
			}
			paramMap.put("msgtype", type);
			paramMap.put("send_ignore_reprint", send_ignore_reprint);
			String jsonStr = "";
			logger.info("###### result-SendMassMSGWithOpenId-openIds.size:"+openIds.size());
			if(1 == isPublicUser){
				List<List<String>> list = Lists.partition(openIds,9500);
				logger.info("###### result-SendMassMSGWithOpenId-list.size:"+list.size()+";openIds.size:"+openIds.size());
				for(int i=0;i<list.size();i++){
					paramMap.put("touser", list.get(i));
					jsonStr = HttpKit.Post(JSONObject.toJSONString(paramMap), post_url);
					logger.info("###### result-SendMassMSGWithOpenId-"+i+":" + jsonStr);
					JSONObject json = JSONObject.parseObject(jsonStr);
					if (!json.getString("errcode").equals("0")) {
						resultMap.put("code", json.getString("errcode"));
						resultMap.put("msg", json.getString("errmsg"));
					} else {
						resultMap.put("code", "200");
						resultMap.put("msg_id", json.getString("msg_id"));
						if (type.equals("mpnews")) {
							resultMap.put("msg_data_id", json.getString("msg_data_id"));
						}
					}
				}
			}else{
				paramMap.put("touser", openIds);
				jsonStr = HttpKit.Post(JSONObject.toJSONString(paramMap), post_url);
				logger.info("###### result-SendMassMSGWithOpenId:" + jsonStr);
				JSONObject json = JSONObject.parseObject(jsonStr);
				if (!json.getString("errcode").equals("0")) {
					resultMap.put("code", json.getString("errcode"));
					resultMap.put("msg", json.getString("errmsg"));
				} else {
					resultMap.put("code", "200");
					resultMap.put("msg_id", json.getString("msg_id"));
					if (type.equals("mpnews")) {
						resultMap.put("msg_data_id", json.getString("msg_data_id"));
					}
				}
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
			resultMap.put("code", "400");
			resultMap.put("msg", e.getMessage());
		}
		return resultMap;
	}
	public static void main(String[] args) {

			String [] arr = {"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};
			List<String> lists = Arrays.asList(arr);
		List<List<String>> list = Lists.partition(lists,10);
		System.out.println(JsonUtils.toJson(list));

	}


	/**
	 * 根据标签群发【订阅号与服务号认证后均可用】
	 *
	 * @param access_token
	 * @param msgtype             mpnews（图文）text（文本）voice（语音）image（图片）video（视频）
	 * @param mediaId             媒体ID
	 * @param send_ignore_reprint 图文消息被判定为转载时，是否继续群发。 1为继续群发（转载），0为停止群发
	 * @return
	 */
	public static Map<String, String> SendMassMSGAll(String msgtype, String access_token, Boolean is_to_all, Integer tag_id, String mediaId, int send_ignore_reprint) {
		Map<String, String> resultMap = new HashMap<>();
		try {
			String post_url = SendMassMessageAllUrl.replace("ACCESS_TOKEN", access_token);
			Map<String, Object> paramMap = new HashMap<>();
			if (msgtype.equals("mpnews")) {
				Map<String, Object> filterMap = new HashMap<>();
				filterMap.put("is_to_all", is_to_all);
				if (!is_to_all) {
					filterMap.put("tag_id", tag_id);
				}
				paramMap.put("filter", filterMap);
				Map<String, String> mediaIdMap = new HashMap<>();
				mediaIdMap.put("media_id", mediaId);
				paramMap.put("mpnews", mediaIdMap);
				paramMap.put("msgtype", msgtype);
				paramMap.put("send_ignore_reprint", send_ignore_reprint);
			} else {
				resultMap.put("code", "400");
				resultMap.put("msg", "暂无次功能！");
				return resultMap;
			}

			String jsonStr = HttpKit.Post(JSONObject.toJSONString(paramMap), post_url);
			//logger.info("###### result:{}", jsonStr);
			System.out.println("返回数据：" + jsonStr);
			JSONObject json = JSONObject.parseObject(jsonStr);
			if (!json.getString("errcode").equals("0")) {
				resultMap.put("code", json.getString("errcode"));
				resultMap.put("msg", json.getString("errmsg"));
			} else {
				resultMap.put("code", "200");
				resultMap.put("msg_id", json.getString("msg_id"));
				if (msgtype.equals("mpnews")) {
					resultMap.put("msg_data_id", json.getString("msg_data_id"));
				}

			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
			resultMap.put("code", "400");
			resultMap.put("msg", e.getMessage());
		}
		return resultMap;
	}

	//获取Video的URL
	private static String UploadVideoUrl = "https://api.weixin.qq.com/cgi-bin/media/uploadvideo?access_token=ACCESS_TOKEN";

	/**
	 * 获取video的mediaid
	 *
	 * @param access_token
	 * @param media_id
	 * @param title
	 * @param description
	 * @return
	 */
	public static String getMediaIdByVideo(String access_token, String media_id, String title, String description) {
		String post_url = UploadVideoUrl.replace("ACCESS_TOKEN", access_token);
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("media_id", media_id);
		paramMap.put("title", title);
		paramMap.put("description", description);
		String jsonStr = HttpKit.Post(JSONObject.toJSONString(paramMap), post_url);
		return jsonStr;
	}

	//获取永久素材url
	private static String GetMaterialUrl = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=ACCESS_TOKEN";

	/**
	 * 获取永久素材
	 *
	 * @param access_token
	 * @param media_id
	 * @return
	 */
	public static Map<String, String> getMaterial(String access_token, String media_id) {
		Map<String, String> resultMap = new HashMap<>();
		String post_url = GetMaterialUrl.replace("ACCESS_TOKEN", access_token);
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("media_id", media_id);
		String jsonStr = HttpKit.Post(JSONObject.toJSONString(paramMap), post_url);
		JSONObject json = JSONObject.parseObject(jsonStr);
		System.out.println(json);
		if (StringUtil.isNotEmpty(json.getString("errcode"))) {
			resultMap.put("code", "400");
			resultMap.put("msg", json.getString("errmsg"));
			return resultMap;
		}
		resultMap.put("code", "200");
		resultMap.put("data", jsonStr);
		return resultMap;
	}


	/**
	 * 修改永久图文素材
	 *
	 * @param access_token
	 * @param media_id
	 * @return
	 */
	public static Map<String, String> updateNews(String access_token, String media_id, WxArticle wxArticle, int index) {
		Map<String, String> resultMap = new HashMap<>();
		try {
			String post_url = UpdateNewsUrl.replace("ACCESS_TOKEN", access_token);
			Map<String, Object> paramMap = new HashMap<>();
			paramMap.put("media_id", media_id);
			paramMap.put("index", index);
			paramMap.put("articles", wxArticle);
			String jsonStr = HttpKit.Post(JSONObject.toJSONString(paramMap), post_url);

			JSONObject json = JSONObject.parseObject(jsonStr);
			if (!json.getString("errcode").equals("0")) {
				resultMap.put("code", json.getString("errcode"));
				resultMap.put("msg", json.getString("errmsg"));
			} else {
				resultMap.put("code", "200");

			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
			resultMap.put("code", "400");
			resultMap.put("msg", e.getMessage());
		}
		return resultMap;
	}

	/**
	 * 删除素材
	 *
	 * @param access_token
	 * @param media_id
	 * @return
	 */
	public static Map<String, String> deleteNews(String access_token, String media_id) {
		Map<String, String> resultMap = new HashMap<>();
		try {
			String post_url = DeleteNews.replace("ACCESS_TOKEN", access_token);
			Map<String, Object> paramMap = new HashMap<>();
			paramMap.put("media_id", media_id);
			String jsonStr = HttpKit.Post(JSONObject.toJSONString(paramMap), post_url);

			JSONObject json = JSONObject.parseObject(jsonStr);
			if (!json.getString("errcode").equals("0")) {
				resultMap.put("code", json.getString("errcode"));
				resultMap.put("msg", json.getString("errmsg"));
			} else {
				resultMap.put("code", "200");
			}
		} catch (Exception e) {
			System.out.println(e.getMessage());
			resultMap.put("code", "400");
			resultMap.put("msg", e.getMessage());
		}
		return resultMap;
	}
}
