package bus.service.impl;

import bus.model.SnowflakeUtil;
import bus.model.dto.*;
import bus.model.dto.page.BCourseInfoPageDto;
import bus.model.po.*;
import bus.model.vo.BCourseInfoVo;
import bus.mapper.BCourseInfoMapper;

import bus.service.*;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.orcas.common.sso.model.ExtInfo;
import com.orcas.iso.config.common.user.CurrentUserHolder;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Program: bus
 * @Description: 描述
 * @Author: zy
 * @Date: 2025-03-02 19:53:49
 **/
@Service

public class BCourseInfoServiceImpl extends ServiceImpl<BCourseInfoMapper, BCourseInfoPo> implements BCourseInfoService {

    @Autowired
    private BCourseInfoMapper bCourseInfoMapper;
    @Resource
    private SnowflakeUtil snowflakeUtil;
    @Resource
    private BCourseTimeService bCourseTimeService;
    @Resource
    private BCourseStationService bCourseStationService;
    @Resource
    private BStationInfoService bStationInfoService;
    @Resource
    private BCourseBusService bCourseBusService;
    @Resource
    private BBusInfoService bBusInfoService;

	/**
     * 详情
     * @param id
     * @return
     */
    @Override
    public BCourseInfoDto getDetailById(String id){
        BCourseInfoPo po = this.bCourseInfoMapper.selectById(id);
        BCourseInfoDto bCourseInfoDto = BeanUtil.toBean(po, BCourseInfoDto.class);
        String mapPoint = po.getMapPoint();
        if(StrUtil.isNotBlank(mapPoint)) {
            List<BCoursePointDto> fileJsons = JSONUtil.toList(mapPoint, BCoursePointDto.class);
            bCourseInfoDto.setMapPointList(fileJsons);
        }
        QueryWrapper<BCourseTimePo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("course_id", id);
        queryWrapper.orderByAsc("sort");
        List<BCourseTimePo> list = bCourseTimeService.list(queryWrapper);
        bCourseInfoDto.setBCourseTimeList(BeanUtil.copyToList(list, BCourseTimeDto.class));


        QueryWrapper<BCourseStationPo> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("course_id", id);
        queryWrapper1.orderByAsc("sort");
        List<BCourseStationPo> list1 = bCourseStationService.list(queryWrapper1);
        if(CollectionUtil.isNotEmpty(list1)) {
            List<String> stationIds = list1.stream().map(BCourseStationPo::getStationId).collect(Collectors.toList());
            QueryWrapper<BStationInfoPo> queryWrapper2 = new QueryWrapper<>();
            queryWrapper2.in("id", stationIds);
            List<BStationInfoPo> list2 = bStationInfoService.list(queryWrapper2);
            Map<String,BStationInfoPo> collect = list2.stream().collect(Collectors.toMap(BStationInfoPo::getId, b -> b));
            List<BCourseStationDto> list5 = new ArrayList<>();
            for (BCourseStationPo bCourseStationPo : list1 ) {
                String stationId = bCourseStationPo.getStationId();
                BStationInfoPo bStationInfoPo = collect.get(stationId);
                if(bStationInfoPo != null) {
                    BCourseStationDto bCourseStationDto = new BCourseStationDto();
                    bCourseStationDto.setId(bCourseStationPo.getId());
                    bCourseStationDto.setStationId(bCourseStationPo.getStationId());
                    bCourseStationDto.setSort(bCourseStationPo.getSort());
                    bCourseStationDto.setType(bCourseStationPo.getType());
                    bCourseStationDto.setRemark(bCourseStationPo.getRemark());
                    bCourseStationDto.setName(bStationInfoPo.getName());
                    bCourseStationDto.setStationType(bStationInfoPo.getStationType());
                    bCourseStationDto.setStationStatus(bStationInfoPo.getStationStatus());
                    bCourseStationDto.setDetailAddress(bStationInfoPo.getDetailAddress());
                    bCourseStationDto.setStationCode(bStationInfoPo.getStationCode());
                    bCourseStationDto.setLatitude(bStationInfoPo.getLatitude());
                    bCourseStationDto.setLongitude(bStationInfoPo.getLongitude());
                    list5.add(bCourseStationDto);
                }
            }
            bCourseInfoDto.setBCourseStationList(list5);
        }

        QueryWrapper<BCourseBusPo> queryWrapper3 = new QueryWrapper<>();
        queryWrapper3.eq("course_id", id);
        queryWrapper3.orderByAsc("sort");
        List<BCourseBusPo> list3 = bCourseBusService.list(queryWrapper3);
        if(CollectionUtil.isNotEmpty(list3)) {
            List<String> busIds = list3.stream().map(BCourseBusPo::getBusId).collect(Collectors.toList());
            QueryWrapper<BBusInfoPo> queryWrapper4 = new QueryWrapper<>();
            queryWrapper4.in("id", busIds);
            List<BBusInfoPo> list4 = bBusInfoService.list(queryWrapper4);
            Map<String,BBusInfoPo> collect = list4.stream().collect(Collectors.toMap(BBusInfoPo::getId, b -> b));
            List<BCourseBusDto> list2 = new ArrayList<>();
            for (BCourseBusPo bCourseBusPo : list3 ) {
                String busId = bCourseBusPo.getBusId();
                BBusInfoPo bBusInfoPo = collect.get(busId);
                if(bBusInfoPo != null) {
                    BCourseBusDto bCourseBusDto = new BCourseBusDto();
                    bCourseBusDto.setId(bCourseBusPo.getId());
                    bCourseBusDto.setBusId(bCourseBusPo.getBusId());
                    bCourseBusDto.setSort(bCourseBusPo.getSort());
                    bCourseBusDto.setRemark(bCourseBusPo.getRemark());
                    bCourseBusDto.setBusNo(bBusInfoPo.getBusNo());
                    bCourseBusDto.setDriverName(bBusInfoPo.getDriverName());
                    bCourseBusDto.setDriverPhone(bBusInfoPo.getDriverPhone());
                    list2.add(bCourseBusDto);
                }
            }

            bCourseInfoDto.setBCourseBusList(list2);
        }
        return bCourseInfoDto;
    }

	/**
     * 保存
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
	public void save(BCourseInfoDto dto){
        BCourseInfoPo po = BeanUtil.toBean(dto, BCourseInfoPo.class);
        List<BCoursePointDto> mapPointList = dto.getMapPointList();
        if(CollectionUtil.isNotEmpty(mapPointList)) {
            String mapPoint = JSONUtil.toJsonStr(mapPointList);
            po.setMapPoint(mapPoint);
        }
        ExtInfo extInfo = CurrentUserHolder.get();
        po.setId(snowflakeUtil.snowflakeId());
        po.setCreateTime(new Date());
        po.setUpdateTime(new Date());
        po.setCreatorId(extInfo.getUserId());
        po.setUpdaterId(extInfo.getUserId());
        po.setCreatorName(extInfo.getUserName());
        po.setUpdaterName(extInfo.getUserName());
        //处理时刻
        List<BCourseTimeDto> bCourseTimeList = dto.getBCourseTimeList();
        po.setFirstBusSpace(bCourseTimeList.get(0).getBusSpace());
        List<BCourseTimePo> bCourseTimePoList = handleCourseTime(bCourseTimeList, extInfo, po.getId(), false);
        bCourseTimeService.saveBatch(bCourseTimePoList);
        //处理标志点
        List<BCourseStationDto> bCourseStationList = dto.getBCourseStationList();

        String stationId = bCourseStationList.get(0).getStationId();
        BStationInfoPo byId = bStationInfoService.getById(stationId);
        po.setFirstStationName(byId.getName());
        po.setFirstStationId(stationId);

        String stationId1 = bCourseStationList.get(bCourseStationList.size()-1).getStationId();
        BStationInfoPo byId1 = bStationInfoService.getById(stationId1);
        po.setLastStationName(byId1.getName());
        po.setLastStationId(stationId1);

        List<BCourseStationPo> bCourseStationPos = handleCourseStation(bCourseStationList, extInfo, po.getId(), true);
        bCourseStationService.saveBatch(bCourseStationPos);

        //处理车辆
        List<BCourseBusDto> bCourseBusList = dto.getBCourseBusList();
        List<BCourseBusPo> bCourseBusPos = handleCourseBus(bCourseBusList, extInfo, po.getId(), true);
        bCourseBusService.saveBatch(bCourseBusPos);
        this.bCourseInfoMapper.insert(po);
    }

    /**
    * 列表
    * @param dto
    * @return
    */
    @Override
    public List<BCourseInfoVo> list(BCourseInfoPageDto dto){
        return this.bCourseInfoMapper.list(dto);
    }

	/**
     * 修改
     * @param dto
     * @return
     */
    @Override
    public void update(BCourseInfoDto dto){
        BCourseInfoPo po = BeanUtil.toBean(dto, BCourseInfoPo.class);
        List<BCoursePointDto> mapPointList = dto.getMapPointList();
        if(CollectionUtil.isNotEmpty(mapPointList)) {
            String mapPoint = JSONUtil.toJsonStr(mapPointList);
            po.setMapPoint(mapPoint);
        }
        ExtInfo extInfo = CurrentUserHolder.get();
        po.setUpdateTime(new Date());
        po.setUpdaterId(extInfo.getUserId());
        po.setUpdaterName(extInfo.getUserName());
        //处理时刻
        bCourseTimeService.deleteByCourseId(po.getId());
        List<BCourseTimeDto> bCourseTimeList = dto.getBCourseTimeList();
        po.setFirstBusSpace(bCourseTimeList.get(0).getBusSpace());
        List<BCourseTimePo> bCourseTimePoList = handleCourseTime(bCourseTimeList, extInfo, po.getId(), false);
        bCourseTimeService.saveBatch(bCourseTimePoList);
        //处理标志点
        bCourseStationService.deleteByCourseId(po.getId());
        List<BCourseStationDto> bCourseStationList = dto.getBCourseStationList();
        String stationName= bCourseStationList.get(0).getName();
        po.setFirstStationName(stationName);
        String stationName1 = bCourseStationList.get(bCourseStationList.size()-1).getName();
        po.setLastStationName(stationName1);

        List<BCourseStationPo> bCourseStationPos = handleCourseStation(bCourseStationList, extInfo, po.getId(),false);
        bCourseStationService.saveBatch(bCourseStationPos);
        //处理车辆
        bCourseBusService.deleteByCourseId(po.getId());
        List<BCourseBusDto> bCourseBusList = dto.getBCourseBusList();
        List<BCourseBusPo> bCourseBusPos = handleCourseBus(bCourseBusList, extInfo, po.getId(), false);
        bCourseBusService.saveBatch(bCourseBusPos);
        this.bCourseInfoMapper.updateById(po);
    }


    private List<BCourseTimePo> handleCourseTime(List<BCourseTimeDto> timeList,
                                                 ExtInfo extInfo,
                                                 String courseId,
                                                 Boolean isCreate) {
        List<BCourseTimePo> bCourseTimePoList = new ArrayList<>();
        for (int i = 0; i < timeList.size(); i++) {
            BCourseTimeDto bCourseTimeDto = timeList.get(i);
            BCourseTimePo bCourseTimePo = BeanUtil.toBean(bCourseTimeDto, BCourseTimePo.class);
            bCourseTimePo.setId(snowflakeUtil.snowflakeId());
            bCourseTimePo.setCourseId(courseId);
            if(isCreate){
                bCourseTimePo.setCreateTime(new Date());
                bCourseTimePo.setCreatorId(extInfo.getUserId());
                bCourseTimePo.setCreatorName(extInfo.getUserName());
            }
            bCourseTimePo.setUpdateTime(new Date());
            bCourseTimePo.setUpdaterId(extInfo.getUserId());
            bCourseTimePo.setUpdaterName(extInfo.getUserName());
            if (i == 0) {
                bCourseTimePo.setType("0");
            }else {
                bCourseTimePo.setType("1");
            }
            bCourseTimePoList.add(bCourseTimePo);
        }
        return bCourseTimePoList;
    }
    /**
     * 处理站点信息
     */

    private List<BCourseStationPo> handleCourseStation(List<BCourseStationDto> stationList,
                                                       ExtInfo extInfo,
                                                       String courseId,
                                                       Boolean isCreate) {
        List<BCourseStationPo> poList = new ArrayList<>();
        for (int i = 0; i < stationList.size(); i++) {
            BCourseStationDto bCourseStationDto = stationList.get(i);
            BCourseStationPo bCourseStationPo = BeanUtil.toBean(bCourseStationDto, BCourseStationPo.class);
            bCourseStationPo.setId(snowflakeUtil.snowflakeId());
            bCourseStationPo.setCourseId(courseId);
            if(isCreate){
                bCourseStationPo.setCreateTime(new Date());
                bCourseStationPo.setCreatorId(extInfo.getUserId());
                bCourseStationPo.setCreatorName(extInfo.getUserName());
            }
            bCourseStationPo.setUpdateTime(new Date());
            bCourseStationPo.setUpdaterId(extInfo.getUserId());
            bCourseStationPo.setUpdaterName(extInfo.getUserName());
            if (i == 0) {
                bCourseStationPo.setType("0");
            }else if(i == stationList.size()-1) {
                bCourseStationPo.setType("2");
            }else{
                bCourseStationPo.setType("1");
            }
            poList.add(bCourseStationPo);
        }
        return poList;
    }

    private List<BCourseBusPo> handleCourseBus(List<BCourseBusDto> busList,
                                               ExtInfo extInfo,
                                               String courseId,
                                               Boolean isCreate) {
        List<BCourseBusPo> poList = BeanUtil.copyToList(busList, BCourseBusPo.class);
        poList.forEach(bCourseBusPo -> {
            bCourseBusPo.setCourseId(courseId);
            bCourseBusPo.setId(snowflakeUtil.snowflakeId());
            bCourseBusPo.setCourseId(courseId);
            if(isCreate){
                bCourseBusPo.setCreateTime(new Date());
                bCourseBusPo.setCreatorId(extInfo.getUserId());
                bCourseBusPo.setCreatorName(extInfo.getUserName());
            }
            bCourseBusPo.setUpdateTime(new Date());
            bCourseBusPo.setUpdaterId(extInfo.getUserId());
            bCourseBusPo.setUpdaterName(extInfo.getUserName());
        });

        return poList;

    }



    /**
     * 删除
     * @param id
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(String id){
        QueryWrapper<BCourseTimePo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("course_id", id);
        bCourseTimeService.remove(queryWrapper);
        QueryWrapper<BCourseStationPo> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("course_id", id);
        bCourseStationService.remove(queryWrapper1);
        QueryWrapper<BCourseBusPo> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("course_id", id);
        bCourseBusService.remove(queryWrapper2);
		bCourseInfoMapper.deleteById(id);
    }

    @Override
    public List<BBusTrackInfoDto> getNearbyRoutes(BigDecimal latitude, BigDecimal longitude, Integer radius) {
        // 1. 查询附近站点
        List<BStationInfoDto> nearbyStations = bCourseInfoMapper.findNearbyStations(latitude, longitude, radius);
        if (CollectionUtil.isEmpty(nearbyStations)) {
            return Collections.emptyList();
        }
        // 2. 查询经过这些站点的路线
        List<Long> stationIds = nearbyStations.stream()
                .map(BStationInfoDto::getId)
                .collect(Collectors.toList());

        List<BCourseInfoVo> routes = bCourseInfoMapper.findRoutesByStations(stationIds);

        for (BCourseInfoVo route : routes) {
            BBusTrackInfoDto dto = new BBusTrackInfoDto();
           // vo.setRouteId(route.getId());
//            vo.setRouteName(route.getName());
//            vo.setStartStation(route.getStartStation());
//            vo.setEndStation(route.getEndStation());
//            vo.setFirstTime(route.getFirstTime());
//            vo.setLastTime(route.getLastTime());
//            vo.setPrice(route.getPrice());
        }

        return null;

//        // 3. 转换并返回结果
//        return routes.stream().map(route -> {
//            RouteVO vo = new RouteVO();
//            vo.setRouteId(route.getId());
//            vo.setRouteName(route.getName());
//            vo.setStartStation(route.getStartStation());
//            vo.setEndStation(route.getEndStation());
//            vo.setFirstTime(route.getFirstTime());
//            vo.setLastTime(route.getLastTime());
//            vo.setPrice(route.getPrice());
//            // 计算距离最近的站点
//            StationDTO nearestStation = findNearestStation(
//                    nearbyStations,
//                    latitude,
//                    longitude
//            );
//            vo.setNearestStation(nearestStation.getName());
//            vo.setDistance(calculateDistance(
//                    latitude,
//                    longitude,
//                    nearestStation.getLatitude(),
//                    nearestStation.getLongitude()
//            ));
//            return vo;
//        }).collect(Collectors.toList());
    }

    /**
     * 查找最近的站点
     */
    private BStationInfoDto findNearestStation(
            List<BStationInfoDto> stations,
            Double latitude,
            Double longitude) {
        return stations.stream()
                .min(Comparator.comparingDouble(station ->
                        calculateDistance(
                                latitude,
                                longitude,
                                 station.getLatitude().doubleValue(),
                                station.getLongitude().doubleValue()
                        )
                ))
                .orElse(null);
    }

    /**
     * 计算两点之间的距离(米)
     */
    private double calculateDistance(
            Double lat1,
            Double lng1,
            Double lat2,
            Double lng2) {
        double radLat1 = Math.toRadians(lat1);
        double radLat2 = Math.toRadians(lat2);
        double a = radLat1 - radLat2;
        double b = Math.toRadians(lng1) - Math.toRadians(lng2);

        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a/2),2) +
                Math.cos(radLat1)*Math.cos(radLat2)*Math.pow(Math.sin(b/2),2)));
        s = s * 6378137; // 地球半径
        return s;
    }

    @Override
    public List<BCourseTrackTreeDto> getTreeList() {
        List<BCourseInfoPo> list = this.bCourseInfoMapper.selectList((Wrapper)((QueryWrapper)(new QueryWrapper()).eq("is_delete", 0)).orderByDesc("status"));
        Map<String, List<BCourseInfoPo>> busGroups = (Map)list.stream().collect(Collectors.groupingBy(BCourseInfoPo::getStatus, Collectors.toList()));
        List<BCourseTrackTreeDto> treeList = new ArrayList();
        busGroups.forEach((status, buses) -> {
            BCourseTrackTreeDto statusNode = new BCourseTrackTreeDto();
            statusNode.setStatus(status);
            List<BTrackNameDto> children = (List)buses.stream().map((bus) -> {
                BTrackNameDto busNode = new BTrackNameDto();
                busNode.setId(bus.getId());
                busNode.setName(bus.getCourseName());
                busNode.setCode(bus.getCourseCode());
                return busNode;
            }).collect(Collectors.toList());
            statusNode.setList(children);
            treeList.add(statusNode);
        });
        return treeList;
    }

    @Override
    public BTrackStationDto getPoint(String courseId) {
        BTrackStationDto dto = new BTrackStationDto();
        BCourseInfoPo byId = (BCourseInfoPo)this.getById(courseId);
        List<BCourseStationPo> listByCourse = this.bCourseStationService.getListByCourse(courseId);
        if (CollectionUtil.isNotEmpty(listByCourse)) {
            List<String> stationIds = (List)listByCourse.stream().map(BCourseStationPo::getStationId).collect(Collectors.toList());
            List<BStationPointDto> list = new ArrayList();
            this.bStationInfoService.listByIds(stationIds).forEach((bStationInfoPo) -> {
                BStationPointDto bCoursePointDto = new BStationPointDto();
                bCoursePointDto.setLatitude(bCoursePointDto.getLatitude());
                bCoursePointDto.setLongitude(bCoursePointDto.getLongitude());
                bCoursePointDto.setId(bStationInfoPo.getId());
                bCoursePointDto.setName(bStationInfoPo.getName());
                list.add(bCoursePointDto);
            });
            dto.setSlist(list);
        }

        String mapPoint = byId.getMapPoint();
        if (StrUtil.isNotBlank(mapPoint)) {
            List<BCoursePointDto> fileJsons = JSONUtil.toList(mapPoint, BCoursePointDto.class);
            dto.setClist(fileJsons);
        }

        dto.setId(courseId);
        return dto;
    }

    @Override
    public List<BStationPointDto> getAllPoint() {
        QueryWrapper<BStationInfoPo> queryWrapper = new QueryWrapper();
        queryWrapper.eq("is_delete", 0);
        List<BStationInfoPo> list = this.bStationInfoService.list(queryWrapper);
        List<BStationPointDto> bStationPointDtos = BeanUtil.copyToList(list, BStationPointDto.class);
        return bStationPointDtos;
    }

    @Override
    public List<BTrackCourseDto> getAllCourse() {
        List<BTrackCourseDto> list = new ArrayList();
        QueryWrapper<BCourseInfoPo> queryWrapper1 = new QueryWrapper();
        queryWrapper1.eq("is_delete", 0);
        List<BCourseInfoPo> list1 = this.list(queryWrapper1);
        Iterator var4 = list1.iterator();

        while(var4.hasNext()) {
            BCourseInfoPo po = (BCourseInfoPo)var4.next();
            String mapPoint = po.getMapPoint();
            if (StrUtil.isNotBlank(mapPoint)) {
                BTrackCourseDto dto = new BTrackCourseDto();
                List<BCoursePointDto> fileJsons = JSONUtil.toList(mapPoint, BCoursePointDto.class);
                dto.setClist(fileJsons);
                dto.setId(po.getId());
                list.add(dto);
            }
        }

        return list;
    }




}
