package com.minxing365.connector.model;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.minxing365.connector.http.MxApi;
import com.minxing365.connector.json.JSONObject;
import com.minxing365.connector.utils.HMACSHA1;
import com.minxing365.connector.utils.StringUtil;

public class OfficialAccount {

		static Logger log = Logger.getLogger(OfficialAccount.class.getName());
		public MxApi mxApi = new MxApi(); 
		private final static int TEXT = 0;
		private final static int ARTICLE = 1;
		
		public boolean sendMessageToUsers(Message message, List<String> receivers) {
			String users = usersListToString(receivers);
			return sendMessageToUsersStr(message, users);
		}
		
		public boolean sendMessageToUsersStr(Message message, String users) {
			boolean result = false;
			if(message.getClass().equals(TextMessage.class)){
				result = post(message, TEXT, false, users);
			} else if(message.getClass().equals(ArticleMessage.class)){
				sendResourceForId((ArticleMessage)message);
				result = post(message, ARTICLE, false, users);
			}
			return result;
		}
		
		public boolean sendMessageToPublic(Message message) {
			boolean result = false;
			if(message.getClass().equals(TextMessage.class)){
				result = post(message, TEXT, true, null);
			} else if(message.getClass().equals(ArticleMessage.class)) {
				sendResourceForId((ArticleMessage)message);
				result = post(message, ARTICLE, true, null);
			}
			return result;
		}
		
		private void sendResourceForId(ArticleMessage message){
			List<Article> articles = message.getArticles();
			for(Article art : articles){
				if("resource".equals(art.getType())){
					Resource re = art.getResource();
					JSONObject resource;
					try {
						resource = mxApi.post("/conversations/ocu_resources", new PostParameter[]{new PostParameter("title", re.getTitle()),
								new PostParameter("sub_title", re.getSubTitle()), new PostParameter("author", re.getAuthor()),
								new PostParameter("create_time", re.getCreateTime()), new PostParameter("pic_url", re.getPicUrl()),
								new PostParameter("content", re.getContent())});
						art.setResourceId("" + ((Integer) resource.get("resource_id")));
					} catch (Exception e) {
						e.printStackTrace();
						continue;
					}
				}
			}
		}
		
		public boolean sendXmlMessageToUsers(String xml, String users){
			return sendMessageToUsersStr(transform(xml), users); 
		}
		
		public boolean sendXmlMessageToPublic(String xml){
			return sendMessageToPublic(transform(xml)); 
		}
		
		public String checkSignature(HttpServletRequest request){
			
			String token = null;
			String timestamp = null;
			String nonce = null;
			String openId = null;
			
			if(request != null && request.getMethod().equals("GET")){
				try {
					token = StringUtil.pathDecode(request.getParameter("token"));
					timestamp = request.getParameter("timestamp");
					nonce = request.getParameter("nonce");
					openId = StringUtil.pathDecode(request.getParameter("open_id"));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
					return null;
				}
				
			} else if (request != null && request.getMethod().equals("POST")){
				token = request.getHeader("token");
				timestamp = request.getHeader("timestamp");
				nonce = request.getHeader("nonce");
				openId = request.getHeader("open_id");
			}
			
			if(token == null || timestamp == null || nonce == null || openId == null){
				return null;
			}
			
			try {
				String sign = HMACSHA1.getSignature(timestamp + nonce, mxApi.getClientSercret());
				String t = mxApi.getClientId() + ":" + sign;
				if(t.equals(token)){
					return openId;
				}
				return null;
			} catch (MxException e) {
				e.printStackTrace();
				return null;
			}
		}
		
		public HashMap<String, String> checkSignature2(HttpServletRequest request){
			
			String token = null;
			String timestamp = null;
			String nonce = null;
			String openId = null;
			String body = null;
			
			HashMap<String, String> values = new HashMap<String, String>();
			if(request != null && request.getMethod().equals("GET")){
				try {
					token = StringUtil.pathDecode(request.getParameter("token"));
					timestamp = request.getParameter("timestamp");
					nonce = request.getParameter("nonce");
					openId = StringUtil.pathDecode(request.getParameter("open_id"));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
					return null;
				}
				
			} else if (request != null && request.getMethod().equals("POST")){
				token = request.getHeader("token");
				timestamp = request.getHeader("timestamp");
				nonce = request.getHeader("nonce");
				openId = request.getHeader("open_id");
				BufferedReader reader = null;
				try {
					StringBuilder sb = new StringBuilder();
					reader = request.getReader();
					String content = null;
					while((content = reader.readLine()) != null){
						sb.append(content);
					}
					body = sb.toString();
					System.out.println(body);
				} catch (IOException e) {
					e.printStackTrace();
					return null;
				}
				
			}
			
			if(token == null || timestamp == null || nonce == null || openId == null){
				return null;
			}
			
			try {
				String sign = HMACSHA1.getSignature(timestamp + nonce, mxApi.getClientSercret());
				String t = mxApi.getClientId() + ":" + sign;
				if(t.equals(token)){
					values.put("openId", openId);
					if(body != null){
						values.put("body", body);
					}
					return values;
				}
				return null;
			} catch (MxException e) {
				e.printStackTrace();
				return null;
			}
		}

		public User getUserInfo(String openId){
			try {
				JSONObject json = mxApi.get("/oauth/user_info/" + openId);
				Iterator iter = json.keys();
				User user = new User();
				while(iter.hasNext()){
					String key = (String)iter.next();
					Object obj = json.get(key);
					String value = "";
					
					if(obj != null && !obj.equals(JSONObject.NULL)){
						value = (String)obj;
					}
					key  = key.substring(0,1).toUpperCase() + key.substring(1); //first letter to uppercase
					
					Method[] methods = User.class.getMethods();
					for(Method m : methods){
						if(m.getName().equals("set" + key)){
							m.invoke(user, value);
						}
					}
				}
				return user;
			} catch (MxException e) {
				e.printStackTrace();
				return null;
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		}
		
		public int uploadResource(String resourceXml){
			Document document;
			try {
				document = DocumentHelper.parseText(resourceXml);
				Element root = document.getRootElement();
				String heading = root.elementText("heading");
				String subHeading = root.elementText("subheading");
				String author = root.elementText("author");
				String dateTime = root.elementText("datetime");
				
				Element contentEle = root.element("content");
				Element image = contentEle.element("image");
				String imageUrl = "";
				if(image != null){
					imageUrl = image.attributeValue("src");
				}
				List<Element> paragraphs = contentEle.elements("p");
				String content = "";
				for(Element p:paragraphs){
					content += "<p>" + p.getTextTrim() + "</p>";
				}
				
				JSONObject resource = mxApi.post("/conversations/ocu_resources", new PostParameter[]{new PostParameter("title", heading),
						new PostParameter("sub_title", subHeading), new PostParameter("author", author),
						new PostParameter("create_time", dateTime), new PostParameter("pic_url", imageUrl),
						new PostParameter("content", content)});
				return  (Integer) resource.get("resource_id");
			} catch (Exception e) {
				e.printStackTrace();
				return 0;
			}
			
		}
		
		private  boolean post(Message message, int type, boolean isPublic, String receivers){
			List<PostParameter> params = new ArrayList<PostParameter>();
			if(type == ARTICLE){
				ArticleMessage am = (ArticleMessage)message;
				System.out.println(am.getArticleBody());
				params.add(new PostParameter("body", am.getArticleBody()));
			} else {
				TextMessage tm = (TextMessage)message;
				params.add(new PostParameter("body", tm.getBody()));
			}
			
			if(!isPublic){
				if(receivers==null || receivers.trim().equals("")){
					log.error("Receiver list is null!");
					return false;
				}
				
				params.add(new PostParameter("direct_to_user_ids", receivers));
			}
			
			params.add(new PostParameter("content_type", type));
			
			try {
				mxApi.post("/conversations/ocu_messages", params.toArray(new PostParameter[params.size()]));
				return true;
			} catch (MxException e) {
				e.printStackTrace();
				return false;
			}
		}
		
		private Message transform(String xml){
			try {
				Message message = null;
				Document document = DocumentHelper.parseText(xml.trim());
				Element root = document.getRootElement();
				String type = root.attributeValue("type");
				if(type != null) {
					type = type.trim();
				}
				
				if("text".equals(type)){
					message = new TextMessage(root.getText());
				} else if ("richtext".equals(type)){
					Element header = root.element("header");
					Element title = header.element("title");
					Element image = root.element("image");
					
					String url = "";
					String appUrl = "";
					String headerImageUrl = "";
					if(image != null){
						Element action = image.element("action");
						if(action.attributeValue("type").equals("url")){
							url = action.attributeValue("url");
							url = getParams(action, url);
							
						}else if(action.attributeValue("type").equals("app")){
							appUrl = action.attributeValue("url");
							appUrl = getParams(action, appUrl);
						}
						headerImageUrl = image.attributeValue("src");
					}
					
					ArticleMessage am = new ArticleMessage();
					am.addArticle(new Article(title.getText(), "", headerImageUrl, url, appUrl));
					
					List<Element> items = root.elements("item");
					for(Element e: items){
						String text = e.attributeValue("text");
						String imageUrl = null;
						Element icon = e.element("icon");
						if(icon != null){
							imageUrl = icon.attributeValue("src");
						}
						
						Element itemAction = e.element("action");
						String actionType = itemAction.attributeValue("type");
						String actionUrl = itemAction.attributeValue("src");
						String actionAppUrl = "";
						String resourceId = "";
						if("url".equals(actionType)){
							actionUrl = getParams(itemAction, actionUrl);
						} else if("app".equals(actionType)){
							actionAppUrl = getAppParams(itemAction);
						} else if("resource".equals(actionType)){
							resourceId = itemAction.attributeValue("resId");
						}
						if(resourceId.trim().equals("")){
							am.addArticle(new Article(text, "", imageUrl, actionUrl, actionAppUrl));
						} else {
							am.addArticle(new Article(resourceId, "", ""));
						}
						
					}
					
					message = am;
				}
				return message;
			} catch (DocumentException e) {
				e.printStackTrace();
				return null;
			}
		}

		private String usersListToString(List<String> receivers){
			StringBuilder temp = new StringBuilder();
			for(int i=0, s = receivers.size(); i< s; i++){
				if(i != 0){
					temp.append(",");
				}
				temp.append(receivers.get(i));
			}
			return temp.toString();
		}
		
		private String getParams(Element action, String url) {
			Element paramEle = action.element("params");
			if(paramEle != null){
				List<Element> params = paramEle.elements("param");
				Element e = null;
				for(int i=0, j=params.size(); i<j; i++){
					e = params.get(i);
					if(i == 0){
						url += "?";
					} else {
						url += "&";
					}
					url += e.attributeValue("name") + "=" + e.getTextTrim();
				}
			}
			return url;
		}
		
		private String getAppParams(Element action){
			Element paramEle = action.element("params");
			String appUrl = "";
			if(paramEle != null){
				List<Element> params = paramEle.elements("param");
				Element e = null;
				for(int i=0, j=params.size(); i<j; i++){
					e = params.get(i);
					if(i != 0){
						appUrl += ",";
					}
					appUrl += e.attributeValue("name") + "=" + e.getTextTrim();
				}
			}
			return appUrl;
		}
		
}
