package com.sdtool.common.api;

import com.dySweetFishPlugin.elasticsearch.ESClient;
import com.dySweetFishPlugin.tool.lang.DateUtil;
import com.dySweetFishPlugin.tool.lang.ThreadFactoryWithNamePrefix;
import com.google.common.collect.Lists;
import com.sdtool.common.datas.ESKeys;
import com.sdtool.common.entity.system.OpLog;
import com.sweetfish.convert.json.JsonConvert;
import com.sweetfish.service.AbstractService;
import com.sweetfish.service.RetResult;
import com.sweetfish.source.PageFlipper;
import com.sweetfish.util.AnyValue;
import com.sweetfish.util.AutoLoad;
import com.sweetfish.util.ResourceType;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryAction;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
import org.rex.RMap;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by jlutt on 2018-08-02.
 *
 * @author jlutt
 */
@AutoLoad(false)
@ResourceType(OpLogService.class)
public class OpLogService extends AbstractService {


    private ThreadPoolExecutor opExecutor;

    @Resource
    ESClient esClient;

    @Resource
    JsonConvert jsonConvert;

    @Override
    public void init(AnyValue config) {
        BlockingQueue<Runnable> queue = new LinkedBlockingQueue<>(Integer.MAX_VALUE);

        //执行任务线程池
        opExecutor = new ThreadPoolExecutor(
                5,
                10,
                30000,
                TimeUnit.SECONDS,
                queue,
                new ThreadFactoryWithNamePrefix("[操作日志线程池]")
        );
    }

    @Override
    public void start(AnyValue config) {

    }

    @Override
    public void destroy(AnyValue config) {
        if (opExecutor != null) {
            opExecutor.shutdown();
        }
    }

    public int put(OpLog opLog, long supplierCode) {
        //ResourceFactory.root().inject(opLog);
        opExecutor.execute(() -> esClient.getClient().prepareIndex(ESKeys.ESOPLOG_INDEX + "_" + supplierCode, ESKeys.ESERPDEFAULT_TYPE)
                .setSource(jsonConvert.convertTo(opLog), XContentType.JSON)
                .get());

        return 1;
    }

    @SuppressWarnings("rawtypes")
    public RetResult<List<OpLog>> getOpLogList(RMap searchData, PageFlipper pageFlipper, long supplierCode) {
        //从es中获取

        BoolQueryBuilder qb = QueryBuilders.boolQuery();

        if (searchData != null) {
            if ((searchData.containsKey("userName")) && (StringUtils.isNotEmpty(searchData.getString("userName")))) {
                String keyWord = "\"" + searchData.getString("userName") + "\"";
                qb = qb.must(QueryBuilders.queryStringQuery(keyWord).field("userName"));
            }
            if ((searchData.containsKey("clientIp")) && (StringUtils.isNotEmpty(searchData.getString("clientIp")))) {
                String keyWord = "\"" + searchData.getString("clientIp") + "\"";
                qb = qb.must(QueryBuilders.queryStringQuery(keyWord).field("clientIp"));
            }
            if ((searchData.containsKey("url")) && (StringUtils.isNotEmpty(searchData.getString("url")))) {
                String keyWord = "\"" + searchData.getString("url") + "\"";
                qb = qb.must(QueryBuilders.queryStringQuery(keyWord).field("url"));
            }
            if ((searchData.containsKey("beginTime")) && (StringUtils.isNotEmpty(searchData.getString("beginTime")))) {
                Date beginDate = DateUtil.asDate(searchData.getString("beginTime"), "yyyy-MM-dd");
                qb = qb.must(QueryBuilders.rangeQuery("opDate").gte(DateUtil.getStartOfDay(beginDate).getTime()));
            }
            if ((searchData.containsKey("endTime")) && (StringUtils.isNotEmpty(searchData.getString("endTime")))) {
                Date endDate = DateUtil.asDate(searchData.getString("endTime"), "yyyy-MM-dd");
                qb = qb.must(QueryBuilders.rangeQuery("opDate").lte(DateUtil.getEndOfDay(endDate).getTime()));
            }
            if ((searchData.containsKey("beginTimeLong")) && (StringUtils.isNotEmpty(searchData.getString("beginTimeLong")))) {
                long beginTimeLong = searchData.getLong("beginTimeLong");
                qb = qb.must(QueryBuilders.rangeQuery("opDate").gte(beginTimeLong));
            }
            if ((searchData.containsKey("endTimeLong")) && (StringUtils.isNotEmpty(searchData.getString("endTimeLong")))) {
                long endTimeLong = searchData.getLong("endTimeLong");
                qb = qb.must(QueryBuilders.rangeQuery("opDate").lte(endTimeLong));
            }
        }

        SearchRequestBuilder requestBuilder = esClient.getClient().prepareSearch(ESKeys.ESOPLOG_INDEX + "_" + supplierCode, ESKeys.ESOPLOG_INDEX + "_0")
                .setTypes(ESKeys.ESERPDEFAULT_TYPE)
                .setQuery(qb)
                .addSort("opDate", SortOrder.DESC)
                .setSize(pageFlipper.getPageSize())
                .setFrom(pageFlipper.getPageSize() * (pageFlipper.getPageIndex() - 1));

        SearchHits searchHits = requestBuilder.execute().actionGet().getHits();

        List<OpLog> logList = Lists.newLinkedList();
        searchHits.forEach(x -> {
            String json = x.getSourceAsString();

            OpLog opLog = jsonConvert.convertFrom(OpLog.class, json);
            opLog.setEsId(x.getId());
            opLog.setEsIndex(x.getIndex());

            logList.add(opLog);
        });

        pageFlipper.setTotal(searchHits.getTotalHits());

        return RetResult.<List<OpLog>>successT().result(logList).page(pageFlipper);
    }

    public RetResult<OpLog> viewOpLog(String esId, String esIndex, long supplierCode) {
        //从es中获取

        QueryBuilder qb = QueryBuilders.idsQuery().addIds(esId);

        String searchIndex = StringUtils.isBlank(esIndex) ? ESKeys.ESOPLOG_INDEX + "_" + supplierCode : esIndex;
        SearchRequestBuilder requestBuilder = esClient.getClient().prepareSearch(searchIndex)
                .setTypes(ESKeys.ESERPDEFAULT_TYPE)
                .setQuery(qb)
                .setSize(1);

        SearchHits searchHits = requestBuilder.execute().actionGet().getHits();

        if (searchHits.getTotalHits() == 0) {
            return RetResult.<OpLog>errorT().retinfo("未找到对应的操作记录");
        } else {
            SearchHit hit = searchHits.getHits()[0];
            OpLog opLog = jsonConvert.convertFrom(OpLog.class, hit.getSourceAsString());
            opLog.setEsId(hit.getId());

            return RetResult.<OpLog>successT().result(opLog);
        }
    }

    @SuppressWarnings("rawtypes")
    public RetResult<OpLog> deleteOpLogList(RMap searchData, long supplierCode) {
        BoolQueryBuilder qb = QueryBuilders.boolQuery();

        if (searchData != null) {
            if ((searchData.containsKey("userName")) && (StringUtils.isNotEmpty(searchData.getString("userName")))) {
                String keyWord = "\"" + searchData.getString("userName") + "\"";
                qb = qb.must(QueryBuilders.queryStringQuery(keyWord).field("userName"));
            }
            if ((searchData.containsKey("clientIp")) && (StringUtils.isNotEmpty(searchData.getString("clientIp")))) {
                String keyWord = "\"" + searchData.getString("clientIp") + "\"";
                qb = qb.must(QueryBuilders.queryStringQuery(keyWord).field("clientIp"));
            }
            if ((searchData.containsKey("url")) && (StringUtils.isNotEmpty(searchData.getString("url")))) {
                String keyWord = "\"" + searchData.getString("url") + "\"";
                qb = qb.must(QueryBuilders.queryStringQuery(keyWord).field("url"));
            }
            if ((searchData.containsKey("beginTime")) && (StringUtils.isNotEmpty(searchData.getString("beginTime")))) {
                Date beginDate = DateUtil.asDate(searchData.getString("beginTime"), "yyyy-MM-dd");
                qb = qb.must(QueryBuilders.rangeQuery("opDate").gte(DateUtil.getStartOfDay(beginDate).getTime()));
            }
            if ((searchData.containsKey("endTime")) && (StringUtils.isNotEmpty(searchData.getString("endTime")))) {
                Date endDate = DateUtil.asDate(searchData.getString("endTime"), "yyyy-MM-dd");
                qb = qb.must(QueryBuilders.rangeQuery("opDate").lte(DateUtil.getEndOfDay(endDate).getTime()));
            }

            if ((searchData.containsKey("beginTimeLong")) && (StringUtils.isNotEmpty(searchData.getString("beginTimeLong")))) {
                long beginTimeLong = searchData.getLong("beginTimeLong");
                qb = qb.must(QueryBuilders.rangeQuery("opDate").gte(beginTimeLong));
            }
            if ((searchData.containsKey("endTimeLong")) && (StringUtils.isNotEmpty(searchData.getString("endTimeLong")))) {
                long endTimeLong = searchData.getLong("endTimeLong");
                qb = qb.must(QueryBuilders.rangeQuery("opDate").lte(endTimeLong));
            }
        }

        //异步操作，不是什么重要数据，让es慢慢删去

        DeleteByQueryAction.INSTANCE.newRequestBuilder(esClient.getClient())
                .refresh(true)
                .source(ESKeys.ESOPLOG_INDEX + "_" + supplierCode, ESKeys.ESOPLOG_INDEX + "_0")
                .filter(qb)
                .execute(new ActionListener<>() {
                    //回调监听
                    @Override
                    public void onResponse(BulkByScrollResponse response) {
                        logger.info("删除操作日志：" + response.getDeleted());
                    }

                    @Override
                    public void onFailure(Exception e) {
                        // Handle the exception
                        logger.error(e.getMessage(), e);
                    }
                });

        return RetResult.successT();
    }
}
