package com.mosty.yjzl.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mosty.base.model.dto.jcgl.TbJcglXfqyDto;
import com.mosty.base.model.dto.yjzl.TbZlxxInsertDto;
import com.mosty.base.model.dto.yjzl.TbZlxxZxrDtoInsertDto;
import com.mosty.base.model.entity.qwzx.TbQwXfbb;
import com.mosty.base.model.entity.sjzx.TbJq;
import com.mosty.base.model.entity.yjzl.*;
import com.mosty.base.model.query.yjzl.TbZxzbQuery;
import com.mosty.base.model.vo.base.DeptInfoVo;
import com.mosty.base.utils.Constant;
import com.mosty.base.utils.DateUtils;
import com.mosty.base.utils.Kit;
import com.mosty.base.utils.UUIDGenerator;
import com.mosty.common.redis.service.RedisService;
import com.mosty.yjzl.cluster.DistanceRunnable;
import com.mosty.yjzl.cluster.NeighborDTO;
import com.mosty.yjzl.cluster.WGS84Point;
import com.mosty.yjzl.mapper.*;
import com.mosty.yjzl.remote.TbBaseAdaptRemoteService;
import com.mosty.yjzl.remote.TbJcglAdaptRemoteService;
import com.mosty.yjzl.remote.TbQwzxAdaptRemoteService;
import com.mosty.yjzl.service.TbZlxxService;
import com.mosty.yjzl.service.TbZxzbService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.locationtech.jts.geom.Coordinate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.stream.Collectors;

/**
 * 中心坐标服务器
 */
@Service
@AllArgsConstructor
public class TbZxzbServiceImpl extends ServiceImpl<TbZxzbMapper, TbZxzb>
        implements TbZxzbService {

    private final TbYjxxMapper tbYjxxMapper;
    private final TbFzycMapper tbFzycMapper;
    private final TbBaseAdaptRemoteService tbBaseAdaptRemoteService;
    private final TbJcglAdaptRemoteService tbJcglAdaptRemoteService;
    private final TbFzycJsdxMapper tbFzycJsdxMapper;
    private final TbQwzxAdaptRemoteService tbQwzxAdaptRemoteService;
    private final TbZlxxService tbZlxxService;
    private final TbFzycXfxzMapper tbFzycXfxzMapper;
    private final RedisService redisService;

    @Override
    public IPage<TbZxzb> queryListPage(TbZxzbQuery zxzbQuery) {
        IPage<TbZxzb> page = this.baseMapper.selectPage(
                new Page<>(zxzbQuery.getPageNum(), zxzbQuery.getPageSize()),
                new LambdaQueryWrapper<TbZxzb>()
                        .eq(TbZxzb::getZblx, zxzbQuery.getZblx())
                        .eq(StringUtils.isNotBlank(zxzbQuery.getZbrq()), TbZxzb::getZbrq, zxzbQuery.getZbrq())
                        .orderByDesc(TbZxzb::getZxdsl)
        );
        return page;
    }

    @Override
    public List<TbZxzb> queryList(TbZxzbQuery zxzbQuery) {
        List<TbZxzb> list = this.baseMapper.selectList(
                new LambdaQueryWrapper<TbZxzb>()
                        .eq(TbZxzb::getZblx, zxzbQuery.getZblx())
                        .eq(StringUtils.isNotBlank(zxzbQuery.getZbrq()), TbZxzb::getZbrq, zxzbQuery.getZbrq())
                        .orderByDesc(TbZxzb::getZxdsl)
        );
        return list;
    }

    @Override
    public void computeCenter(String startTime, String endTime) {
        if (StringUtils.isEmpty(endTime)) {
            endTime = DateUtils.getHDateString();
        }
        if (StringUtils.isEmpty(startTime)) {
            String queryDateString = DateUtils.getQueryDateString(new Date(), "16");
            if (queryDateString.equals("09")) {
                startTime = DateUtils.getQueryDateString(DateUtils.getNextDate(new Date(), "H", -8), "02");
            } else {
                startTime = DateUtils.getQueryDateString(DateUtils.getNextDate(new Date(), "H", -4), "02");
            }

        }
//        int xldw = 1;//默认相邻点位10
//        String xldws = tbBaseAdaptRemoteService.getValue("ZXZB_XLDWSL");
//        if (StringUtils.isNotBlank(xldws)) {
//            //有配置取配置相邻点位
//            xldw = Integer.valueOf(xldws);
//        }

        //用于定位本地获取方块区域
        String uuid = UUIDGenerator.getUUID();

        List<TbJq> jqList = this.tbYjxxMapper.queryJq(startTime, endTime);
        Set<WGS84Point> points = new HashSet<>();
        if (!CollectionUtils.isEmpty(jqList)) {
            for (TbJq jq : jqList) {
                if (jq.getJd() != null && jq.getWd() != null) {
                    points.add(new WGS84Point(jq.getWd().doubleValue(), jq.getJd().doubleValue(), jq.getSsbmdm()));
                }
            }
        }
        if (points.size() > 0) {
            this.baseMapper.deleteAll("01");
            ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(100);
            List<NeighborDTO> neighborList = Collections.synchronizedList(new ArrayList<>(30000));
//            int counter = 0;
            for (WGS84Point point : points) {
                // 计算每个点一定范围内所有点坐标
                threadPool.execute(new DistanceRunnable(point, points, neighborList, 1000));
//                System.out.println(++counter);
            }
            // 等待线程池执行完毕
            while (neighborList.size() != points.size()) {
                System.out.println(neighborList.size());
            }
            threadPool.shutdown();
            // 排序
            Collections.sort(neighborList);
            // 筛选
            Map<WGS84Point, Long> map = new HashMap<>();
            Iterator<NeighborDTO> it = neighborList.iterator();
            while (it.hasNext()) {
                NeighborDTO neighborDTO = (NeighborDTO) it.next();
                Map<WGS84Point, Long> neighbors = neighborDTO.getNeighbors();
                if (map.containsKey(neighborDTO.getPoint())) {
                    it.remove();
                }
                map.putAll(neighbors);
            }
            if (!CollectionUtils.isEmpty(neighborList)) {
                //查询所有巡防区
                List<TbJcglXfqyDto> listXfqyAll = this.tbJcglAdaptRemoteService.getListXfqyAll();


                Map<String, List<TbFzycJsdx>> xqMap = new HashMap<>();
                //查询最后一条数据的的标示
                TbFzyc fzyc1 = this.tbFzycMapper.selectOne(new LambdaQueryWrapper<TbFzyc>().orderByDesc(TbFzyc::getXtCjsj).last(" limit 1"));
                if (ObjectUtils.isNotEmpty(fzyc1)) {
                    String dwId = fzyc1.getDwId();
                    if (StringUtils.isNotEmpty(dwId)) {
                        List<TbFzycJsdx> tbFzycJsdxes = this.tbFzycJsdxMapper.selectList(new LambdaQueryWrapper<TbFzycJsdx>().eq(TbFzycJsdx::getDwId, dwId).isNotNull(TbFzycJsdx::getXfqId));
                        if (ObjectUtils.isNotEmpty(tbFzycJsdxes)) {
                            xqMap = tbFzycJsdxes.stream().filter(s -> StringUtils.isNotEmpty(s.getXfqId())).collect(Collectors.groupingBy(TbFzycJsdx::getXfqId));
                        }
                    }
                }
                List<TbFzyc> fzycList = new ArrayList<>();
                // 业务操作
                for (NeighborDTO neighborDTO : neighborList) {
                    WGS84Point point = neighborDTO.getPoint();
                    Map<WGS84Point, Long> neighbors = neighborDTO.getNeighbors();
                    int size = neighbors.size() + 1;
                    //半径
                    Map<String, double[]> mapPoint = returnLLSquarePoint(point.getLongitude(), point.getLatitude(), 150);
                    double[] leftTopPoint = mapPoint.get("leftTopPoint");
                    double[] rightBottomPoint = mapPoint.get("rightBottomPoint");
                    BigDecimal x1 = BigDecimal.valueOf(leftTopPoint[1]);
                    BigDecimal y1 = BigDecimal.valueOf(leftTopPoint[0]);
                    BigDecimal x2 = BigDecimal.valueOf(rightBottomPoint[1]);
                    BigDecimal y2 = BigDecimal.valueOf(rightBottomPoint[0]);
                    TbFzyc fzyc = new TbFzyc();
                    fzyc.setId(UUIDGenerator.getUUID());
                    fzyc.setRealDate(endTime.substring(0, 10));
                    fzyc.setX1(x1);
                    fzyc.setY1(y1);
                    fzyc.setX2(x2);
                    fzyc.setY2(y2);
                    fzyc.setGridType("300");
                    fzyc.setProb(BigDecimal.valueOf(size));
                    DeptInfoVo dept = this.tbBaseAdaptRemoteService.getOrgByOrgcode(point.getSsbmdm());
                    if (ObjectUtils.isNotEmpty(dept)) {
                        fzyc.setSsbm(dept.getDeptname());
                        fzyc.setSsbmid(dept.getDeptid());
                        fzyc.setSsbmdm(dept.getDeptcode());
                        fzyc.setSsxgajdm(dept.getFxjcode());
                        fzyc.setSsxgajid(dept.getFxjid());
                        fzyc.setSsxgaj(dept.getFxjname());
                        fzyc.setSssgaj(dept.getDszname());
                        fzyc.setSssgajdm(dept.getDszcode());
                        fzyc.setSssgajid(dept.getDszid());
                    } else {
                        fzyc.setSsbm("四川省德阳市公安局");
                        fzyc.setSsbmid("44015");
                        fzyc.setSsbmdm("510600000000");
                        fzyc.setSsxgajdm("510600000000");
                        fzyc.setSsxgajid("44015");
                        fzyc.setSsxgaj("四川省德阳市公安局");
                        fzyc.setSssgaj("四川省德阳市公安局");
                        fzyc.setSssgajdm("510600000000");
                        fzyc.setSssgajid("44015");
                    }

                    fzyc.setXtSjzt("1");
                    fzyc.setXtScbz("0");
                    fzyc.setXtCjsj(new Timestamp(System.currentTimeMillis()));
                    BigDecimal X = x1.add(x2.subtract(x1).divide(new BigDecimal(2)));
                    BigDecimal Y = y1.add(y2.subtract(y1).divide(new BigDecimal(2)));
                    fzyc.setZxX(X);
                    fzyc.setZxY(Y);
                    fzyc.setDwId(uuid);
                    fzyc.setBc(startTime.substring(11, 13) + "-" + endTime.substring(11, 13));

//                    //根据点位计算在那个巡区上
//                    Set<String> xfq = new HashSet<>();
                    if (!CollectionUtils.isEmpty(listXfqyAll)) {
                        int cs = 0;
                        for (TbJcglXfqyDto dto : listXfqyAll) {
                            //特警大队 机动一 二 三不生成方块
                            if (!dto.getSsbmdm().equals("510700440300") && !dto.getSsbmdm().equals("510700440400") && !dto.getSsbmdm().equals("510700440500") && !dto.getSsbmdm().equals("510700440600")) {
                                Coordinate[] coordinates = new Coordinate[dto.getPgis().size()];
                                for (int i = 0; i < dto.getPgis().size(); i++) {
                                    BigDecimal[] jwd = dto.getPgis().get(i);
                                    Coordinate coor = new Coordinate();
                                    coor.x = jwd[0].doubleValue();
                                    coor.y = jwd[1].doubleValue();
                                    coordinates[i] = coor;
                                }
                                boolean s = Kit.isInGeometry(coordinates, X + "," + Y);
                                if (s) {
                                    TbFzycJsdx tbFzycJsdx = new TbFzycJsdx();
                                    BeanUtils.copyProperties(dto, tbFzycJsdx);
                                    tbFzycJsdx.setId(UUIDGenerator.getUUID());
                                    tbFzycJsdx.setFzycId(fzyc.getId());
                                    tbFzycJsdx.setXfqId(dto.getId());
                                    tbFzycJsdx.setXfqMc(dto.getXfqMc());
                                    tbFzycJsdx.setDwId(uuid);
                                    cs += tbFzycJsdxMapper.insert(tbFzycJsdx);
                                    //本地区域已经有数据 删除上次区域数据
                                    xqMap.remove(dto.getId());
                                    //下发指令
                                    List<TbQwXfbb> xfbbs = this.tbQwzxAdaptRemoteService.getBbidByXq(dto.getId());
                                    for (TbQwXfbb bb : xfbbs) {
                                        TbZlxxInsertDto zldto = new TbZlxxInsertDto();
                                        zldto.setYwId(fzyc.getId());
                                        zldto.setZllx("09");
                                        zldto.setZlly("09");
                                        zldto.setZlzxlx("1");
                                        zldto.setZlbt("犯罪预测");
                                        zldto.setZlnr("次区域内发生" + size + "起警情,请加强巡逻");
                                        zldto.setZldj("40");
                                        zldto.setZljsdx("03");
                                        zldto.setJd(X);
                                        zldto.setWd(Y);
                                        zldto.setZlfsddxzqh(fzyc.getSsbmdm().substring(0, 6));
                                        zldto.setZljsrs(1);
                                        zldto.setSsbmid(bb.getSsbmid());
                                        zldto.setSsbmdm(bb.getSsbmdm());
                                        zldto.setSsbm(bb.getSsbm());
                                        zldto.setSsbm(bb.getSsbm());
                                        zldto.setZlxflx("4");
                                        List<TbZlxxZxrDtoInsertDto> zxrDtoList = new ArrayList<>();
                                        TbZlxxZxrDtoInsertDto zxr = new TbZlxxZxrDtoInsertDto();
                                        zxr.setZxrLx("03").setZxrXzid(bb.getId()).setZxrXzmc(bb.getJzMc());
                                        zxrDtoList.add(zxr);
                                        zldto.setZxrDtoList(zxrDtoList);
                                        String zlid = tbZlxxService.addZl(zldto);
                                        TbFzycXfxz xfxz = new TbFzycXfxz();
                                        BeanUtils.copyProperties(tbFzycJsdx, xfxz);
                                        xfxz.setId(UUIDGenerator.getUUID());
                                        xfxz.setBbId(bb.getId());
                                        xfxz.setZlId(zlid);
                                        xfxz.setSfqs("0");
                                        String xzmc = bb.getJzMc();
                                        if (StringUtils.isEmpty(xzmc)) {
                                            xzmc = bb.getFzrXm() + "警组";
                                        }
                                        xfxz.setXzmc(xzmc);
                                        this.tbFzycXfxzMapper.insert(xfxz);
                                    }
                                }
                            }
                        }
                        if (cs > 0) {
                            fzycList.add(fzyc);
                            this.tbFzycMapper.insert(fzyc);
                            //查询警情部门是否添加
                            int jsc = this.tbFzycJsdxMapper.selectCount(new LambdaQueryWrapper<TbFzycJsdx>()
                                    .eq(TbFzycJsdx::getFzycId, fzyc.getId())
                                    .eq(TbFzycJsdx::getSsbmdm, point.getSsbmdm())
                            );
                            if (jsc < 1) {
                                //不管有没有都存到到对象里面
                                TbFzycJsdx tbFzycJsdx = new TbFzycJsdx();
                                BeanUtils.copyProperties(fzyc, tbFzycJsdx);
                                tbFzycJsdx.setId(UUIDGenerator.getUUID());
                                tbFzycJsdx.setFzycId(fzyc.getId());
                                tbFzycJsdx.setDwId(uuid);
                                tbFzycJsdxMapper.insert(tbFzycJsdx);
                            }
                        }

                    }


                }
                //上次存在的区域 本次没有定位
                if (ObjectUtils.isNotEmpty(xqMap)) {
                    List<TbFzycJsdx> jsdxList = new ArrayList<>();
                    for (String k : xqMap.keySet()) {
                        jsdxList.addAll(xqMap.get(k));
                    }
                    Map<String, List<TbFzycJsdx>> fzMap = jsdxList.stream().collect(Collectors.groupingBy(TbFzycJsdx::getFzycId));
                    Set<String> setFz = jsdxList.stream().map(TbFzycJsdx::getFzycId).collect(Collectors.toSet());
                    List<TbFzyc> tbFzycs = this.tbFzycMapper.selectList(new LambdaQueryWrapper<TbFzyc>().in(TbFzyc::getId, setFz));
                    for (TbFzyc fzyc : tbFzycs) {
                        List<TbFzycJsdx> jsdxList1 = fzMap.get(fzyc.getId());
                        fzyc.setLsId(fzyc.getId());
                        fzyc.setId(UUIDGenerator.getUUID());
                        fzyc.setDwId(uuid);
                        fzyc.setSfxl("0");
                        fzyc.setRealDate(endTime.substring(0, 10));
                        fzyc.setBc(startTime.substring(11, 13) + "-" + endTime.substring(11, 13));
                        fzyc.setXtCjsj(new Timestamp(System.currentTimeMillis()));
                        fzycList.add(fzyc);
                        this.tbFzycMapper.insert(fzyc);
                        for (TbFzycJsdx jsdx : jsdxList1) {
                            jsdx.setId(UUIDGenerator.getUUID());
                            jsdx.setFzycId(fzyc.getId());
                            jsdx.setLsId(fzyc.getId());
                            jsdx.setDwId(uuid);
                            jsdx.setXtCjsj(new Timestamp(System.currentTimeMillis()));
                            tbFzycJsdxMapper.insert(jsdx);

                        }
                    }
                }
                redisService.setCacheObject(Constant.FZYC_LIST, fzycList);
                redisService.setCacheObject(Constant.FZYC_BC, startTime.substring(11, 13) + "-" + endTime.substring(11, 13));
            }
        }
    }

    /**
     * 根据经纬度，获取正方形四个点位
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @param distance  范围（米）  半径
     * @return
     */
    public static Map<String, double[]> returnLLSquarePoint(double longitude, double latitude, double distance) {
        Map<String, double[]> squareMap = new HashMap<String, double[]>();
        // 计算经度弧度,从弧度转换为角度
        double dLongitude = 2 * (Math.asin(Math.sin(distance / (2 * 6378137)) / Math.cos(Math.toRadians(latitude))));
        dLongitude = Math.toDegrees(dLongitude);
        // 计算纬度角度
        double dLatitude = distance / 6378137;
        dLatitude = Math.toDegrees(dLatitude);
        // 正方形
        //左上角
        double[] leftTopPoint = {latitude + dLatitude, longitude - dLongitude};
        //右上角
        double[] rightTopPoint = {latitude + dLatitude, longitude + dLongitude};
        //左下角
        double[] leftBottomPoint = {latitude - dLatitude, longitude - dLongitude};
        //右下角
        double[] rightBottomPoint = {latitude - dLatitude, longitude + dLongitude};
        squareMap.put("leftTopPoint", leftTopPoint);
        squareMap.put("rightTopPoint", rightTopPoint);
        squareMap.put("leftBottomPoint", leftBottomPoint);
        squareMap.put("rightBottomPoint", rightBottomPoint);
        return squareMap;
    }


}
