package com.example.repurchase.getTags;

import com.example.repurchase.configuration.ElasticSearchPoolUtil;
import com.example.repurchase.utils.BaiDuMapUnit;
import com.example.repurchase.utils.DateUtils;
import com.example.repurchase.utils.HouseTagsUtils;
import com.example.repurchase.utils.TagsUtils;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.SocketTimeoutException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.*;

import static org.elasticsearch.index.query.QueryBuilders.*;

/**
 * @author 黄树文
 * @date 2020/2/25 15:33
 */

@Component
public class CalculateHousePriceTags {


    private Logger log = LoggerFactory.getLogger(CalculateHousePriceTags.class);

    @Autowired
    private TagsUtils tagsUtils;

    private static Integer nThreads = 16;

    private static ExecutorService fixedThreadPool = Executors.newFixedThreadPool(nThreads);

    /**
     * 多线程读取crm_memberbase_phoneid_v1中无经纬度的数据，爬取经纬度，获取价格，房价标签
     *
     * @param threadNum 并行数
     * @param step      每次并行的用户数
     * @throws InterruptedException
     * @throws BrokenBarrierException
     */
    public void runGetHouseTagsMultiThread(Integer threadNum, Integer step) throws Exception {

        threadCalculateHousePriceTags(1, 1);

        CountDownLatch countDownLatch = new CountDownLatch(threadNum);
        for (int i = 0; i < threadNum; i++) {
            Integer threadNumTemp = i;
            fixedThreadPool.submit(new Thread(() -> {
                try {
                    log.info("Thread:" + threadNumTemp + "准备完毕,time:" + System.currentTimeMillis() + "， 开始爬取数据");
                    threadCalculateHousePriceTags(threadNumTemp, step);
                    log.info("Thread:" + threadNumTemp + "爬取数据完毕,time:" + System.currentTimeMillis());
                } catch (Exception e) {
                    e.printStackTrace();
                    log.warn("Thread:" + threadNumTemp + "爬取数据失败,time:" + System.currentTimeMillis());
                } finally {
                    log.info("countDownLatch.countDown()");
                    countDownLatch.countDown();
                }
            }));
        }
        countDownLatch.await();
        log.info("执行结束");
    }

    /**
     * 读取crm_memberbase_phoneid_v1中没有经纬度房价标签的数据，计算经纬度，获取住房标签,------单线程
     *
     * @param threadNum 线程号
     * @param step      用户数
     * @throws SQLException
     * @throws IOException
     */
    public void threadCalculateHousePriceTags(Integer threadNum, Integer step) throws Exception {

        RestHighLevelClient restHighLevelClient = ElasticSearchPoolUtil.getClient();

        BoolQueryBuilder queryBuilder = boolQuery().mustNot(nestedQuery("Tags", matchQuery("Tags.TagTypeId", "8"),
                ScoreMode.None)).mustNot(matchQuery("MemUsualAddress", ""));

        // 获取ElasticSearch中无房价信息的用户的地理位置
        String[] fieldsInclude = {"MemUsualAddress", "Tags"};

        SearchResponse searchResponse = restHighLevelClient.search(new SearchRequest("crm_memberbase_phoneid_v1")
                        .source(new SearchSourceBuilder().query(queryBuilder).fetchSource(fieldsInclude, null).from(threadNum * step).size(step))
                , RequestOptions.DEFAULT);

        BulkRequest bulkRequest = new BulkRequest().timeout(TimeValue.timeValueMillis(2));
        bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);

        // 根据房价获取标签
        HashMap<String, Map<String, Object>> housePriceTagsAll = tagsUtils.getHousePriceTags();

        for (SearchHit hit : searchResponse.getHits()) {
            // 定义一个元素为map的ArrayLish集合
            ArrayList<Map<String, Object>> memberTags = new ArrayList<>();
            if(hit.getSourceAsMap().containsKey("Tags")){
                memberTags = (ArrayList<Map<String, Object>>) hit.getSourceAsMap().get("Tags");
            }
            String memUsualAddress = hit.getSourceAsMap().get("MemUsualAddress").toString();
            String id = hit.getId();
//            System.out.println(id);
            // 调用百度接口获取经纬度
            HashMap<String, Double> baiduResult = BaiDuMapUnit.getLatLng(memUsualAddress, threadNum);
            // 如果baiduResult不为null，则说明调用百度接口有返回值
            if (baiduResult != null) {
                Map<String, Object> hashmap = null;
                if (baiduResult.get("lat") != -120.0) {
                    // 查询安居客房价信息数据获取最近房价
                    Integer anjukeHousePrice = HouseTagsUtils.getHousePrice(restHighLevelClient, baiduResult, 10.0);
                    hashmap = housePriceTagsAll.get(tagsUtils.getHouseTag(anjukeHousePrice));
                    hashmap.put("TagCrtTime", DateUtils.getCurrentTime());
                    hashmap.put("lat", baiduResult.get("lat"));
                    hashmap.put("lng", baiduResult.get("lng"));
                } else {
                    hashmap = new HashMap<>();
                    hashmap.put("TagTypeName", "用户住房房价");
                    hashmap.put("TagTypeId", "8");
                    hashmap.put("TagName", "");
                    hashmap.put("TagId", "");
                    hashmap.put("TagKey", "");
                    hashmap.put("TagCrtTime", DateUtils.getCurrentTime());
                    hashmap.put("lat", baiduResult.get("lat"));
                    hashmap.put("lng", baiduResult.get("lng"));
                }

                Map<String, Object> finalHashmap = hashmap;
                if(memberTags != null  && memberTags.size()>0){
                    memberTags.removeIf(item -> finalHashmap.get("TagName").equals(item.get("TagName").toString()));
                }
                memberTags.add(hashmap);

            } else {
                continue;
            }

            UpdateRequest tagsUpdateRequest = new UpdateRequest("crm_memberbase_phoneid_v1", id).fetchSource("Tags", null)
                    .doc(XContentType.JSON, "Tags", memberTags).upsert();
            tagsUpdateRequest.retryOnConflict(5);

            bulkRequest.add(tagsUpdateRequest);

        }
        if (bulkRequest.numberOfActions() > 0) {
            try{
                restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            }catch (SocketTimeoutException e){
                restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
            }
            log.info("线程" + threadNum + "插入了" + String.valueOf(bulkRequest.numberOfActions()) + "条住房标签");
        }

        ElasticSearchPoolUtil.returnClient(restHighLevelClient);
    }
}
