package com.reyun.service.impl;

import com.google.common.base.Function;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.reyun.dic.CustomMenuType;
import com.reyun.dic.ReportEnumType;
import com.reyun.dic.RoleEnumType;
import com.reyun.model.*;
import com.reyun.repository.*;
import com.reyun.service.*;
import com.reyun.taskexecute.ReportCallable;
import com.reyun.util.*;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
 * Created by sunhao on 17/4/10.
 * description:时间分析service
 */
@Service
public class EventStatsServiceImpl implements EventStatsService {

    private Logger logger = LoggerFactory.getLogger(EventStatsServiceImpl.class);

    @Autowired
    EventService eventService;
    @Autowired
    EventStatsRepository eventStatsRepository;
    @Autowired
    EventViewAttrRepository eventViewAttrRepository;
    @Autowired
    EventRepository eventRepository;
    @Autowired
    AppRepository appRepository;
    @Autowired
    CustomMenuTemplateRepository customMenuTemplateRepository;
    @Autowired
    CommonParamService commonParamService;
    @Autowired
    UserGroupService userGroupService;
    @Autowired
    ConfigParamService configparamService;
    @Autowired
    AccountRepository accountRepository;
    @Autowired
    AuthService authService;
    @Autowired
    ReportService reportService;

    //分类维度 用户群
    private final static String DIMENSION_FIELD = "attr";
    private final static String DIMENSION_VALUES = "values";

    //SQL参数
    //开始时间
    private final static String SQL_START_DATE = "$startData";
    //结束时间
    private final static String SQL_END_DATE = "$endDate";
    //select字段
    private final static String SQL_SELECT_FIELD = "$selectFieldSql";
    //group字段
    private final static String SQL_GROUP_FIELD = "$groupFieldSql";
    //条件字段
    private final static String SQL_WHERE_FIELD = "$whereFieldSql";

    private final static String SQL_PARTICLE_DATE = "$selectDate";

    //按照设备,按照账户
    private final static String SQL_XWHO = "xwho";
    private final static String SQL_DEVICE_ID = "_deviceid";

    //显示粒度
    private final static String VIEW_PARTICLE_DAY = "day";
    private final static String VIEW_PARTICLE_WEEK = "week";
    private final static String VIEW_PARTICLE_MONTH = "month";

    //查询URI
    private final static String URI_REPORT_BY_SQL = "/api/trackingio/bysql";

    private final static String DIMENSION_TOTAL = "total";
    private final static String DIMENSION_USER_GROUP = "usergroup";
    private final static String SELECT_FIELD_TOTAL = ", '整体' as total";

    private final static String REPORT_CALLABLE_TYPE_EVENT = "eventstats";


    @Override
    public boolean checkEventStatsName(String eventStatsName, Long appId) {

        EventStats eventStats = eventStatsRepository.findEventStatsByName(eventStatsName, appId);

        return eventStats == null;
    }

    /**
     * 创建事件分析
     * 参数校验在controller层
     */
    @Override
    public EventStats createEventStats(EventStats eventStats) {

        //生成查询sql
        String appKey = appRepository.findAppkeyById(eventStats.getApp());

        String querySql = SqlUtil.generateEventStatsSqlTemplate(eventStats.getEventCondition(), appKey, getEventViewAttrMap());

        eventStats.setQuerySql(querySql);

        //校验生成的SQL
        if (StringUtil.isEmpty(querySql)) {

            return null;

        } else {

            return eventStatsRepository.save(eventStats);
        }
    }

    /**
     * 修改事件分析,修改event_condition和query_sql
     * 参数校验在controller层
     */
    @Override
    public int updateEventStats(EventStats eventStats, Long accountId) {

        EventStats findEventStats = eventStatsRepository.findEventStats(eventStats.getId());

        //生成SQL
        String appKey = appRepository.findAppkeyById(findEventStats.getApp());
        String querySql = SqlUtil.generateEventStatsSqlTemplate(eventStats.getEventCondition(), appKey, getEventViewAttrMap());

        //校验生成的SQL
        if (StringUtil.isEmpty(querySql)) {

            return 0;

        } else {

            return eventStatsRepository.updateEventStats(eventStats.getEventName(), eventStats.getEventCondition(),
                    querySql, accountId, findEventStats.getId(), new Date());
        }
    }

    /**
     * 删除事件分析
     */
    @Override
    public int deleteEventStats(Long eventStatsId, Long accountId) {

        //查看事件是否存在看单之中,如果存在则删除。
        List<Long> templateList = customMenuTemplateRepository.findTemplateByOriginal(eventStatsId, CustomMenuType.EVENT_STATS.getKey());
        if (!CollectionUtils.isEmpty(templateList)) {
            customMenuTemplateRepository.deleteTemplateByIds(accountId, templateList);
        }

        //删除事件
        return eventStatsRepository.deleteEventStats(accountId, eventStatsId, new Date());
    }

    /**
     * 查询所有事件
     */
    @Override
    public List<EventStats> findAllEventStats(Long accountId, Long appId) {
        return eventStatsRepository.findAll(appId, false);
    }

    /**
     * 查询事件分析数据
     * 参数校验在controller层
     */
    @Override
    public Map<String, List> queryEventStatsData(Long appId, Long accountId, String startDate, String endDate, String groupCondition,
                                                 boolean isDevice, String eventCondition, String viewFlag) {

        String appKey = appRepository.findAppkeyById(appId);
        Map<String, EventViewAttr> eventViewAttrMap = getEventViewAttrMap();
        String querySql = SqlUtil.generateEventStatsSqlTemplate(eventCondition, appKey, eventViewAttrMap);

        //查询sql nul
        if (StringUtil.isEmpty(querySql)) {
            return null;
        }

        querySql = querySql.replace("$campaign","");
        //默认聚合字段
        String groupField = "total";

        //查询时间粒度
        querySql = replaceQueryParticleDate(querySql, startDate, endDate, viewFlag);

        if (!StringUtil.isEmpty(groupCondition)) {

            JSONObject fieldGroupObject = JSONObject.fromObject(groupCondition);
            JSONArray values = fieldGroupObject.getJSONArray(DIMENSION_VALUES);

            groupField = fieldGroupObject.getString(DIMENSION_FIELD);

            if (DIMENSION_USER_GROUP.equals(groupField)) {
                //用户群分组对比
                return getUserGroupDimensionResponse(querySql, values, isDevice, appId, appKey, accountId, startDate, endDate, viewFlag);

            } else {
                //其他用户群对比
                return getOtherDimensionResponse(querySql, groupField, isDevice, appId, appKey, accountId, startDate, endDate, viewFlag);
            }
        }

        //非维度对比查询
        return getTotalResponse(appKey, querySql, groupField, isDevice, appId, accountId, startDate, endDate, viewFlag);

    }

    /**
     * 获取整体的查询结果
     * created by sunhao 20170515
     */
    private Map<String, List> getTotalResponse(String appKey, String querySql, String groupField, boolean isDevice, Long appId,
                                               Long accountId, String startDate, String endDate, String viewFlag) {

        querySql = replaceQuerySql(querySql, SELECT_FIELD_TOTAL, "", "", isDevice);

        Map<String, String> conditions = new HashMap<>();
        conditions.put("sql", querySql);
        conditions.put("dbtype", "presto");
        conditions.put("datatype", ReportEnumType.LIST.getCode());
        conditions.put("reportname", "eventstats");
        conditions.put("appid", appKey);


        Map<String, List> responseJson = reportService.reportBySql(conditions);


        return formatEventStatsReportData(responseJson, groupField, appId, accountId, startDate, endDate, viewFlag);

    }

    /**
     * 获取整体和其他维度对比查询结果
     * created by sunhao 20170515
     */
    private Map<String, List> getOtherDimensionResponse(String querySql, String groupField, boolean isDevice, Long appId,String appKey,
                                                        Long accountId, String startDate, String endDate, String viewFlag) {

        String totalSelect =  SELECT_FIELD_TOTAL;
        String dimensionSelect = getFieldSelectSql(groupField);
        String dimensionGroup = getFieldSelectSql(groupField);
        //整体
        String querySqlTotal = replaceQuerySql(querySql, totalSelect, "", "", isDevice);
        //维度
        String querySqlDimension = replaceQuerySql(querySql, dimensionSelect, dimensionGroup, "", isDevice);

        //demo账号处理 TODO

        return getTotalAndDimensionResult(querySqlTotal, querySqlDimension, groupField, startDate, endDate, appId, appKey, accountId, viewFlag, false);
    }

    /**
     * 获取整体和用户群对比查询的结果
     * created by sunhao 20170515
     */
    private Map<String, List> getUserGroupDimensionResponse(String querySql, JSONArray values, boolean isDevice, Long appId,String appKey,
                                                            Long accountId, String startDate, String endDate, String viewFlag) {

        String userGroupValue = values.getString(0);
        String totalSelect = SELECT_FIELD_TOTAL;
        String dimensionSelect = ",'" + userGroupValue + "' as " + DIMENSION_USER_GROUP;
        String dimensionWhere =  getUserGroupWhereSql(values.getString(0));

        //整体
        String querySqlTotal = replaceQuerySql(querySql, totalSelect, "", "", isDevice);
        //用户群维度
        String querySqlUser = replaceQuerySql(querySql, dimensionSelect, "", dimensionWhere, isDevice);

        //demo账号处理 TODO

        return getTotalAndDimensionResult(querySqlTotal, querySqlUser, values.getString(0), startDate, endDate, appId, appKey, accountId, viewFlag, true);
    }

    /**
     * 获取整体和分类维度合并的结果
     * created by sunhao 20170515
     */
    private Map<String, List> getTotalAndDimensionResult(String querySqlTotal, String querySqlDimension, String groupField, String startDate,
                                                         String endDate, Long appId, String appKey, Long accountId, String viewFlag, boolean isUserGroup) {

        Map<String, List> result = new HashMap<>();

        //创建一个线程池
        ExecutorService pool = Executors.newFixedThreadPool(2);

        try {
            //创建两个有返回值的任务
            ReportCallable callableTotal = new ReportCallable(REPORT_CALLABLE_TYPE_EVENT, querySqlTotal, DIMENSION_TOTAL,
                    startDate, endDate, viewFlag, appId, appKey, accountId, null);
            ReportCallable callableDimension = new ReportCallable(REPORT_CALLABLE_TYPE_EVENT, querySqlDimension, isUserGroup ? DIMENSION_USER_GROUP : groupField,
                    startDate, endDate, viewFlag, appId, appKey, accountId, groupField);
            //执行任务并获取Future对象
            Future<Map<String, List>> futureTotal = pool.submit(callableTotal);
            Future<Map<String, List>> futureDimension = pool.submit(callableDimension);
            Map<String, List> resultTotal = futureTotal.get();
            Map<String, List> resultDimension = futureDimension.get();

            //聚合两个结果
            if (isUserGroup) {

                result = combineResultOfUserGroup(resultTotal, resultDimension, groupField);

            } else {

                result = combineResultOfOtherDimension(resultTotal, resultDimension);
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            pool.shutdown();
        }

        return result;
    }

    /**
     * 聚合其他维度对比数据
     * 将resultDimension(多个维度的数据)的数据聚合到resultTotal中
     */
    private Map<String, List> combineResultOfOtherDimension(Map<String, List> resultTotal, Map<String, List> resultDimension){

        List<?> valueListTotal = resultTotal.get("val");
        List<?> valueListUser = resultDimension.get("val");
        List<String> columnKeyList = resultDimension.get("columnkey");
        List<String> nameList = resultDimension.get("name");

        if (!CollectionUtils.isEmpty(valueListUser) && !CollectionUtils.isEmpty(columnKeyList)) {

            columnKeyList.remove(0);
            nameList.remove(0);

            for (String columnKey : columnKeyList) {
                for (int i = 0; i < resultTotal.get("val").size(); i++) {
                    Map<String, Object> valueMap = (Map<String, Object>) valueListTotal.get(i);
                    valueMap.put(columnKey, ((Map<String, Object>) valueListUser.get(i)).get(columnKey));
                }
            }
        }

        resultTotal.get("name").addAll(nameList);
        resultTotal.get("columnkey").addAll(columnKeyList);

        return resultTotal;
    }

    /**
     * 聚合用户群对比查询结果
     * 将resultUser(单维度)数据聚合到resultTotal
     */
    private Map<String, List> combineResultOfUserGroup(Map<String, List> resultTotal, Map<String, List> resultUser, String userGroupValue) {

        UserGroup userGroup = userGroupService.findById(Long.parseLong(userGroupValue));

        List<?> valueListTotal = resultTotal.get("val");
        List<?> valueListUser = resultUser.get("val");

        if (CollectionUtils.isEmpty(valueListUser)) {

            for (int i = 0; i < resultTotal.get("val").size(); i++) {
                Map<String, Object> valueMap = (Map<String, Object>) valueListTotal.get(i);
                valueMap.put(userGroupValue, 0);
            }

        } else {

            for (int i = 0; i < resultTotal.get("val").size(); i++) {
                Map<String, Object> valueMap = (Map<String, Object>) valueListTotal.get(i);
                valueMap.put(userGroupValue, ((Map<String, Object>) valueListUser.get(i)).get(userGroupValue));
            }
        }

        resultTotal.get("name").add(userGroup.getName());
        resultTotal.get("columnkey").add(userGroupValue);

        return resultTotal;
    }

    /**
     * 替换SQL中的参数,对于关系如下
     * selectField:SQL_SELECT_FIELD
     * groupField:SQL_GROUP_FIELD
     * whereField:SQL_WHERE_FIELD
     * created by sunhao 20170515
     */
    private String replaceQuerySql(String querySql, String selectField, String groupField, String whereField, boolean isDevice) {

        querySql = querySql.replace(SQL_SELECT_FIELD, selectField);
        querySql = querySql.replace(SQL_GROUP_FIELD, groupField);
        querySql = querySql.replace(SQL_WHERE_FIELD, whereField);
        querySql = querySql.replaceAll(SQL_XWHO, isDevice ? SQL_DEVICE_ID : SQL_XWHO);

        return querySql;
    }

    /**
     * 获取用户群分组条件SQL
     * created by sunhao 20170515
     */
    private String getUserGroupWhereSql(String userGroupValue) {

        String userGroupSql = " and xwho in (select objectid as xwho from " + Constant.usergroupTable + " where id = '%' and objecttype = 'xwho') ";

        return userGroupSql.replace("%", userGroupValue);
    }

    /**
     * 替换查询粒度
     */
    private String replaceQueryParticleDate(String querySql, String startDate, String endDate, String viewFlag) {

        try {
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

            Date start = simpleDateFormat.parse(startDate);
            Date end = simpleDateFormat.parse(endDate);

            switch (viewFlag) {

                case VIEW_PARTICLE_DAY:
                    querySql = querySql.replace(SQL_START_DATE, startDate);
                    querySql = querySql.replace(SQL_END_DATE, endDate);
                    querySql = querySql.replace(SQL_PARTICLE_DATE, " ds ");
                    break;
                case VIEW_PARTICLE_WEEK:
                    querySql = querySql.replace(SQL_START_DATE, simpleDateFormat.format(DateUtil.getFirstDayOfWeek(start)));
                    querySql = querySql.replace(SQL_END_DATE, simpleDateFormat.format(DateUtil.getLastDayOfWeek(end)));
                    querySql = querySql.replace(SQL_PARTICLE_DATE, " date_format(date_parse(ds, '%Y-%m-%d'), '%Y%v') ");
                    break;
                case VIEW_PARTICLE_MONTH:
                    querySql = querySql.replace(SQL_START_DATE, DateUtil.getFirstDayOfMonth(start));
                    querySql = querySql.replace(SQL_END_DATE, DateUtil.getLastDayOfMonth(end));
                    querySql = querySql.replace(SQL_PARTICLE_DATE, " date_format(date_parse(ds, '%Y-%m-%d'), '%Y%m') ");
                    break;
                default:
                    querySql = querySql.replace(SQL_START_DATE, startDate);
                    querySql = querySql.replace(SQL_END_DATE, endDate);
                    querySql = querySql.replace(SQL_PARTICLE_DATE, " ds ");
                    break;
            }

        } catch (ParseException e) {
            logger.error(e.getMessage());
        }

        return querySql;
    }

    /**
     * 获取默认显示属性
     */
    private Map<String, EventViewAttr> getEventViewAttrMap() {

        List<EventViewAttr> eventViewAttrList = eventViewAttrRepository.findEventViewAttr();

        return Maps.uniqueIndex(eventViewAttrList, new Function<EventViewAttr, String>() {
            @Override
            public String apply(EventViewAttr eventViewAttr) {
                return eventViewAttr.getViewAttr();
            }
        });
    }

    /**
     * 生成带有,的字段 ,field
     */
    private String getFieldSelectSql(String field) {
        return ", " + field;
    }

    /**
     * 格式化sql查询出的数据
     */
    @Override
    public Map<String, List> formatEventStatsReportData(Map<String, List> responseResult, String groupField, Long appId, Long accountId,
                                                        String startDate, String endDate, String viewType) {

        Map<String, List> result = new HashMap<>();

        //获取时间范围内按照时间粒度的所有日期
        Map<String, String> dateStringMap = getDateMapByViewFlag(startDate, endDate, viewType);

        Map<String, JSONObject> valueMap = new HashMap<>();
        List<Map<String, Object>> valueResult = new ArrayList<>();
        List<String> nameList = Lists.newArrayList();
        List<String> columnKeyList = new ArrayList<>();
        List<String> keyList = new ArrayList<>();
        List<String> dateColumnList = new ArrayList<>();

        try {

            JSONObject responseObject = JSONObject.fromObject(responseResult);
            Object responseValueObject = responseObject.get("val");

            if (null != responseValueObject && !CollectionUtils.isEmpty((JSONArray) responseValueObject)) {

                JSONArray valueArray = (JSONArray) responseValueObject;

                //获取日期列表
                dateColumnList.addAll(dateStringMap.keySet());

                //筛选出所有的group内容
                for (int i = 0; i < valueArray.size(); i++) {

                    JSONObject valueObject = valueArray.getJSONObject(i);
                    String date = valueObject.getString("ds");
                    if (date.length() == 10 && viewType.equals("week")) {
                        date = DateUtil.getYYYYWW(date);
                    } else if (date.length() == 10 && viewType.equals("month")) {
                        date = DateUtil.getYYYYMM(date);
                    }

                    String columnKey = valueObject.getString(groupField);
                    if (!columnKeyList.contains(columnKey)) {

                        columnKeyList.add(columnKey);
                    }

                    valueMap.put(date + columnKey, valueObject);
                }

                //行转列
                for (String date : dateColumnList) {

                    Map<String, Object> rowValue = new HashMap<>();

                    rowValue.put("ds", dateStringMap.get(date));

                    for (String columnKey : columnKeyList) {

                        JSONObject value = valueMap.get(date + columnKey);
                        rowValue.put(columnKey, null != value ? value.get("sumdata") : 0);
                    }

                    valueResult.add(rowValue);
                }

                //排序,降序
                Collections.sort(valueResult, new Comparator<Map<String, Object>>() {

                    public int compare(Map<String, Object> o1, Map<String, Object> o2) {

                        return o2.get("ds").toString().compareTo(o1.get("ds").toString());
                    }
                });

                //转换渠道和活动名称
                nameList = getColumnNameList(appId, accountId, columnKeyList, groupField);

                //处理列名
                keyList = getKeyList(new ArrayList<>(dateStringMap.values()));
                columnKeyList.add(0, "ds");

            } else if (DIMENSION_TOTAL.equals(groupField)) {
                //整体的全零处理
                columnKeyList.add("ds");
                columnKeyList.add(groupField);

                nameList.add("日期");
                nameList.add("整体");

                keyList = getKeyList(new ArrayList<>(dateStringMap.values()));

                //数据补零
                for (String date : dateStringMap.values()) {
                    Map<String, Object> rowValue = new HashMap<>();
                    rowValue.put("ds", date);
                    rowValue.put(groupField,0);
                    valueResult.add(rowValue);
                }

                //排序,降序
                Collections.sort(valueResult, new Comparator<Map<String, Object>>() {

                    public int compare(Map<String, Object> o1, Map<String, Object> o2) {

                        return o2.get("ds").toString().compareTo(o1.get("ds").toString());
                    }
                });
            }

        } catch (Exception e) {
            logger.error(e.getMessage());
        }

        //设置结果
        result.put("val", valueResult);
        result.put("columnkey", columnKeyList);
        result.put("name", nameList);
        result.put("key", keyList);

        return result;
    }

    /**
     * 获取日期段的前半部分 降序排列
     */
    private List<String> getKeyList(List<String> keyNameList) {

        List<String> keyList = new ArrayList<>();

        for (String dateKey : keyNameList) {
            keyList.add(dateKey.substring(0, 10));
        }

        Collections.sort(keyList);

        return keyList;
    }


    /**
     * 获取列名中文名
     */
    private List<String> getColumnNameList(Long appId, Long accountId, List<String> columnKeyList, String groupField) {

        List<String> nameList = new ArrayList<>();

        nameList.add("日期");

        nameList.addAll(columnKeyList);

        return nameList;
    }

    /**
     * 根据查询粒度查询范围内的日期样式
     */
    private Map<String, String> getDateMapByViewFlag(String startDate, String endDate, String viewFlag) {

        Map<String, String> columnDateMap = new HashMap<>();

        switch (viewFlag) {

            case VIEW_PARTICLE_DAY:
                List<String> dayList = DateUtil.getDateInterval(startDate, endDate);

                for (String date : dayList) {
                    columnDateMap.put(date, date);
                }
                break;

            case VIEW_PARTICLE_WEEK:
                List<String> weekList = DateUtil.getEveryWeek(startDate, endDate);

                for (String week : weekList) {
                    columnDateMap.put(week, DateUtil.getFirstDayOfWeek(week) + "~" + DateUtil.getLastDayOfWeek(week));
                }

                break;

            case VIEW_PARTICLE_MONTH:
                List<String> monthList = DateUtil.getEveryMonth(startDate, endDate);

                for (String month : monthList) {
                    columnDateMap.put(month, DateUtil.getFirstdayOfMonth(month) + "~" + DateUtil.getLastdayOfMonth(month));
                }
                break;

            default:
                break;
        }

        return columnDateMap;
    }
}
