package com.winsun.service.impl;

import com.winsun.service.AccessStatisticService;
import com.winsun.utils.AccessStatisticDataSearchUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * luochengfeng
 */
@Slf4j
@Service
public class AccessStatisticServiceImpl implements AccessStatisticService {

    /**
     * 获取pv访问统计量列表
     * @return
     */
    public Map<String, Object> getPvStatisticsEchartData(Date startDate, Date endDate, String type, List<Integer> userIds) {

        SimpleDateFormat sdf = null;
        if ("hour".equals(type)) {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }else if("month".equals(type)) {
            sdf = new SimpleDateFormat("yyyy-MM");
        }else {
            sdf = new SimpleDateFormat("yyyy-MM-dd");
        }
        Map<String, Object> result = new HashMap<>();
        try {

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

            List<Integer> seriesData = new ArrayList<>();
            Calendar calendar = Calendar.getInstance();
            // 拆除数据
            JSONArray buckets = getAccessStatisticListData(startDate, endDate, type, userIds);
            JSONObject bucket = new JSONObject();
            for(Object jsonObject : buckets) {
                bucket = JSONObject.fromObject(jsonObject);
                if (bucket.get("key") == null || bucket.get("doc_count") == null) {
                    log.error("获取pv访问量列表部分数据错误：" + JSONObject.fromObject(bucket).toString());
                    break;
                }
                Long timestamp = bucket.getLong("key");
                calendar.setTimeInMillis(timestamp);
                if (startDate.getTime()/1000 <= calendar.getTimeInMillis()/1000) {
                    xAxisData.add(sdf.format(calendar.getTime()));
                    Integer docCount = bucket.getInt("doc_count");
                    seriesData.add(docCount);
                }
            }

            result.put("xAxisData", xAxisData);
            result.put("seriesData", seriesData);

        }catch(Exception e) {
            log.error("获取pv访问量列表错误" + e.getMessage());
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 获取uv访问统计量列表
     * @param startDate
     * @param endDate
     * @param type
     * @return
     */
    public Map<String, Object> getUvStatisticsEchartData(Date startDate, Date endDate, String type, List<Integer> userIds) {

        SimpleDateFormat sdf = null;
        if ("hour".equals(type)) {
            sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }else if("month".equals(type)) {
            sdf = new SimpleDateFormat("yyyy-MM");
        }else {
            sdf = new SimpleDateFormat("yyyy-MM-dd");
        }
        Map<String, Object> result = new HashMap<>();
        try {

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

            List<Integer> seriesData = new ArrayList<>();
            Calendar calendar = Calendar.getInstance();
            // 拆除数据
            JSONArray buckets = getAccessStatisticListData(startDate, endDate, type, userIds);
            log.info("uv数据：" + buckets);
            JSONObject bucket = new JSONObject();
            for(Object jsonObject : buckets) {
                bucket = JSONObject.fromObject(jsonObject);
                if (bucket.get("key") == null || bucket.get("userCount") == null) {
                    log.error("获取uv访问量列表部分数据错误：" + JSONObject.fromObject(bucket).toString());
                    break;
                }
                Long timestamp = bucket.getLong("key");
                calendar.setTimeInMillis(timestamp);
                if (startDate.getTime()/1000 <= calendar.getTimeInMillis()/1000) {
                    xAxisData.add(sdf.format(calendar.getTime()));
                    JSONObject userCount = JSONObject.fromObject(bucket.get("userCount"));
                    Integer value = userCount.getInt("value");
                    seriesData.add(value);
                }
            }

            result.put("xAxisData", xAxisData);
            result.put("seriesData", seriesData);
        }catch(Exception e) {
            log.error("获取uv访问量列表错误" + e.getMessage());
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 获取指定日期的pv、uv访问统计量
     * @param startDate
     * @param endDate
     * @return
     */
    public JSONArray getAccessStatisticListData(Date startDate, Date endDate, String type, List<Integer> userIds){

        JSONArray buckets = new JSONArray();

        // 判断用户id
        StringBuilder userIdsDql = new StringBuilder();
        if (userIds != null && userIds.size() > 0) {
            userIdsDql.append("(");
            for(int i = 0; i < userIds.size(); ++i) {
                userIdsDql.append("http_referer:*").append(userIds.get(i)).append("* ");
                if (userIds.size() != (i+1)) {
                    userIdsDql.append("OR ");
                }
            }
            userIdsDql.append(")");
        }
        log.info("统计用户：" + userIdsDql.toString());

        String dql = "{\"size\":0,\"query\":{\"bool\":{\"filter\":[{\"range\":{\"@timestamp\":{\"gte\":" + startDate.getTime() + ",\"lte\":" + endDate.getTime() +",\"format\":\"epoch_millis\"}}},{\"query_string\":{\"analyze_wildcard\":true,\"query\":\"request:*.do* " + userIdsDql.toString() + "\"}}]}},\"aggs\":{\"groupBy\": {\"date_histogram\": {\"field\": \"@timestamp\",\"interval\": \"" + type + "\"},\"aggs\":{\"userCount\":{\"cardinality\":{\"field\":\"remote_addr\"}}}}}}";
        log.info("dql：" + dql);
        try {
            String esSearch = AccessStatisticDataSearchUtils.esSearch(dql);
            log.info(esSearch);
            JSONObject json = JSONObject.fromObject(esSearch);
            JSONObject aggregations = JSONObject.fromObject(json.get("aggregations"));
            JSONObject groupBy = JSONObject.fromObject(aggregations.get("groupBy"));
            buckets = JSONArray.fromObject(groupBy.get("buckets"));
        }catch(Exception e) {
            log.error("处理数据异常，请检查数据格式是否正确");
            log.error(e.getMessage());
            e.printStackTrace();
        }
        return buckets;
    }
}
