package com.reyun.service.impl;

import com.reyun.model.Account;
import com.reyun.model.UserGroup;
import com.reyun.repository.AccountRepository;
import com.reyun.repository.AppRepository;
import com.reyun.repository.EventtableMetadataRepository;
import com.reyun.repository.UserGroupRepository;
import com.reyun.service.AppService;
import com.reyun.service.AuthService;
import com.reyun.service.UserGroupService;
import com.reyun.taskexecute.UserGroupThread;
import com.reyun.util.Constant;
import com.reyun.util.ValidateUtil;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class UserGroupServiceImpl implements UserGroupService {

	@Autowired
	UserGroupRepository userGroupRepository;

	@Autowired
	EventtableMetadataRepository eventtableMetadataRepository;

	@Autowired
	AppRepository appRepository;

    @Autowired
    AppService appService;

	@Autowired
	AccountRepository accountRepository;

    @Autowired
    AuthService authService;

	@Override
	public UserGroup save(UserGroup userGroup, Long account) {
		userGroup.setAccount(account);
		userGroup.setCreateAccount(account);
		userGroup.setCreateTime(new Date());
		userGroup.setStatus(0);
		userGroup.setDataUpdateTime(new Date());
		Map<String, String> map = this.getSql(userGroup);
		String sql = map.get("sql");
		userGroup.setQuerySql(sql);

		UserGroup save = userGroupRepository.save(userGroup);

		UserGroupThread thread = new UserGroupThread(save,false);
		thread.start();
	
		return save;
	}

	@Override
	public UserGroup findById(Long id) {
		return userGroupRepository.findOne(id);
	}

	@Override
	public boolean refresh(Long id) {
		UserGroup findOne = userGroupRepository.findOne(id);
		if (findOne.getStatus() == 0) {
			return false;
		} else {
			findOne.setStatus(0);
			findOne.setDataUpdateTime(new Date());
			UserGroup save = userGroupRepository.save(findOne);
			UserGroupThread thread = new UserGroupThread(save,true);
			thread.start();
			return true;
		}
	}

	@Override
	public UserGroup update(UserGroup source, Long account) {
		UserGroup userGroup = userGroupRepository.findOne(source.getId());
		userGroup.setStartDate(source.getStartDate());
		userGroup.setEndDate(source.getEndDate());
		userGroup.setEventInfo(source.getEventInfo());
		userGroup.setMark(source.getMark());
		userGroup.setModifyAccount(account);
		userGroup.setModifyTime(new Date());
		userGroup.setUserType(source.getUserType());
		userGroup.setProfileInfo(source.getProfileInfo());
		userGroup.setName(source.getName());
		userGroup.setStatus(0);
		userGroup.setDataUpdateTime(new Date());
		Map<String, String> map = this.getSql(userGroup);
		String sql = map.get("sql");
		// String bucketStr = map.get("bucketid");
		userGroup.setQuerySql(sql);

		UserGroup save = userGroupRepository.save(userGroup);
		UserGroupThread thread = new UserGroupThread(save,true);
		thread.start();
		
		return save;
	}

	@Override
	public List<UserGroup> list(Long appId, Long accountId) {

		Account account = accountRepository.findOne(accountId);

        Account rootAccount = authService.findRootParentAccount(accountId);

        List<Account> children = accountRepository.findByParent(rootAccount.getId());

		Map<Long, String> map = new HashMap<>();
		Map<Long, String> emailMap = new HashMap<>();

		map.put(account.getId(), account.getName());
		emailMap.put(account.getId(), account.getEmail());
		if (ValidateUtil.isValid(children)) {
			for (Account acc : children) {
				map.put(acc.getId(), acc.getName());
				emailMap.put(acc.getId(), acc.getEmail());
			}
		}

		List<UserGroup> result =  userGroupRepository.listByApp(appId);

		if (ValidateUtil.isValid(result)) {
			for (UserGroup user : result) {
				user.setcAccount( !ValidateUtil.isValid(map.get(user.getAccount())) ? emailMap.get(user.getAccount()) : map.get(user.getAccount()));
				user.setmAccount(!ValidateUtil.isValid(map.get(user.getModifyAccount())) ? emailMap.get(user.getModifyAccount()) : map.get(user.getModifyAccount()));
                user.setNumber(user.getId()*3);
			}
		}

		return result;
	}
	
	@Override
	public List<UserGroup> list(Long app) {

		return userGroupRepository.listByApp(app);
	}

	@Override
	public UserGroup delete(Long id, Long account) {
		UserGroup userGroup = userGroupRepository.findOne(id);
		userGroup.setModifyAccount(account);
		userGroup.setModifyTime(new Date());
		userGroup.setDelFlag(true);
		UserGroup save = userGroupRepository.save(userGroup);
		return save;
	}

	@Override
	public Boolean valid(Long account, Long app, String name) {
		UserGroup userGroup = userGroupRepository
				.findByName(app, account, name);
		Boolean flag = true;
		if (userGroup == null) {
			flag = false;
		}
		return flag;
	}

	@Override
	public Map<String, String> getSql(UserGroup userGroup) {

		String appkey = appRepository.findAppkeyById(userGroup.getApp());
		String startDate = userGroup.getStartDate();
		String endDate = userGroup.getEndDate();

		String eventInfo = userGroup.getEventInfo();
		StringBuilder eventSB = new StringBuilder();
		if (ValidateUtil.isValid(eventInfo)) {
			JSONObject eventsObj = JSONObject.fromObject(eventInfo);
			String eventRelation = eventsObj.getString("relation");
			JSONArray eventArray = eventsObj.getJSONArray("events");

			List<String> eventNameList = new ArrayList<String>();
			for (int i = 0; i < eventArray.size(); i++) {
				JSONObject eventObject = eventArray.getJSONObject(i);
				String eventName = eventObject.getString("event");
				eventNameList.add(eventName);
				String proRelation = eventObject.getString("relation");
				if (i == 0) {
					eventSB.append(
							" xwho in ( select xwho from "
									+ Constant.eventTable + appkey + " where ")
							.append("ds>='").append(startDate)
							.append("' and ds<='").append(endDate)
							.append("' and xwhat ='").append(eventName)
							.append("' ");

				} else {
					eventSB.append(") ")
							.append(eventRelation)
							.append(" xwho in ( select xwho from "
									+ Constant.eventTable + appkey + " where ")
							.append("ds>='").append(startDate)
							.append("' and ds<='").append(endDate)
							.append("' and xwhat ='").append(eventName)
							.append("' ");
				}
				JSONArray params = eventObject.getJSONArray("params");
				if (params.size() > 0) {
					for (int j = 0; j < params.size(); j++) {

						JSONObject param = params.getJSONObject(j);

                        String attrName = param.getString("attr");
                        String typeName = attrName.equals("_cid") ? "number" : param.getString("type");
                        String values = param.getString("value");

						if (param.getString("operator").contains("in")) {

							if (typeName.contains("string") || typeName.contains("date")) {
								String value = values.replace(",", "','");
								if (j == 0) {
									eventSB.append("and (")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append(" ('").append(value)
											.append("') ");
								} else {
									eventSB.append(proRelation)
											.append(" ")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append("('").append(value)
											.append("') ");
								}
							} else {
								if (j == 0) {
									eventSB.append("and (")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append(" (").append(values)
											.append(") ");
								} else {
									eventSB.append(proRelation)
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append("(").append(values)
											.append(") ");
								}
							}
						} else if (param.getString("operator").contains("between")) {

							if (typeName.contains("string") || typeName.contains("date")) {

								String value = values.replace(",", "' and '");
								if (j == 0) {
									eventSB.append("and (")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append(" '").append(value)
											.append("' ");
								} else {
									eventSB.append(proRelation)
											.append(" ")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append(" '").append(value)
											.append("' ");
								}

							} else {
								String value = values.replace(",", " and ");
								if (j == 0) {
									eventSB.append("and (")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append(" ").append(value)
											.append(" ");
								} else {
									eventSB.append(proRelation)
											.append(" ")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append(" ").append(value)
											.append(" ");
								}
							}
						} else {
							if (typeName.contains("string") || typeName.contains("date")) {
								if (j == 0) {
									eventSB.append("and (")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append(" '").append(values)
											.append("' ");
								} else {
									eventSB.append(proRelation)
											.append(" ")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append(" '").append(values)
											.append("' ");
								}
							} else {
								if (j == 0) {
									eventSB.append("and (")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append(" ").append(values)
											.append(" ");
								} else {
									eventSB.append(proRelation)
											.append(" ")
											.append(attrName)
											.append(" ")
											.append(param.getString("operator"))
											.append(" ").append(values)
											.append(" ");
								}
							}

						}

					}
					eventSB.append(")");
				}
			}
		}
		StringBuilder result = new StringBuilder();
		String profileInfo = userGroup.getProfileInfo();
		if (ValidateUtil.isValid(profileInfo)) {
			JSONObject profileJson = JSONObject.fromObject(profileInfo);
			String relation = profileJson.getString("relation");
			JSONArray profilesJson = profileJson.getJSONArray("profiles");

			// 循环profilesJson获得每个属性的信息
			for (int i = 0; i < profilesJson.size(); i++) {
				// 数据类型
				String type = profilesJson.getJSONObject(i).getString("type");
				// 属性名儿
				String attr = profilesJson.getJSONObject(i).getString("attr");
				// 运算符
				String operator = profilesJson.getJSONObject(i).getString(
						"operator");
				// 属性值
				String value = profilesJson.getJSONObject(i).getString("value");

				result.append(attr).append(" ").append(operator).append(" ");

				/**
				 * 根据运算符不同拼接不同的sql语句
				 */

				// = < > >= <= 等直接加上value
				if (operator.equals("=") || operator.equals(">")
						|| operator.equals("<") || operator.equals(">=")
						|| operator.equals("<=")) {
					// string date的数据类型需要在值上加‘’
					if (type.equals("string") || type.equals("date")) {
						result.append("'").append(value).append("'");
					} else {
						result.append(value);
					}

				} else if (operator.equals("in") || operator.equals("not in")) {

					// 运算符是in not in需要加上（），遍历数组
					String[] array = value.split(",");
					result.append("(");
					// = < > >= <= 等直接加上value
					if (type.equals("string") || type.equals("date")) {
						for (int j = 0; j < array.length - 1; j++) {
							result.append("'").append(array[j]).append("'")
									.append(",");
						}
						result.append("'").append(array[array.length - 1])
								.append("'").append(")");
					} else {
						for (int j = 0; j < array.length - 1; j++) {
							result.append(array[j]).append(",");
						}
						result.append(array[array.length - 1]).append(")");
					}

				} else if (operator.equals("between")) {

					String[] array = value.split(",");
					// = < > >= <= 等直接加上value
					if (type.equals("date") || type.equals("string")) {
						result.append("'").append(array[0]).append(" and ")
								.append("'").append(array[1]).append("'");
					} else {
						result.append(array[0]).append(" and ")
								.append(array[1]);
					}

				}
				result.append(" ").append(relation).append(" ");
			}

			result.delete((result.toString().length())
					- (relation.length() + 1), result.toString().length() - 1);
		}

		// List<String> listBuckets = eventtableMetadataRepository.listBuckets(
		// appkey, userGroup.getStartDate(), userGroup.getEndDate(),
		// eventNameList);

		// String bucketStr = String.join("','", listBuckets);

		StringBuilder sqlSB = new StringBuilder();
		if (ValidateUtil.isValid(eventInfo)) {
			if (!ValidateUtil.isValid(profileInfo)) {
				sqlSB.append(
						"select xwho from " + Constant.eventTable + appkey
								+ " where(").append("_deviceid!='00000000-0000-0000-0000-000000000000' and ").append(eventSB.toString())
						.append("))");
			} else {
				sqlSB.append(
						"select xwho from " + Constant.eventTable + appkey
								+ " where(").append("_deviceid!='00000000-0000-0000-0000-000000000000' and ")
						.append(eventSB.toString())
						.append("))")
						.append(" and xwho in (select xwho from "
								+ Constant.profileTable + appkey + " where ")
						.append(" (").append("_deviceid!='00000000-0000-0000-0000-000000000000' and ")
						.append(result.toString()).append("))");
			}
		} else {
			sqlSB.append(
					"select xwho from " + Constant.profileTable + appkey
							+ " where ").append(" ( ").append("_deviceid!='00000000-0000-0000-0000-000000000000' and ")
					.append(result.toString()).append(")");
		}
		String query = sqlSB.toString();
		// String sql = query.replace("$", bucketStr);
		Map<String, String> map = new HashMap<String, String>();
		map.put("sql", query);
		// map.put("bucketid", bucketStr);
		return map;
	}

}
