package com.aidex.common.app.server.impl;

import com.aidex.common.app.domain.vo.LocationVO;
import com.aidex.common.app.domain.vo.SysWharfVO;
import com.aidex.common.app.server.IAppService;
import com.aidex.common.exception.SysException;
import com.aidex.common.gps.domain.AlarmDatetailsEntity;
import com.aidex.common.gps.domain.FenceEntity;
import com.aidex.common.gps.domain.LocationEntity;
import com.aidex.common.gps.domain.MyGpsEntity;
import com.aidex.common.gps.server.IGpsService;
import com.aidex.common.utils.StringUtils;
import com.aidex.common.utils.dist.CalcDist;
import com.aidex.framework.cache.ConfigUtils;
import com.aidex.system.domain.SysNotice;
import com.aidex.system.domain.SysShip;
import com.aidex.system.domain.SysWharf;
import com.aidex.system.service.SysNoticeService;
import com.aidex.system.service.SysShipService;
import com.aidex.system.service.SysWharfService;
import org.apache.ibatis.javassist.expr.NewArray;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class AppService implements IAppService {

    @Autowired
    private SysNoticeService sysNoticeService;
    @Autowired
    private SysWharfService sysWharfService;
    @Autowired
    private IGpsService iGpsService;

    @Autowired
    private SysShipService sysShipService;


    public List<SysNotice> getCarouselList(){

        List<SysNotice> carouselList = sysNoticeService.findList(new SysNotice(){{setCarousel("1");}});
        return carouselList;
    }

    public List<SysNotice> getNoticeList(){
        List<SysNotice> noticeList = sysNoticeService.findList(new SysNotice(){{setCarousel("0");setNoticeType("1");}});
        return noticeList;
    }

    public SysNotice findCarouselAndNoticeDetails(String id){
        return sysNoticeService.get(id);
    }

    public List<SysWharf> findSysWharfList(){
        return sysWharfService.findList(new SysWharf());
    }

    /*
    * direction 方向 true正向 false反向
    * */
    public List<LocationEntity> findAllLocation(Boolean direction){
        // 全部船只信息
        List<SysShip> allMyGps = sysShipService.findList(new SysShip(){{setStatus("1");}});
        // 全部在线设备
        String macIds = allMyGps.stream().map(SysShip::getShipNum).collect(Collectors.joining(","));
        List<LocationEntity> locationEntities = iGpsService.getLocationBatchByMac(macIds);
        if(locationEntities.size() <= 0)
            throw new SysException(8821,"暂无运行船只");

        // 返回结果
//        List<LocationVO> locationList = new ArrayList<>();

        // 停靠速度
//        Integer stopSpeed = Integer.valueOf(ConfigUtils.getConfigByKey("stop.speed").getConfigValue());

        // 正反向计算数据
        List<LocationEntity> calcList = new ArrayList<>();

        // 正反向计算条件
        String[] conditions ;

        /* 正向运行 */
        if(direction){
            // 获取正向条件
            conditions = ConfigUtils.getConfigByKey("forward.direction").getConfigValue().split("-");
            calcList = locationEntities.stream().filter(local -> ((Double.valueOf(local.getDir()) >= Double.valueOf(conditions[0])) && (Double.valueOf(local.getDir()) <= Double.valueOf(conditions[1])))).collect(Collectors.toList());
        }else {
            // 获取反向条件
            conditions = ConfigUtils.getConfigByKey("reverse.direction").getConfigValue().split("-");
            calcList = locationEntities.stream().filter(local -> ((Double.valueOf(local.getDir()) >= Double.valueOf(conditions[0])) && (Double.valueOf(local.getDir()) <= Double.valueOf(conditions[1])))).collect(Collectors.toList());
        }
//        for (LocationEntity locationEntity : calcList ) {
//            LocationVO locationVO = new LocationVO();
//            BeanUtils.copyProperties(locationEntity,locationVO);
//            locationVO.setIsArrival(Boolean.FALSE);
//            // 查询全部停止船只判断是否到站
//            if(Integer.valueOf(locationVO.getSpeed()) <= stopSpeed){
//                locationVO.setIsArrival(Boolean.TRUE);
//            }
//            locationList.add(locationVO);
//        }
        List<LocationEntity> noDir = locationEntities.stream().filter(local -> Double.valueOf(local.getDir()) <= 0).collect(Collectors.toList());
        calcList.addAll(noDir);
        return  calcList;
    }


    public LocationVO findAllLocationByNext(Boolean direction,String lat, String lon){
        if(StringUtils.isEmpty(lat) || StringUtils.isEmpty(lon))
            throw new SysException(4441,"请告诉我你在哪");

        // 离我最近的站点
        SysWharf wharf = this.findNearestStation(lat,lon);

        if(!wharf.getStatus().equals("0"))
            throw new SysException(4442, wharf.getWharfNanme()+" 已经停用！请更换其他站点");

        List<SysShip> allMyGps = sysShipService.findList(new SysShip(){{setStatus("1");}});
        // 全部在线设备
        String macIds = allMyGps.stream().map(SysShip::getShipNum).collect(Collectors.joining(","));
        List<LocationEntity> locationEntities = iGpsService.getLocationBatchByMac(macIds);


        if(locationEntities.size() <= 0)
            throw new SysException(8821,"暂无运行船只");

        // 默认到站停留时间
        Integer inStopTime = Integer.valueOf(ConfigUtils.getConfigByKey("pull.in.time").getConfigValue());

        // 停靠速度
        Integer stopSpeed = Integer.valueOf(ConfigUtils.getConfigByKey("stop.speed").getConfigValue());

        for (LocationEntity locationEntity : locationEntities) {
            locationEntity.setIsLongStop(Boolean.FALSE);
            // 速度等于等 并且方位为零判断为已经停止
            if(Double.valueOf(locationEntity.getSpeed()) <= Double.valueOf(stopSpeed) && Double.valueOf(locationEntity.getDir()) <= 0){
                // 获取当天的 LocalDate 对象
                LocalDateTime endOfDay = LocalDateTime.now();
                // 获取当天的结束时间
                LocalDateTime startDay = endOfDay.minusMonths(1);
                // 转换为时间戳
                long startTimestamp = startDay.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                long endTimestamp = endOfDay.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
                List<AlarmDatetailsEntity> alarms = iGpsService.findAlarmDetails(locationEntity.getMacid(),"4",startTimestamp,endTimestamp);
                if(alarms.size() > 0){
                    // 取最后一次停靠的方位
                    AlarmDatetailsEntity alarmDetails = alarms.get(0);
                    locationEntity.setDir(alarmDetails.getDir());
                    // 将时间戳转换为LocalDateTime
                    LocalDateTime longStopTime = LocalDateTime.ofEpochSecond(Long.valueOf(alarmDetails.getAlarmime()) / 1000, 0, java.time.ZoneOffset.UTC);
                    // 计算两个日期时间之间的分钟数
                    Long stopTime = ChronoUnit.MINUTES.between(longStopTime, endOfDay);

                    if(stopTime.doubleValue() > Double.valueOf(inStopTime)) {
                        locationEntity.setIsLongStop(Boolean.TRUE);
                    }
                }
            }
        }

        // 正反向计算数据
        List<LocationVO> calcList = new ArrayList<>();


        // 正反向计算条件
        String[] conditions ;

        // 默认航行平均速度
        Long defaultSpeed = 0L;
        /* 正向运行 */
        if(direction){
            // 获取正向条件
            conditions = ConfigUtils.getConfigByKey("forward.direction").getConfigValue().split("-");
            defaultSpeed = Long.valueOf(ConfigUtils.getConfigByKey("forward.default.speed").getConfigValue());
            calcList = locationEntities.stream().filter(local -> ((Double.valueOf(local.getDir()) >= Double.valueOf(conditions[0])) && (Double.valueOf(local.getDir()) <= Double.valueOf(conditions[1])))).map(lot -> {
                LocationVO locationVO = new LocationVO();
                BeanUtils.copyProperties(lot,locationVO);
                locationVO.setDistance(CalcDist.calculateDistance(Double.valueOf(lat),Double.valueOf(lon),
                        Double.valueOf(lot.getLat()),Double.valueOf(lot.getLon())));
                return locationVO;
            }).sorted(Comparator.comparing(LocationVO::getDistance))
                    .collect(Collectors.toList());
        }else {
            // 获取反向条件
            conditions = ConfigUtils.getConfigByKey("reverse.direction").getConfigValue().split("-");
            defaultSpeed = Long.valueOf(ConfigUtils.getConfigByKey("reverse.default.speed").getConfigValue());
            calcList = locationEntities.stream().filter(local -> ((Double.valueOf(local.getDir()) >= Double.valueOf(conditions[0])) && (Double.valueOf(local.getDir()) <= Double.valueOf(conditions[1])))).map(lot -> {
                        LocationVO locationVO = new LocationVO();
                        BeanUtils.copyProperties(lot,locationVO);
                        locationVO.setDistance(CalcDist.calculateDistance(Double.valueOf(lat),Double.valueOf(lon),
                                Double.valueOf(lot.getLat()),Double.valueOf(lot.getLon())));
                        return locationVO;
                    }).sorted(Comparator.comparing(LocationVO::getDistance))
                    .collect(Collectors.toList());
        }
        LocationVO res = null;
        // 有最近的船只则进计算
        if(calcList.size() > 0) {

            // 验证船只是否经过该站点
            for (LocationVO locationVO : calcList) {
                // 验证行驶方向--获取未到达次站点船只--避免已经过站点船只近距离出现
                if(direction){
                   Double position = CalcDist.gps2d(Double.valueOf(wharf.getLat()),Double.valueOf(wharf.getLng()),Double.valueOf(locationVO.getLat()),Double.valueOf(locationVO.getLon()));
                   if(position <= 0){
                       res  = locationVO;
                       break;
                   }
                }else {
                    Double position = CalcDist.gps2d(Double.valueOf(locationVO.getLat()),Double.valueOf(locationVO.getLon()),Double.valueOf(wharf.getLat()),Double.valueOf(wharf.getLng()));
                    if(position <= 0){
                        res  = locationVO;
                        break;
                    }
                }
            }
            if(res == null)
                return null;
            // 停靠时间
            Long awaitTime = 0L;


            // 离船最近的站点
            SysWharf wharfShip = this.findNearestStation(res.getLat(),res.getLon());
            // 验证船是否停止航行
            Boolean isStopOperation = Double.valueOf(res.getSpeed()) <= Double.valueOf(stopSpeed);
            // 为避免GPS服务与本地服务器时间不同步使用GPS服务器期间验证是否进入围栏
            Long endTime = Long.valueOf(res.getServer_time());
            // 减去默认停靠时间在停靠时间内查询进入记录
            Long startTime = endTime - (inStopTime.longValue() * 60 * 1000);

            // 围栏记录数据
            List<AlarmDatetailsEntity> fenceEntities = iGpsService.findAlarmDetails(res.getMacid(),"4",startTime,endTime);

            // 查询是否进入离我最近的站点
            AlarmDatetailsEntity mySite = fenceEntities.stream().filter(alram -> alram.getDescribe().equals(wharf.getWharfNanme())).findFirst().orElse(null);

            AlarmDatetailsEntity shipSite = fenceEntities.stream().filter(alram -> alram.getDescribe().equals(wharfShip.getWharfNanme())).findFirst().orElse(null);

            res.setMyWharf(wharf);


            // 距离几站计算
            Long distSiteNum = 0L;
            if(direction){
                Double position = CalcDist.gps2d(Double.valueOf(wharfShip.getLat()),Double.valueOf(wharfShip.getLng()),Double.valueOf(res.getLat()),Double.valueOf(res.getLon()));
                if(position > 0){
                   distSiteNum = (wharfShip.getWharfOrder() / 10)  - (wharf.getWharfOrder() / 10) ;
                }else {
                   distSiteNum = ((wharfShip.getWharfOrder() / 10) - 1) - (wharf.getWharfOrder() / 10)  ;
                }
            }else {
                Double position = CalcDist.gps2d(Double.valueOf(res.getLat()),Double.valueOf(res.getLon()),Double.valueOf(wharfShip.getLat()),Double.valueOf(wharfShip.getLng()));
                if(position > 0){
                    distSiteNum = (wharf.getWharfOrder() / 10) - (wharfShip.getWharfOrder() / 10) ;
                }else {
                    distSiteNum = (wharf.getWharfOrder() / 10) - ((wharfShip.getWharfOrder() / 10) - 1);
                }
            }

            res.setDistSiteNum(distSiteNum);

            if(res.getIsLongStop())
                res.setStopWharf(wharfShip);
            else {
                if(shipSite == null && mySite != null){
                    res.setStopWharf(wharf);
                }else {
                    res.setStopWharf(wharfShip);
                }
            }

            // 船只已经停靠入站离我最近的站
            if (isStopOperation && (mySite != null || shipSite != null)) {

                res.setIsArrival(Boolean.TRUE);
                // 如果离我最近与停靠站点不是同一站点则计算时间
                if(!wharfShip.getWharfNanme().equals(wharf.getWharfNanme())) {
                    //如果处于停止状态则计算停留剩余时间
                    Double loadingTime = inStopTime.doubleValue() - CalcDist.calcStopTime(res.getUpdtime());
                    // 计算站点间距离
                    Double distince = CalcDist.calculateDistance(Double.valueOf(res.getLat()), Double.valueOf(res.getLon()),
                            Double.valueOf(wharf.getLat()), Double.valueOf(wharf.getLng()));
                    // 计算时间
                    Double time = Math.ceil(((distince / 100) / Double.valueOf(defaultSpeed)) * 60);
                    awaitTime = loadingTime.longValue() + time.longValue();
                }
            }else {
                // 计算站点间距离
                Double distince = CalcDist.calculateDistance(Double.valueOf(res.getLat()),Double.valueOf(res.getLon()),
                        Double.valueOf(wharf.getLat()),Double.valueOf(wharf.getLng()));
                // 船只出站后停止运行
                if(isStopOperation){
                    Double time = Math.ceil(((distince / 100) / Double.valueOf(defaultSpeed)) * 60);
                    awaitTime = time.longValue();
                }else {
                    Double time = Math.ceil(((distince / 100) / Double.valueOf(res.getSpeed())) * 60);
                    awaitTime = time.longValue();
                }
            }

            res.setAwaitTime(awaitTime);
        }

        return res;
    }

    public SysWharfVO findNearestStation(String lat, String lon){
        if(StringUtils.isEmpty(lat) || StringUtils.isEmpty(lon))
            throw new SysException(4441,"请告诉我你在哪");
        List<SysWharf> listWharf = sysWharfService.findList(new SysWharf());
        List<SysWharfVO> vos = new ArrayList<>();
        for (SysWharf sysWharf : listWharf) {
            SysWharfVO wharfVO = new SysWharfVO();
            BeanUtils.copyProperties(sysWharf,wharfVO);
            wharfVO.setDistance(CalcDist.calculateDistance(Double.valueOf(lat),Double.valueOf(lon),
                    Double.valueOf(sysWharf.getLat()),Double.valueOf(sysWharf.getLng())));
            vos.add(wharfVO);
        }
        return  vos.stream().sorted(Comparator.comparing(SysWharfVO::getDistance)).findFirst().orElse(null);
    }

}
