package com.ltgk.port.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.ltgk.common.constant.CacheConstants;
import com.ltgk.common.constant.Constants;
import com.ltgk.common.core.domain.AjaxResult;
import com.ltgk.common.core.redis.RedisCache;
import com.ltgk.common.enums.DsMainAreaMarkTypeEnums;
import com.ltgk.common.enums.EnterOutPortType;
import com.ltgk.common.enums.WarnAreaInfoAreaTypeEnums;
import com.ltgk.common.utils.DateUtils;
import com.ltgk.common.utils.GeoUtils;
import com.ltgk.port.domain.dto.GetInPortListReq;
import com.ltgk.port.domain.dto.GetOutEnterPortListReq;
import com.ltgk.port.domain.dto.GetOutEnterPortSortReq;
import com.ltgk.port.domain.dto.GetOutPortListReq;
import com.ltgk.port.domain.entity.DsMainArea;
import com.ltgk.port.domain.entity.DsPort;
import com.ltgk.port.domain.entity.WarnAreaInfo;
import com.ltgk.port.domain.vo.*;
import com.ltgk.port.mapper.DsPortMapper;
import com.ltgk.port.mapper.WarnAreaInfoMapper;
import com.ltgk.port.service.IDsMainAreaService;
import com.ltgk.port.service.IDsPortService;
import com.ltgk.port.service.PortStatisticsService;
import com.ltgk.port.service.WarnAreaInfoService;
import com.ltgk.system.service.DynamicDataService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.awt.geom.Point2D;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.github.pagehelper.page.PageMethod.startPage;

/**
 * @Author: wan kun
 * @Description: 大屏一张图  渔港统计
 * @Date: 2025/1/16 15:10
 * @Version: 1.0
 */
@Slf4j
@Service
public class PortStatisticsServiceImpl implements PortStatisticsService {
    @Autowired
    private IDsPortService dsPortService;
    @Autowired
    private DsPortMapper dsPortMapper;
    @Autowired
    private IDsMainAreaService dsMainAreaService;
    @Autowired
    private DynamicDataService dynamicDataService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private WarnAreaInfoService warnAreaInfoService;
    @Resource
    private PortStatisticsService portStatisticsService;
    @Autowired
    private WarnAreaInfoMapper warnAreaInfoMapper;

    /**
     * 大图统计
     *
     * @return
     */
    @Override
    public AjaxResult getPortStatistics() {
        PortStatisticsVo portStatisticsVo = new PortStatisticsVo();
        // 查询渔港统计数据
        LambdaQueryWrapper<DsPort> portLqw = new LambdaQueryWrapper<>();
        portLqw.eq(DsPort::getDelFlag, Constants.FLAG_FALSE);
        List<DsPort> list = dsPortService.list(portLqw);
        list.forEach(dsPort -> {
            try {
                List<BoatNavigateStatusVo> currentTimeInPortBoatCount = getCurrentTimeInPortBoatCount(dsPort);
                if (CollectionUtils.isNotEmpty(currentTimeInPortBoatCount)) {
//                    currentTimeInPortBoatCount.sort(Comparator.comparing(BoatNavigateStatusVo::getGpsTime).reversed());
                    dsPort.setBoatNumInPort((long) currentTimeInPortBoatCount.size());
                } else {
                    dsPort.setBoatNumInPort(0L);
                }
            } catch (JsonProcessingException e) {
                log.error("获取当前时间在港内渔船数量失败", e);
            }
        });

        portStatisticsVo.setPortList(list);
        portStatisticsVo.setPortCount(Long.valueOf(list.size()));
        // 查询渔船数量统计
        portStatisticsVo.setBoatCount(dsPortMapper.getBoatCount(null));
        // 查询泊位数量统计
        LambdaQueryWrapper<DsMainArea> berthLqw = new LambdaQueryWrapper<>();
        // 停泊区域
        berthLqw.eq(DsMainArea::getMarkType, DsMainAreaMarkTypeEnums.PORT.getCode());
        portStatisticsVo.setBerthCount(dsMainAreaService.count(berthLqw));
        // 查询24小时内进港数量
        portStatisticsVo.setEnterPortCount(dsPortMapper.getEnterOrOutPortCount(EnterOutPortType.ENTER_PORT.getCode(), DateUtils.getAgoTime(24, TimeUnit.HOURS), DateUtils.getNowDate(), null));
        // 查询24小时内出港数量
        portStatisticsVo.setOutPortCount(dsPortMapper.getEnterOrOutPortCount(EnterOutPortType.OUT_PORT.getCode(), DateUtils.getAgoTime(24, TimeUnit.HOURS), DateUtils.getNowDate(), null));
        // 在港渔船数量
        portStatisticsVo.setInPortCount(portStatisticsVo.getPortList().stream().mapToLong(DsPort::getBoatNumInPort).sum());

        // 渔船出港作业数量
        portStatisticsVo.setOutPortWorkCount((long) portStatisticsService.getOutPortList(new GetOutPortListReq()).size());

        return AjaxResult.success(portStatisticsVo);
    }

    /**
     * 进出港排名
     *
     * @param getOutEnterPortSortReq
     * @return
     */
    @Override
    public List<EnterOutVo> getOutEnterPortSort(GetOutEnterPortSortReq getOutEnterPortSortReq) {
        List<EnterOutVo> returnList = new ArrayList<>();
        List<EnterOutVo> today = dsPortMapper.getEnterOutPortGroupBYPortId(getOutEnterPortSortReq);
        // 将list转为map
        Map<String, EnterOutVo> todayMap = new HashMap<>();
        for (int i = 0; i < today.size(); i++) {
            EnterOutVo enterOutVo = today.get(i);
            enterOutVo.setChange(i);
            todayMap.put(enterOutVo.getPortId(), enterOutVo);
        }
        // 获取两个时间的时间差
        Long diff = DateUtils.parseDate(getOutEnterPortSortReq.getEndTime()).getTime() - DateUtils.parseDate(getOutEnterPortSortReq.getStartTime()).getTime();
        Date yesterdayStartDate = new Date(DateUtils.parseDate(getOutEnterPortSortReq.getStartTime()).getTime() - diff);
        GetOutEnterPortSortReq yesterdayReq = new GetOutEnterPortSortReq();
        yesterdayReq.setStartTime(DateUtils.dateTimeDDHHMMSS(yesterdayStartDate));
        yesterdayReq.setEndTime(getOutEnterPortSortReq.getStartTime());
        List<EnterOutVo> yesterday = dsPortMapper.getEnterOutPortGroupBYPortId(yesterdayReq);
        Map<String, EnterOutVo> yesterdayMap = new HashMap<>();
        for (int i = 0; i < yesterday.size(); i++) {
            EnterOutVo enterOutVo = yesterday.get(i);
            enterOutVo.setChange(i);
            yesterdayMap.put(enterOutVo.getPortId(), enterOutVo);
        }
        todayMap.forEach((k, v) -> {
            if (yesterdayMap.containsKey(k)) {
                EnterOutVo enterOutVo = yesterdayMap.get(k);
                enterOutVo.setChange(enterOutVo.getChange() - v.getChange());
                returnList.add(enterOutVo);
            } else {
                v.setChange(0);
                returnList.add(v);
            }
        });
        returnList.sort(Comparator.comparing(EnterOutVo::getAllCount).reversed());
        return returnList;
    }

    @Override
    public List<BoatEnterOutVo> getOutEnterPortList(GetOutEnterPortListReq getOutEnterPortListReq) {
        startPage(getOutEnterPortListReq.getPageNum(), getOutEnterPortListReq.getPageSize());
        if (getOutEnterPortListReq.getType().equals(0)) {
            return dsPortMapper.getEnterOrOutPortList(getOutEnterPortListReq, EnterOutPortType.ENTER_PORT.getCode(), DateUtils.getAgoTime(24, TimeUnit.HOURS), DateUtils.getNowDate());
        } else {
            return dsPortMapper.getEnterOrOutPortList(getOutEnterPortListReq, EnterOutPortType.OUT_PORT.getCode(), DateUtils.getAgoTime(24, TimeUnit.HOURS), DateUtils.getNowDate());
        }
    }

    @Override
    public List<BoatNavigateStatusVo> getInPortList(GetInPortListReq getInPortListReq) {
        LambdaQueryWrapper<DsPort> portLqw = new LambdaQueryWrapper<>();
        portLqw.eq(DsPort::getDelFlag, Constants.FLAG_FALSE);
        portLqw.eq(StringUtils.isNotBlank(getInPortListReq.getPortId()), DsPort::getId, getInPortListReq.getPortId());
        List<DsPort> list = dsPortService.list(portLqw);
        List<BoatNavigateStatusVo> sortList = new ArrayList<>();
        List<BoatNavigateStatusVo> returnList = new ArrayList<>();
        list.forEach(dsPort -> {
            try {
                List<BoatNavigateStatusVo> boatList = getCurrentTimeInPortBoatCount(dsPort);
                if (ObjectUtils.isNotEmpty(boatList))
                    sortList.addAll(boatList);
            } catch (JsonProcessingException e) {
                log.error("获取当前时间在港内渔船数量失败", e);
            }
        });
        sortList.sort(Comparator.comparing(BoatNavigateStatusVo::getGpsTime).reversed());
        // 筛选
        if (ObjectUtils.isNotEmpty(sortList)) {
            sortList.forEach(item -> {
                // 筛选条件
                if (StringUtils.isNotBlank(getInPortListReq.getBoatName()) && StringUtils.isNotBlank(getInPortListReq.getDeviceCode())) {
                    if (StringUtils.isNotBlank(item.getBoatName()) && item.getBoatName().contains(getInPortListReq.getBoatName()) && StringUtils.isNotBlank(item.getTerminalCode()) && item.getTerminalCode().contains(getInPortListReq.getDeviceCode()))
                        returnList.add(item);
                } else if (StringUtils.isNotBlank(getInPortListReq.getBoatName())) {
                    if (StringUtils.isNotBlank(item.getBoatName()) && item.getBoatName().contains(getInPortListReq.getBoatName()))
                        returnList.add(item);
                } else if (StringUtils.isNotBlank(getInPortListReq.getDeviceCode())) {
                    if (StringUtils.isNotBlank(item.getTerminalCode()) && item.getTerminalCode().contains(getInPortListReq.getDeviceCode()))
                        returnList.add(item);
                } else {
                    returnList.add(item);
                }
            });
        }
        return returnList;
    }

    @Override
    public List<BoatNavigateStatusVo> getOutPortList(GetOutPortListReq getOutPortListReq) {
        List<BoatNavigateStatusVo> list = new ArrayList<>();
        // 获取3海里渔区信息
        WarnAreaInfo warnAreaInfo = warnAreaInfoMapper.getWarnAreaInfo(WarnAreaInfoAreaTypeEnums.THREE_NAUTICAL_MILE_AREA.getCode());
        if (ObjectUtils.isEmpty(warnAreaInfo) || ObjectUtils.isEmpty(warnAreaInfo.getPoints())) return list;
        // 非圆形【四边形、多边形】 数据组装经纬度
        String[] split = warnAreaInfo.getPoints().split(";");
        if (split.length < 4) {
            return list;
        }
        List<Point2D.Double> points = new ArrayList<>();
        for (int i = 0; i < split.length; i++) {
            String[] split1 = split[i].split(",");
            if (split1.length != 2) {
                return list;
            }
            points.add(new Point2D.Double(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])));
        }
        Set<String> dynamicList = redisCache.getGeoList(CacheConstants.TERMINAL_KEY);

        HashMap<String, String> exitBoatMap = new HashMap<>();
        dynamicList.forEach(item -> {
            // 获取缓存的名字用来获取 缓存的信息
            String cacheName = item;
            if (ObjectUtils.isNotEmpty(cacheName)) {
                Object cacheObject = redisCache.getCacheObject(CacheConstants.TERMINAL_KEY + "-" + cacheName);
                if (ObjectUtils.isNotEmpty(cacheObject)) {
                    BoatDynamicDataVo boatDynamicData = JSON.parseObject(cacheObject.toString(), BoatDynamicDataVo.class);
                    // 根据信息获取渔船数据
                    if (ObjectUtils.isNotEmpty(boatDynamicData) && StringUtils.isNotBlank(boatDynamicData.getMmsi()) && !boatDynamicData.getMmsi().equals("0") && !exitBoatMap.containsKey(boatDynamicData.getMmsi())) {
                        // 筛选条件
                        if (StringUtils.isNotBlank(getOutPortListReq.getBoatName()) && StringUtils.isNotBlank(getOutPortListReq.getDeviceCode())) {
                            if (StringUtils.isNotBlank(boatDynamicData.getBoatName()) && boatDynamicData.getBoatName().contains(getOutPortListReq.getBoatName()) && StringUtils.isNotBlank(boatDynamicData.getMmsi()) && boatDynamicData.getMmsi().contains(getOutPortListReq.getDeviceCode()))
                                if (ObjectUtils.isNotEmpty(this.getOutPortList(boatDynamicData, points))) {
                                    list.add(this.getOutPortList(boatDynamicData, points));
                                    exitBoatMap.put(boatDynamicData.getMmsi(), boatDynamicData.getMmsi());
                                }

                        } else if (StringUtils.isNotBlank(getOutPortListReq.getBoatName())) {
                            if (StringUtils.isNotBlank(boatDynamicData.getBoatName()) && boatDynamicData.getBoatName().contains(getOutPortListReq.getBoatName()))
                                if (ObjectUtils.isNotEmpty(this.getOutPortList(boatDynamicData, points))) {
                                    list.add(this.getOutPortList(boatDynamicData, points));
                                    exitBoatMap.put(boatDynamicData.getMmsi(), boatDynamicData.getMmsi());
                                }
                        } else if (StringUtils.isNotBlank(getOutPortListReq.getDeviceCode())) {
                            if (StringUtils.isNotBlank(boatDynamicData.getMmsi()) && boatDynamicData.getMmsi().contains(getOutPortListReq.getDeviceCode()))
                                if (ObjectUtils.isNotEmpty(this.getOutPortList(boatDynamicData, points))) {
                                    list.add(this.getOutPortList(boatDynamicData, points));
                                    exitBoatMap.put(boatDynamicData.getMmsi(), boatDynamicData.getMmsi());
                                }
                        } else {
                            if (ObjectUtils.isNotEmpty(this.getOutPortList(boatDynamicData, points))) {
                                list.add(this.getOutPortList(boatDynamicData, points));
                                exitBoatMap.put(boatDynamicData.getMmsi(), boatDynamicData.getMmsi());
                            }
                        }

                    }
                }
            }
        });
        list.sort(Comparator.comparing(BoatNavigateStatusVo::getGpsTime).reversed());
        return list;
    }

    public BoatNavigateStatusVo getOutPortList(BoatDynamicDataVo boatDynamicData, List<Point2D.Double> points) {
        // 判断不在5海里内 即为出海
        Point2D.Double pointDouble = new Point2D.Double(boatDynamicData.getLongitude(), boatDynamicData.getLatitude());
        if (!GeoUtils.isInPolygon(pointDouble, points)) {
            BoatNavigateStatusVo boatNavigateStatus = new BoatNavigateStatusVo();
            boatNavigateStatus.setBoatId(boatDynamicData.getBoatId());
            boatNavigateStatus.setBoatName(boatDynamicData.getBoatName());
            boatNavigateStatus.setDeviceType(boatDynamicData.getDeviceType());
            boatNavigateStatus.setTerminalCode(StringUtils.isNotBlank(boatDynamicData.getMmsi()) ? boatDynamicData.getMmsi() : boatDynamicData.getTargetSourceId());
            boatNavigateStatus.setLongitude(boatDynamicData.getLongitude());
            boatNavigateStatus.setLatitude(boatDynamicData.getLatitude());
            boatNavigateStatus.setSog(boatDynamicData.getSpeed());
            boatNavigateStatus.setCog(boatDynamicData.getCourse());
            boatNavigateStatus.setHeading(boatDynamicData.getCourse());
            boatNavigateStatus.setGpsTime(boatDynamicData.getLocationTime());
            boatNavigateStatus.setBoatLength(boatDynamicData.getBoatLength());
            boatNavigateStatus.setMoldedBreadth(boatDynamicData.getBoatWidth());
            return boatNavigateStatus;
        } else {
            return null;
        }
    }

    /**
     * 获取当前时间在港渔船数量
     *
     * @param dsPort：渔港参数
     * @return Long
     * @author Qi ChengBin
     * @date 2025/3/4
     */
    public List<BoatNavigateStatusVo> getCurrentTimeInPortBoatCount(DsPort dsPort) throws JsonProcessingException {
        int regionType = 0;
        String region = "[{\"x\":108.212615,\"y\":21.51282},{\"x\":109.1228567,\"y\":21.51282},{\"x\":109.1228567,\"y\":19.076025},{\"x\":108.212615,\"y\":19.076025}]";
        if (dsPort.getAreaType().equals("Circle")) {
            regionType = 1;
            // 圆形数据组装经纬度
            String[] split = dsPort.getPositionInfo().split(",");
            if (split.length != 3) {
                return null;
            }
            region = "[{\"x\":" + split[0] + ",\"y\":" + split[1] + "}," + split[2] + "]";
        } else {
            // 非圆形【四边形、多边形】 数据组装经纬度
            String[] split = dsPort.getPositionInfo().split(";");
            if (split.length < 4) {
                return null;
            }
            List<Point> points = new ArrayList<>();
            for (int i = 0; i < split.length; i++) {
                String[] split1 = split[i].split(",");
                if (split1.length != 2) {
                    return null;
                }
                points.add(new Point(Double.parseDouble(split1[0]), Double.parseDouble(split1[1])));
            }
            region = JSONObject.toJSONString(points);
        }
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> dynamicList = dynamicDataService.getDynamicCountByRegion(region, regionType);
        List<BoatNavigateStatusVo> list = new ArrayList<>();
        HashMap<String, String> exitBoatMap = new HashMap<>();
        dynamicList.forEach(item -> {
            // 获取缓存的名字用来获取 缓存的信息
            String cacheName = item.getContent().getName();
            if (ObjectUtils.isNotEmpty(cacheName)) {
                Object cacheObject = redisCache.getCacheObject(CacheConstants.TERMINAL_KEY + "-" + cacheName);
                if (ObjectUtils.isNotEmpty(cacheObject)) {
                    BoatDynamicDataVo boatDynamicData = JSON.parseObject(cacheObject.toString(), BoatDynamicDataVo.class);
                    // 根据信息获取渔船数据
                    if (ObjectUtils.isNotEmpty(boatDynamicData) && StringUtils.isNotBlank(boatDynamicData.getMmsi()) && !boatDynamicData.getMmsi().equals("0") && !exitBoatMap.containsKey(boatDynamicData.getMmsi())) {
                        BoatNavigateStatusVo boatNavigateStatus = new BoatNavigateStatusVo();
                        boatNavigateStatus.setBoatId(boatDynamicData.getBoatId());
                        boatNavigateStatus.setBoatName(boatDynamicData.getBoatName());
                        boatNavigateStatus.setDeviceType(boatDynamicData.getDeviceType());
                        boatNavigateStatus.setTerminalCode(StringUtils.isNotBlank(boatDynamicData.getMmsi()) ? boatDynamicData.getMmsi() : boatDynamicData.getTargetSourceId());
                        boatNavigateStatus.setLongitude(boatDynamicData.getLongitude());
                        boatNavigateStatus.setLatitude(boatDynamicData.getLatitude());
                        boatNavigateStatus.setSog(boatDynamicData.getSpeed());
                        boatNavigateStatus.setCog(boatDynamicData.getCourse());
                        boatNavigateStatus.setHeading(boatDynamicData.getCourse());
                        boatNavigateStatus.setGpsTime(boatDynamicData.getLocationTime());
                        boatNavigateStatus.setBoatLength(boatDynamicData.getBoatLength());
                        boatNavigateStatus.setMoldedBreadth(boatDynamicData.getBoatWidth());
                        boatNavigateStatus.setName(boatDynamicData.getName());
                        list.add(boatNavigateStatus);
                        exitBoatMap.put(boatDynamicData.getMmsi(), boatDynamicData.getMmsi());
                    }
                }
            }
        });
        return list;
    }
}
