package org.outstudio.wxtest.util;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.List;

import org.easywechat.msg.Article;
import org.easywechat.msg.BaseMsg;
import org.easywechat.msg.ImageMsg;
import org.easywechat.msg.MusicMsg;
import org.easywechat.msg.NewsMsg;
import org.easywechat.msg.RespType;
import org.easywechat.msg.TextMsg;
import org.easywechat.msg.VideoMsg;
import org.easywechat.msg.VoiceMsg;
import org.easywechat.msg.req.BaseReq;
import org.easywechat.msg.req.EventType;
import org.easywechat.msg.req.LocationEvent;
import org.easywechat.msg.req.MenuEvent;
import org.easywechat.msg.req.TextReqMsg;
import org.easywechat.util.MessageFactory;
import org.jsoup.Connection;
import org.jsoup.Connection.Method;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.parser.Parser;
import org.jsoup.select.Elements;

/**
 * 与微信相关的工具类
 */
public class WechatUtil {

	/**
	 * 模拟发送文本消息
	 * 
	 * @return 响应信息,一般为XML格式
	 * @throws IOException
	 */
	public static String sendText(String token, String url, String text)
			throws IOException {
		String realUrl = buildUrl(token, url);
		String xmlData = createTextReqMsg(text).toXml();

		String resp = getConn(realUrl).rawData(xmlData).execute().body();

		return resp;
	}

	/**
	 * 模拟发送菜单点击事件
	 * 
	 * @return 响应信息,一般为XML格式
	 * @throws IOException
	 */
	public static String sendClickEvent(String token, String url,
			String eventKey) throws IOException {
		String realUrl = buildUrl(token, url);
		String xmlData = createMenuClickEvent(eventKey).toXml();
		System.out.println(xmlData);

		String resp = getConn(realUrl).rawData(xmlData).execute().body();

		return resp;
	}

	/**
	 * 模拟发送地理位置事件
	 * 
	 * @return 响应信息,一般为XML格式
	 * @throws IOException
	 */
	public static String sendLocationEvent(String token, String url,
			double latitude, double longitude, double precision)
			throws IOException {
		String realUrl = buildUrl(token, url);
		String xmlData = createLocationEvent(latitude, longitude, precision)
				.toXml();

		String resp = getConn(realUrl).rawData(xmlData).execute().body();

		return resp;
	}

	/**
	 * 模拟发送XML数据
	 * 
	 * @return 响应信息,一般为XML格式
	 * @throws IOException
	 */
	public static String sendXml(String token, String url, String xml)
			throws IOException {
		String realUrl = buildUrl(token, url);

		String resp = getConn(realUrl).rawData(xml).execute().body();

		return resp;
	}

	public static Document getDocFromXml(String xml) {
		return Jsoup.parse(xml, "", Parser.xmlParser());
	}

	/**
	 * 解析Document得到微信响应消息对象
	 * 
	 * @throws Exception
	 *             如果解析失败
	 */
	public static BaseMsg getMsgFromDoc(Document doc) throws Exception {

		String toUserName = getTagValue("ToUserName", doc);
		String fromUserName = getTagValue("FromUserName", doc);
		String rawCreateTime = getTagValue("CreateTime", doc);
		long createTime = Long.parseLong(rawCreateTime);

		String msgType = getTagValue("MsgType", doc);

		BaseMsg msg;

		if (msgType.equals(RespType.TEXT)) {
			String content = getTagValue("Content", doc);
			msg = MessageFactory.createTextMsg(content);
		} else if (msgType.equals(RespType.NEWS)) {

			NewsMsg newsMsg = MessageFactory.createNewsMsg();

			Elements items = doc.getElementsByTag("item");
			for (Element item : items) {
				String title = getTagValue("Title", item);
				String description = getTagValue("Description", item);
				String picUrl = getTagValue("PicUrl", item);
				String Url = getTagValue("Url", item);

				newsMsg.add(title, description, picUrl, Url);
			}
			msg = newsMsg;
		} else if (msgType.equals(RespType.IMAGE)) {
			String mediaId = getTagValue("MediaId", doc);
			msg = MessageFactory.createImageMsg(mediaId);
		} else if (msgType.equals(RespType.VOICE)) {
			String mediaId = getTagValue("MediaId", doc);
			msg = MessageFactory.createVoiceMsg(mediaId);
		} else if (msgType.equals(RespType.VIDEO)) {
			String mediaId = getTagValue("MediaId", doc);
			String title = getTagValue("Title", doc);
			String description = getTagValue("Description", doc);
			msg = MessageFactory.createVideoMsg(mediaId, title, description);
		} else if (msgType.equals(RespType.MUSIC)) {
			String title = getTagValue("Title", doc);
			String description = getTagValue("Description", doc);
			String musicUrl = getTagValue("MusicUrl", doc);
			String hqMusicUrl = getTagValue("HQMusicUrl", doc);
			String thumbMediaId = getTagValue("ThumbMediaId", doc);
			msg = MessageFactory.createMusicMsg(thumbMediaId, title,
					description, musicUrl, hqMusicUrl);
		} else {
			return null;
		}

		msg.setFromUserName(fromUserName);
		msg.setToUserName(toUserName);
		msg.setCreateTime(createTime);

		return msg;
	}

	/**
	 * 得到解析后的消息对象
	 */
	public static String getPrettyString(BaseMsg msg) {
		StringBuilder sb = new StringBuilder();
		String space = "  ";

		if (msg instanceof TextMsg) {
			TextMsg textMsg = (TextMsg) msg;
			sb.append("文本消息:\n");
			sb.append(space).append("Content:").append(textMsg.getContent())
					.append("\n");
		} else if (msg instanceof ImageMsg) {
			ImageMsg imageMsg = (ImageMsg) msg;
			sb.append("图片消息:\n");
			sb.append(space).append("MediaId:").append(imageMsg.getMediaId())
					.append("\n");
		} else if (msg instanceof VoiceMsg) {
			VoiceMsg voiceMsg = (VoiceMsg) msg;
			sb.append("语音消息:\n");
			sb.append(space).append("MediaId:").append(voiceMsg.getMediaId())
					.append("\n");
		} else if (msg instanceof VideoMsg) {
			VideoMsg videoMsg = (VideoMsg) msg;
			sb.append("视频消息:\n");
			sb.append(space).append("MediaId:").append(videoMsg.getMediaId())
					.append("\n");
			sb.append(space).append("Title:").append(videoMsg.getTitle())
					.append("\n");
			sb.append(space).append("Description:")
					.append(videoMsg.getDescription()).append("\n");
		} else if (msg instanceof MusicMsg) {
			MusicMsg musicMsg = (MusicMsg) msg;
			sb.append("视频消息:\n");
			sb.append(space).append("Title:").append(musicMsg.getTitle())
					.append("\n");
			sb.append(space).append("Description:")
					.append(musicMsg.getDescription()).append("\n");
			sb.append(space).append("MusicUrl:").append(musicMsg.getMusicUrl())
					.append("\n");
			sb.append(space).append("HQMusicUrl:")
					.append(musicMsg.getHqMusicUrl()).append("\n");
			sb.append(space).append("ThumbMediaId:")
					.append(musicMsg.getThumbMediaId()).append("\n");
		} else if (msg instanceof NewsMsg) {
			NewsMsg newsMsg = (NewsMsg) msg;
			sb.append("图文消息:\n");
			List<Article> articles = newsMsg.getArticles();
			for (int i = 0; i < articles.size(); i++) {
				sb.append(space).append("第 ").append(i + 1).append(" 条:\n");

				Article article = articles.get(i);

				String title = article.getTitle();
				String description = article.getDescription();
				String picUrl = article.getPicUrl();
				String url = article.getUrl();

				if (title != null) {
					sb.append(space).append(space).append("Title:")
							.append(title).append("\n");
				}
				if (description != null) {
					sb.append(space).append(space).append("Description:")
							.append(description).append("\n");
				}
				if (picUrl != null) {
					sb.append(space).append(space).append("PicUrl:")
							.append(picUrl).append("\n");
				}
				if (url != null) {
					sb.append(space).append(space).append("Url:").append(url)
							.append("\n");
				}
			}
		}

		sb.append("\n");
		sb.append("FromUserName:").append(msg.getFromUserName()).append("\n");
		sb.append("ToUserName:").append(msg.getToUserName()).append("\n");
		long createTime = msg.getCreateTime();
		sb.append("CreateTime:").append(createTime).append("(")
				.append(getDatetimeFromCreateTime(createTime)).append(")\n");

		return sb.toString();
	}

	/**
	 * 将微信消息的CreateTime解析成格式化的日期时间字符串
	 */
	public static String getDatetimeFromCreateTime(long createTime) {
		String raw = String.valueOf(createTime);
		String strTime = StringUtil.paddingRight(raw, '0', 13);
		long time = Long.parseLong(strTime);
		return new Timestamp(time).toString().substring(0, 19);
	}

	/**
	 * 得到适合该项目的Connection对象
	 */
	private static Connection getConn(String url) {
		return Jsoup.connect(url).header("Content-Type", "application/json")
				.ignoreContentType(true).timeout(10000).method(Method.POST);
	}

	private static String buildUrl(String token, String rawUrl) {
		StringBuilder sb = new StringBuilder(rawUrl);

		String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
		String nonce = "zzz";
		String signature = SignatureUtil.getSignature(token, timestamp, nonce);

		sb.append("?signature=").append(signature).append("&timestamp=")
				.append(timestamp).append("&nonce=").append(nonce);
		return sb.toString();
	}

	private static TextReqMsg createTextReqMsg(String content) {
		TextReqMsg msg = new TextReqMsg(content);
		buildReqBody(msg);
		return msg;
	}

	private static MenuEvent createMenuClickEvent(String eventKey) {
		MenuEvent event = new MenuEvent(eventKey);
		event.setEvent(EventType.CLICK);
		buildReqBody(event);
		return event;
	}

	private static LocationEvent createLocationEvent(double latitude,
			double longitude, double precision) {
		LocationEvent event = new LocationEvent(latitude, longitude, precision);
		event.setEvent(EventType.LOCATION);
		buildReqBody(event);
		return event;
	}

	private static void buildReqBody(BaseReq req) {
		req.setFromUserName("FromUserName");
		req.setToUserName("ToUserName");
		req.setCreateTime(System.currentTimeMillis() / 1000);
	}

	private static String getTagValue(String tagName, Element ele) {
		Elements eles = ele.getElementsByTag(tagName);
		return eles.isEmpty() ? null : eles.get(0).text();
	}

}