package com.example.repurchase.calculation;


import com.example.repurchase.utils.DateUtils;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
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.DistanceUnit;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;

@Component
public class CalculateHousePrice {

    @Autowired
    private RestHighLevelClient restHighLevelClient;


    public void calculateHousePrice() throws Exception {

        SearchSourceBuilder sourceBuilderGender = new SearchSourceBuilder();
        sourceBuilderGender.query(QueryBuilders.boolQuery()
                        .must(QueryBuilders.existsQuery("Lat"))
                        .must(QueryBuilders.rangeQuery("Lat").gt(-120))
                        .mustNot(QueryBuilders.existsQuery("AnjukeHousePrice"))).size(4000);
        SearchRequest searchRequest = new SearchRequest("").source(sourceBuilderGender);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);


        SearchHits hits = searchResponse.getHits();

        Integer step = 2000;
        Integer num = 0;
        BulkRequest bulkRequest = new BulkRequest();
        bulkRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);

        for (SearchHit hit : hits) {
            num++;
            Map<String, Object> resultSet = hit.getSourceAsMap();
            List<Map<String, Object>> anjukeData = getAnjukeData(resultSet.get("Lat").toString() + "," + resultSet.get("Lng").toString(), 10.0f, "km");
            if (anjukeData.size() == 0) {
                anjukeData = getAnjukeData(resultSet.get("Lat").toString() + "," + resultSet.get("Lng").toString(), 1000.0f, "km");
            }
            if (anjukeData.size() > 0) {
//                System.out.println(resultSet.getString("id"));
                num += 1;
                Map<String, Object> anjukeDataMin = anjukeData.get(0);
                anjukeDataMin.put("LatLngTime", DateUtils.getCurrentTime());
                XContentBuilder xContentBuilder = jsonBuilder()
                        .startObject()
                        .field("AnjukeAddress", anjukeDataMin.get("AnjukeAddress"))
                        .field("AnjukeHousePrice", anjukeDataMin.get("AnjukeHousePrice"))
                        .field("AnjukeLat", anjukeDataMin.get("AnjukeLat"))
                        .field("AnjukeLng", anjukeDataMin.get("AnjukeLng"))
                        .field("distance", anjukeDataMin.get("range"))
                        .field("LatLngTime", DateUtils.getCurrentTime())
                        .endObject();
                IndexRequest indexRequest = new IndexRequest("user_lat_lng", resultSet.get("id").toString())
                        .source(xContentBuilder);

                UpdateRequest updateRequest = new UpdateRequest("user_lat_lng", resultSet.get("id").toString())
                        .doc(xContentBuilder).upsert(indexRequest);
                bulkRequest.add(updateRequest);
//                System.out.println(anjukeDataMin);
            }
            if (num % step == 0) {
                if (bulkRequest.numberOfActions() > 0) {
                    restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
                }
                System.out.println("插入了： " + num + " 条数据");
                bulkRequest = new BulkRequest();
            }
        }
        if (num % step != 0) {
            if (bulkRequest.numberOfActions() > 0) {
                restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
            }
            System.out.println("总共插入了： " + num + " 条数据");
        }
    }


    private List<Map<String, Object>> getAnjukeData(String location, Float range, String unit) throws Exception {
        List<Map<String, Object>> arrayList = new ArrayList<>();
        //分割 经纬度
        String[] slocation = location.split(",");
        Double lat = Double.parseDouble(slocation[0]);
        Double lon = Double.parseDouble(slocation[1]);

        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();


        searchSourceBuilder.from(0).size(1000);//查询多少条
        GeoDistanceQueryBuilder location1 = null;
        //按哪种长度单位去查找 km还是m
        if (unit.equals("km")) {
            location1 = QueryBuilders.geoDistanceQuery("Location").point(lat, lon)
                    .distance(range, DistanceUnit.KILOMETERS);
        } else if (unit.equals("m")) {
            location1 = QueryBuilders.geoDistanceQuery("Location").point(lat, lon)
                    .distance(range, DistanceUnit.METERS);
        }
        searchSourceBuilder.postFilter(location1);
        //获取距离多少公里 这个才是获取点与点之间距离的
        GeoDistanceSortBuilder sort = SortBuilders.geoDistanceSort("Location", lat, lon);
        //sort.unit(DistanceUnit.METERS);
        //排序
        sort.order(SortOrder.ASC);
        sort.point(lat, lon);
        searchSourceBuilder.sort(sort);

        SearchRequest searchRequest = new SearchRequest("anjuke_data").source(searchSourceBuilder);
        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        SearchHits hits = searchResponse.getHits();
        SearchHit[] searchHit = hits.getHits();
        //搜索耗时
        float userTime = searchResponse.getTook().getMillis() / 1000f;
        System.out.println("搜索附近的地址(" + hits.getTotalHits() + "个),耗时(" + userTime + "秒);");
        //获取搜索完后的信息
        for (SearchHit hit : searchHit) {
            Map<String, Object> map = new HashMap<>();
            map.put("AnjukeAddress", hit.getSourceAsMap().get("Address"));
            map.put("AnjukeHousePrice", hit.getSourceAsMap().get("HousePrice"));
            map.put("AnjukeLat", hit.getSourceAsMap().get("Location").toString().split(",")[0]);
            map.put("AnjukeLng", hit.getSourceAsMap().get("Location").toString().split(",")[1]);
            //获取距离值，并保留两位小数点
            BigDecimal geoDis = new BigDecimal((Double) hit.getSortValues()[0]);
            Object location2 = hit.getSourceAsMap().get("Location");
            Map<String, Object> hitMap = hit.getSourceAsMap();
            //计算距离
            hitMap.put("geoDistance", geoDis.setScale(0, BigDecimal.ROUND_HALF_DOWN));
            map.put("range", hit.getSourceAsMap().get("geoDistance"));
            arrayList.add(map);
//            System.out.println((String)hit.getSourceAsMap().get("Address")+"的坐标："+
//                    location2 + "与我的距离" +
//                    hit.getSourceAsMap().get("geoDistance") +
//                    DistanceUnit.METERS.toString());
        }
        return arrayList;
    }
}
