package com.yihu.hos.services;

import com.mongodb.*;
import com.yihu.hos.core.datatype.DateUtil;
import com.yihu.hos.core.datatype.NumberUtil;
import com.yihu.hos.core.datatype.StringUtil;
import com.yihu.hos.models.BusinessLog;
import com.yihu.hos.web.framework.model.Result;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Date;

/**
 * Created by chenweida on 2016/1/27.
 */
@Service("ServerMonitorService")
public class ServerMonitorService {
    public static final String BEAN_ID = "ServerMonitorService";
    public static final String reduceTableName = "reduceResult";

    @Autowired
    private MongoOperations mongoOperations;

//    public Result mapReduce(String beginTime, String endTime) {
//        DBCollection businessLogDB = mongoOperations.getCollection(mongoOperations
//                .getCollectionName(BusinessLog.class));
//
//        String map = "function(){emit(this.breadcrumbId, this.fireTime);}";
//        String reduce = "function(key, values){ return values[0];}";
//        String out = reduceTableName;
//        BasicDBObject queryObject = new BasicDBObject().append(QueryOperators.AND,
//                new BasicDBObject[]{
//                        new BasicDBObject().append("fireTime",
//                            new BasicDBObject().append(QueryOperators.GTE, DateUtil.toTimestamp(beginTime))),
//                        new BasicDBObject().append("fireTime",
//                                new BasicDBObject().append(QueryOperators.LT, DateUtil.toTimestamp(endTime)))});
//
//        MapReduceOutput mapReduceOutput = businessLogDB.mapReduce(map,
//                reduce.toString(), out, queryObject);
//        DBCollection resultColl = mapReduceOutput.getOutputCollection();
//        DBCursor cursor = resultColl.find();
//        String result = "";
//
//        while (cursor.hasNext()) {
//            result += cursor.next();
//        }
//        return Result.success(result);
//    }
//
//    public JSONObject aggregate(String beginTime, String endTime) {
//        DBCollection reduceDB = mongoOperations.getCollection(mongoOperations
//                .getCollectionName(ReduceResult.class));
//        BasicDBObject queryObject = new BasicDBObject().append(QueryOperators.AND,
//                new BasicDBObject[]{
//                        new BasicDBObject().append("value",
//                                new BasicDBObject().append(QueryOperators.GTE, DateUtil.toTimestamp(beginTime))),
//                        new BasicDBObject().append("value",
//                                new BasicDBObject().append(QueryOperators.LT, DateUtil.toTimestamp(endTime)))});
//
//        DBObject match = new BasicDBObject("$match", queryObject);
//
//        // Now the $group operation
//        DBObject groupFields = new BasicDBObject( "_id", new BasicDBObject("$minute", "$value"));
//        groupFields.put("pv", new BasicDBObject( "$sum", 1));
//        DBObject group = new BasicDBObject("$group", groupFields);
//
//        // build the $sort operation
//        DBObject sortFields =  new BasicDBObject( "_id", 1);
//        DBObject sort = new BasicDBObject("$sort", sortFields );
//        // run aggregation
//        AggregationOutput output = reduceDB.aggregate(match, group, sort);
//        String result = "";
//        for (DBObject dbObject : output.results()) {
//            result += dbObject.toString();
//        }
//        JSONObject jsonObject = new JSONObject(result);
//        return jsonObject;
//    }

    public Result bandwidth(String beginTime, String endTime) {
        DBCollection businessLog = mongoOperations.getCollection(mongoOperations
                .getCollectionName(BusinessLog.class));
        BasicDBObject queryObject = new BasicDBObject().append(QueryOperators.AND,
                new BasicDBObject[]{
                        new BasicDBObject().append("fireTime",
                                new BasicDBObject().append(QueryOperators.GTE, DateUtil.toTimestamp(beginTime))),
                        new BasicDBObject().append("fireTime",
                                new BasicDBObject().append(QueryOperators.LT, DateUtil.toTimestamp(endTime)))});

        DBObject match = new BasicDBObject("$match", queryObject);

        // Now the $group operation
        DBObject groupFields = new BasicDBObject( "_id", "$breadcrumbId");
        groupFields.put("count", new BasicDBObject( "$sum", 1));
        groupFields.put("beginTime", new BasicDBObject( "$first", "$fireTimeSource"));
        groupFields.put("endTime", new BasicDBObject( "$last", "$fireTimeSource"));
        DBObject group = new BasicDBObject("$group", groupFields);

        // build the $sort operation
        DBObject sortFields =  new BasicDBObject( "_id", 1);
        DBObject sort = new BasicDBObject("$sort", sortFields );
        // run aggregation
        AggregationOutput output = businessLog.aggregate(match, group, sort);
        Integer calls = 0;
        long interval = 0;
        for (DBObject dbObject : output.results()) {
            Integer count = Integer.parseInt(StringUtil.toString(dbObject.get("count")));
            if (count >= 2) {
                calls++;
                String begin = StringUtil.toString(dbObject.get("beginTime"));
                String end = StringUtil.toString(dbObject.get("endTime"));
                Date from = DateUtil.toTimestamp(begin, DateUtil.DEFAULT_YMDHMSDATE_FORMAT);
                Date to = DateUtil.toTimestamp(end, DateUtil.DEFAULT_YMDHMSDATE_FORMAT);
                interval += (to.getTime() - from.getTime())/1000;
            }
        }
        JSONObject result = new JSONObject();
        result.put("bandwidth", NumberUtil.divideBigDecimal(BigDecimal.valueOf(calls), BigDecimal.valueOf(interval)));
        return Result.success(result.toString());
    }

    public Result qps(String beginTime, String endTime) {
        DBCollection businessLog = mongoOperations.getCollection(mongoOperations
                .getCollectionName(BusinessLog.class));
        BasicDBObject queryObject = new BasicDBObject().append(QueryOperators.AND,
                new BasicDBObject[]{
                        new BasicDBObject().append("fireTime",
                                new BasicDBObject().append(QueryOperators.GTE, DateUtil.toTimestamp(beginTime))),
                        new BasicDBObject().append("fireTime",
                                new BasicDBObject().append(QueryOperators.LT, DateUtil.toTimestamp(endTime)))});

        DBObject match = new BasicDBObject("$match", queryObject);

        // Now the $group operation
        DBObject groupFields = new BasicDBObject( "_id", "$breadcrumbId");
        groupFields.put("count", new BasicDBObject( "$sum", 1));
        groupFields.put("total", new BasicDBObject( "$first", "$totalServers"));
        groupFields.put("beginTime", new BasicDBObject( "$first", "$fireTimeSource"));
        groupFields.put("endTime", new BasicDBObject( "$last", "$fireTimeSource"));
        DBObject group = new BasicDBObject("$group", groupFields);

        // build the $sort operation
        DBObject sortFields =  new BasicDBObject( "_id", 1);
        DBObject sort = new BasicDBObject("$sort", sortFields );
        // run aggregation
        AggregationOutput output = businessLog.aggregate(match, group, sort);
        Integer calls = 0;
        long interval = 0;
        for (DBObject dbObject : output.results()) {
            Integer count = Integer.parseInt(StringUtil.toString(dbObject.get("count")));
            if (count >= 2) {
                Integer total = Integer.parseInt(StringUtil.toString(dbObject.get("total")));
                if (total == count) {
                    calls++;
                    String begin = StringUtil.toString(dbObject.get("beginTime"));
                    String end = StringUtil.toString(dbObject.get("endTime"));
                    Date from = DateUtil.toTimestamp(begin, DateUtil.DEFAULT_YMDHMSDATE_FORMAT);
                    Date to = DateUtil.toTimestamp(end, DateUtil.DEFAULT_YMDHMSDATE_FORMAT);
                    interval += (to.getTime() - from.getTime())/1000;
                }
            }
        }
        JSONObject result = new JSONObject();
        result.put("qps", NumberUtil.divideBigDecimal(BigDecimal.valueOf(calls), BigDecimal.valueOf(interval)));
        return Result.success(result.toString());
    }

    public Result usage(String beginTime, String endTime) {
        DBCollection businessLog = mongoOperations.getCollection(mongoOperations
                .getCollectionName(BusinessLog.class));
        BasicDBObject queryObject = new BasicDBObject().append(QueryOperators.AND,
                new BasicDBObject[]{
                        new BasicDBObject().append("fireTime",
                                new BasicDBObject().append(QueryOperators.GTE, DateUtil.toTimestamp(beginTime))),
                        new BasicDBObject().append("fireTime",
                                new BasicDBObject().append(QueryOperators.LT, DateUtil.toTimestamp(endTime)))});

        DBObject match = new BasicDBObject("$match", queryObject);

        // Now the $group operation
        DBObject groupFields = new BasicDBObject( "_id", "$breadcrumbId");
        groupFields.put("count", new BasicDBObject( "$sum", 1));
        groupFields.put("total", new BasicDBObject( "$first", "$totalServers"));
        DBObject group = new BasicDBObject("$group", groupFields);

        // build the $sort operation
        DBObject sortFields =  new BasicDBObject( "_id", 1);
        DBObject sort = new BasicDBObject("$sort", sortFields );
        // run aggregation
        AggregationOutput output = businessLog.aggregate(match, group, sort);
        Integer successCount = 0;
        Integer failureCount = 0;
        for (DBObject dbObject : output.results()) {
            Integer total = Integer.parseInt(StringUtil.toString(dbObject.get("total")));
            Integer count = Integer.parseInt(StringUtil.toString(dbObject.get("count")));
            if (total == count) {
                successCount++;
            } else {
                failureCount++;
            }
        }
        JSONObject result = new JSONObject();
        result.put("totalCount", successCount + failureCount);
        result.put("successCount", successCount);
        result.put("failureCount", failureCount);
        return Result.success(result.toString());
    }

    public Result delay(String beginTime, String endTime) {
        DBCollection businessLog = mongoOperations.getCollection(mongoOperations
                .getCollectionName(BusinessLog.class));
        BasicDBObject queryObject = new BasicDBObject().append(QueryOperators.AND,
                new BasicDBObject[]{
                        new BasicDBObject().append("fireTime",
                                new BasicDBObject().append(QueryOperators.GTE, DateUtil.toTimestamp(beginTime))),
                        new BasicDBObject().append("fireTime",
                                new BasicDBObject().append(QueryOperators.LT, DateUtil.toTimestamp(endTime)))});

        DBObject match = new BasicDBObject("$match", queryObject);

        // Now the $group operation
        DBObject groupFields = new BasicDBObject( "_id", "$breadcrumbId");
        groupFields.put("count", new BasicDBObject( "$sum", 1));
        groupFields.put("beginTime", new BasicDBObject( "$first", "$fireTimeSource"));
        groupFields.put("endTime", new BasicDBObject( "$last", "$fireTimeSource"));
        DBObject group = new BasicDBObject("$group", groupFields);

        // build the $sort operation
        DBObject sortFields =  new BasicDBObject( "_id", 1);
        DBObject sort = new BasicDBObject("$sort", sortFields );
        // run aggregation
        AggregationOutput output = businessLog.aggregate(match, group, sort);
        Integer calls = 0;
        long interval = 0;
        for (DBObject dbObject : output.results()) {
            Integer count = Integer.parseInt(StringUtil.toString(dbObject.get("count")));
            if (count >= 2) {
                calls++;
                String begin = StringUtil.toString(dbObject.get("beginTime"));
                String end = StringUtil.toString(dbObject.get("endTime"));
                Date from = DateUtil.toTimestamp(begin, DateUtil.DEFAULT_YMDHMSDATE_FORMAT);
                Date to = DateUtil.toTimestamp(end, DateUtil.DEFAULT_YMDHMSDATE_FORMAT);
                interval += (to.getTime() - from.getTime())/1000;
            }
        }
        JSONObject result = new JSONObject();
        result.put("delay", NumberUtil.divideBigDecimal(BigDecimal.valueOf(interval), BigDecimal.valueOf(calls)));
        return Result.success(result.toString());
    }
}
