package com.sckw.transport.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.sckw.core.model.enums.AddressTypeEnum;
import com.sckw.core.utils.DateUtils;
import com.sckw.core.web.context.LoginUserHolder;
import com.sckw.core.web.response.BaseIotResult;
import com.sckw.core.web.response.result.PageDataResult;
import com.sckw.transport.api.feign.VehicleTraceClient;
import com.sckw.transport.api.model.dto.VehicleDataDTO;
import com.sckw.transport.api.model.dto.VehicleReturnData;
import com.sckw.transport.model.KwtLogisticsOrderAddress;
import com.sckw.transport.model.KwtLogisticsOrderUnit;
import com.sckw.transport.model.KwtVehicleException;
import com.sckw.transport.model.KwtWaybillOrderSubtask;
import com.sckw.transport.model.dto.VehicleExceptionQueryReq;
import com.sckw.transport.model.enuma.VehicleExceptionTypeEnum;
import com.sckw.transport.model.vo.VehicleExceptionVo;
import com.sckw.transport.repository.KwtLogisticsOrderAddressRepository;
import com.sckw.transport.repository.KwtLogisticsOrderUnitRepository;
import com.sckw.transport.repository.KwtVehicleExceptionRepository;
import com.sckw.transport.repository.KwtWaybillOrderSubtaskRepository;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author cxf
 * @desc 车辆异常图片Service
 * @date 2025-12-01
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class VehicleExceptionService {
    
    private final KwtVehicleExceptionRepository exceptionImageRepository;
    private final VehicleTraceClient vehicleTraceClient;
    private final KwtWaybillOrderSubtaskRepository waybillOrderSubtaskRepository;
    private final KwtLogisticsOrderAddressRepository logisticsOrderAddressRepository;
    private final KwtLogisticsOrderUnitRepository kwtLogisticsOrderUnitRepository;
    
    /**
     * 分页查询车辆异常图片信息
     *
     * @param req 查询请求
     * @return 分页结果
     */

    /**
     * 分页查询车辆异常图片信息
     *
     * @param req 查询请求参数
     * @return 车辆异常图片分页结果
     */
    /**
     * 分页查询车辆异常图片信息
     *
     * @param req 查询请求参数
     * @return 车辆异常图片分页结果
     */
    public PageDataResult<VehicleExceptionVo> queryExceptionList(VehicleExceptionQueryReq req) {
        log.info("分页查询车辆异常信息，参数：{}", JSON.toJSONString(req));

        // 设置默认日期参数
        setDefaultDateRange(req);

        // 分页查询异常图片数据
        IPage<KwtVehicleException> page = exceptionImageRepository.queryExceptionImagePage(
                req.getEntId(),
                req.getExceptionType(),
                req.getTruckNo(),
                req.getStartDate(),
                req.getEndDate(),
                req.getPageNum(),
                req.getPageSize()
        );

        // 获取查询结果记录列表
        List<KwtVehicleException> records = page.getRecords();
        // 如果记录为空，返回空的分页结果
        if (CollectionUtils.isEmpty(records)) {
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }

        // 如果有定位状态筛选条件，需要查询车辆实时定位状态
        Map<String, Integer> truckLocationStatusMap = Collections.emptyMap();
        if (req.getLocationStatus() != null) {
            // 提取所有不重复的车牌号
            Map<Long, String> truckIdAndTruckNoMap = records.stream()
                    .filter(x -> Objects.nonNull(x.getTruckId()))
                    .collect(Collectors.toMap(KwtVehicleException::getTruckId, KwtVehicleException::getTruckNo, (k1, k2) -> k1));

            // 批量查询车辆定位状态
            truckLocationStatusMap = queryVehicleLocationStatus(truckIdAndTruckNoMap);
        }

        // 提取所有不重复的运单ID
        List<Long> waybillOrderIds = records.stream()
                .map(KwtVehicleException::getWOrderId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        // 查询相关运单和地址信息
        Map<String, KwtLogisticsOrderAddress> logisticsOrderAddressMap;
        Map<Long, KwtWaybillOrderSubtask> waybillOrderSubtaskMap;

        if (CollectionUtils.isNotEmpty(waybillOrderIds)) {
            // 查询运单信息和地址信息
            LogisticsOrderData logisticsOrderData = queryLogisticsOrderData(waybillOrderIds);
            waybillOrderSubtaskMap = logisticsOrderData.getWaybillOrderSubtaskMap();
            logisticsOrderAddressMap = logisticsOrderData.getLogisticsOrderAddressMap();
        } else {
            logisticsOrderAddressMap = Collections.emptyMap();
            waybillOrderSubtaskMap = Collections.emptyMap();
        }

        // 将查询结果转换为VO对象
        final Map<String, Integer> finalLocationStatusMap = truckLocationStatusMap;
        final Integer locationStatusFilter = req.getLocationStatus();


        // 遍历异常图片记录，构建VO对象列表
        List<VehicleExceptionVo> voList = records.stream()
                .map(image -> buildVehicleExceptionVo(image, finalLocationStatusMap, waybillOrderSubtaskMap, logisticsOrderAddressMap))
                // 过滤掉空值和不符合定位状态条件的记录
                .filter(Objects::nonNull)
                .filter(vo -> locationStatusFilter == null || locationStatusFilter.equals(vo.getLocationStatus()))
                .collect(Collectors.toList());

        // 返回分页结果
        return PageDataResult.of(page, voList);
    }

    /**
     * 设置默认日期范围
     */
    private void setDefaultDateRange(VehicleExceptionQueryReq req) {
        if (StringUtils.isBlank(req.getStartDate())) {
            String startDate = DateUtils.format(DateUtils.getStartOfDay(new Date()), DateUtils.DATE_TIME_PATTERN);
            req.setStartDate(startDate);
        }
        if (StringUtils.isBlank(req.getEndDate())) {
            String endDate = DateUtils.format(DateUtils.getEndOfDay(new Date()), DateUtils.DATE_TIME_PATTERN);
            req.setEndDate(endDate);
        }
    }

    /**
     * 查询物流订单相关数据
     */
    private LogisticsOrderData queryLogisticsOrderData(List<Long> waybillOrderIds) {
        LogisticsOrderData data = new LogisticsOrderData();

        // 查询运单信息
        List<KwtWaybillOrderSubtask> subtasks = waybillOrderSubtaskRepository.queryByWOrderIds(waybillOrderIds);

        if (CollectionUtils.isNotEmpty(subtasks)) {
            // 构建运单ID到运单信息的映射关系
            Map<Long, KwtWaybillOrderSubtask> waybillOrderSubtaskMap = subtasks.stream()
                    .collect(Collectors.toMap(KwtWaybillOrderSubtask::getWOrderId, Function.identity(), (k1, k2) -> k1));

            // 提取物流订单ID
            List<Long> logisticOrderIds = subtasks.stream()
                    .map(KwtWaybillOrderSubtask::getLOrderId)
                    .filter(Objects::nonNull)
                    .distinct()
                    .collect(Collectors.toList());

            // 查询地址信息
            if (CollectionUtils.isNotEmpty(logisticOrderIds)) {
                List<KwtLogisticsOrderAddress> logisticOrderAddresses = logisticsOrderAddressRepository.queryByLogOrderIds(logisticOrderIds);
                // 构建物流订单ID+地址类型到地址信息的映射关系
                Map<String, KwtLogisticsOrderAddress> logisticsOrderAddressMap = Optional.ofNullable(logisticOrderAddresses)
                        .orElse(Collections.emptyList())
                        .stream()
                        .collect(Collectors.toMap(x -> x.getLOrderId() + "_" + x.getAddressType(), Function.identity(), (k1, k2) -> k1));

                data.setLogisticsOrderAddressMap(logisticsOrderAddressMap);
            }

            data.setWaybillOrderSubtaskMap(waybillOrderSubtaskMap);
        }

        return data;
    }

    /**
     * 物流订单数据容器
     */
    @Data
    private static class LogisticsOrderData {
        private Map<Long, KwtWaybillOrderSubtask> waybillOrderSubtaskMap;
        private Map<String, KwtLogisticsOrderAddress> logisticsOrderAddressMap;
    }

    /**
     * 构建车辆异常图片VO
     *
     * @param image                异常图片实体
     * @param locationStatusMap    定位状态Map
     * @return VO对象
     */
    private VehicleExceptionVo buildVehicleExceptionVo(KwtVehicleException image,
                                                       Map<String, Integer> locationStatusMap,
                                                       Map<Long, KwtWaybillOrderSubtask> waybillOrderSubtaskMap ,
                                                       Map<String, KwtLogisticsOrderAddress> logisticsOrderAddressMap) {
        VehicleExceptionVo vo = new VehicleExceptionVo();
        
        vo.setId(image.getId());
        vo.setTruckNo(image.getTruckNo());
        vo.setExceptionType(image.getExceptionType());
        vo.setExceptionTypeName(VehicleExceptionTypeEnum.getName(image.getExceptionType()));
        vo.setImageUrl(image.getImageUrl());
        
        // 格式化异常时间
        if (image.getExceptionTime() != null) {
            vo.setExceptionTime(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
                    .format(image.getExceptionTime()));
        }
        
        vo.setLongitude(image.getLongitude());
        vo.setLatitude(image.getLatitude());
        vo.setLocation(image.getLocation());
        vo.setDescription(image.getDescription());
        vo.setDriverId(image.getDriverId());
        vo.setDriverName(image.getDriverName());
        vo.setDriverPhone(image.getDriverPhone());
        
        // 设置定位状态
        if (locationStatusMap.containsKey(image.getTruckNo())) {
            Integer locationStatus = locationStatusMap.get(image.getTruckNo());
            vo.setLocationStatus(locationStatus);
            vo.setLocationStatusDesc(locationStatus == 1 ? "在线" : "离线");
        } else {
            vo.setLocationStatus(0);
            vo.setLocationStatusDesc("离线");
        }
        KwtWaybillOrderSubtask subtask = waybillOrderSubtaskMap.getOrDefault(image.getWOrderId(), new KwtWaybillOrderSubtask());
        KwtLogisticsOrderAddress loadAdd = logisticsOrderAddressMap.getOrDefault(subtask.getLOrderId() + "_" + AddressTypeEnum.SHIPMENT.getCode(), new KwtLogisticsOrderAddress());
        KwtLogisticsOrderAddress unLoadAdd = logisticsOrderAddressMap.getOrDefault(subtask.getLOrderId() + "_" + AddressTypeEnum.TAKE.getCode(), new KwtLogisticsOrderAddress());
        vo.setLoadAddress(loadAdd.getDetailAddress());
        vo.setStartLng(loadAdd.getLng());
        vo.setStartLat(loadAdd.getLat());
        vo.setUnloadAddress(unLoadAdd.getDetailAddress());
        vo.setEndLng(unLoadAdd.getLng());
        vo.setEndLat(unLoadAdd.getLat());
        vo.setWaybillId(image.getWOrderId());
        vo.setWaybillNo(image.getWOrderNo());
        return vo;
    }
    
    /**
     * 批量查询车辆定位状态
     *
     * @param truckIdAndTruckNoMap 车牌id列表
     * @return 车牌号与定位状态的映射
     */
    private Map<String, Integer> queryVehicleLocationStatus(  Map<Long, String> truckIdAndTruckNoMap) {
        Map<String, Integer> locationStatusMap = new HashMap<>();
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime thirtyMinutesAgo = now.minusMinutes(30);
        if (MapUtils.isEmpty(truckIdAndTruckNoMap)){
            return locationStatusMap;
        }
        truckIdAndTruckNoMap.forEach((truckId, truckNo) -> {
            try {
                VehicleDataDTO vehicleDataDTO = new VehicleDataDTO();
                vehicleDataDTO.setCarNo(Objects.isNull(truckId) ? "0" : String.valueOf(truckId));
                BaseIotResult<VehicleReturnData> result = vehicleTraceClient.queryRealTimeLocation(vehicleDataDTO);
                // 默认离线
                Integer locationStatus = 0;

                if (result != null && StringUtils.equals(result.getCode(), "0") && result.getData() != null) {
                    VehicleReturnData vehicleData = result.getData();

                    // 判断30分钟内有定位数据为在线
                    if (vehicleData.getTs() != null && vehicleData.getTs().toLocalDateTime().isAfter(thirtyMinutesAgo)) {
                        locationStatus = 1;
                    }
                }

                locationStatusMap.put(truckNo, locationStatus);
            } catch (Exception e) {
                log.warn("查询车辆定位状态异常, 车牌号: {}", truckNo, e);
                locationStatusMap.put(truckNo, 0);
            }
        });

        
        return locationStatusMap;
    }


    /**
     * 分页查询车辆异常监控列表
     *
     * @param req 查询请求参数
     * @return 车辆异常监控分页结果
     */
    public PageDataResult<VehicleExceptionVo> exceptionJkList(VehicleExceptionQueryReq req) {
        log.info("分页查询车辆异常监控列表, req: {}", JSON.toJSONString( req));
        if (StringUtils.isBlank( req.getStartDate())){
            String startDate = DateUtils.format(DateUtils.getStartOfDay(new Date()), DateUtils.DATE_TIME_PATTERN);
            req.setStartDate(startDate);
        }
        if (StringUtils.isBlank( req.getEndDate())){
            String endDate = DateUtils.format(DateUtils.getEndOfDay(new Date()), DateUtils.DATE_TIME_PATTERN);
            req.setEndDate(endDate);
        }

        Long entId = Objects.nonNull(req.getEntId()) ? req.getEntId() : LoginUserHolder.getEntId();
        //根据企业查询物流订单
        List<KwtLogisticsOrderUnit> kwtLogisticsOrderUnits = kwtLogisticsOrderUnitRepository.queryByEntId(entId);
        if (CollectionUtils.isEmpty(kwtLogisticsOrderUnits)) {
            log.info("该企业未查询到物流订单数据，企业id:{}", entId);
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }
        //获取物流订单号
        Set<Long> logOrderIds = kwtLogisticsOrderUnits.stream()
                .map(KwtLogisticsOrderUnit::getLOrderId)
                .collect(Collectors.toSet());
        if (CollectionUtils.isEmpty(logOrderIds)) {
            log.info("该企业下物流订单数据，企业id:{}", entId);
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }
        //查询物流运动
        List<KwtWaybillOrderSubtask> kwtWaybillOrderSubtasks = waybillOrderSubtaskRepository.queryByLogIds(new ArrayList<>(logOrderIds));
        if (CollectionUtils.isEmpty(kwtWaybillOrderSubtasks)) {
            log.info("该企业下没有物流运单数据，企业id:{}", entId);
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }
        //获取运单号
        Set<Long> wOrderIds = kwtWaybillOrderSubtasks.stream()
                .map(KwtWaybillOrderSubtask::getWOrderId)
                .collect(Collectors.toSet());
        // 分页查询异常图片数据
        IPage<KwtVehicleException> page = exceptionImageRepository.queryExceptionImagePage1(
                wOrderIds,
                req.getExceptionType(),
                req.getTruckNo(),
                req.getStartDate(),
                req.getEndDate(),
                req.getPageNum(),
                req.getPageSize()
        );

        // 获取查询结果记录列表
        List<KwtVehicleException> records = page.getRecords();
        // 如果记录为空，返回空的分页结果
        if (CollectionUtils.isEmpty(records)) {
            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
        }

        // 如果有定位状态筛选条件，需要查询车辆实时定位状态
        Map<String, Integer> truckLocationStatusMap = new HashMap<>();
        if (req.getLocationStatus() != null) {
            // 提取所有不重复的车牌号
            Map<Long, String> truckIdAndTruckNoMap = records.stream()
                    .filter(x->Objects.nonNull(x.getTruckId()))
                    .collect(Collectors.toMap(KwtVehicleException::getTruckId, KwtVehicleException::getTruckNo, (k1, k2) -> k1));

            // 批量查询车辆定位状态
            truckLocationStatusMap = queryVehicleLocationStatus(truckIdAndTruckNoMap);
        }
        
        // 提取所有不重复的运单ID
        List<Long> waybillOrderNos = records.stream()
                .map(KwtVehicleException::getWOrderId)
                .distinct()
                .collect(Collectors.toList());
        
        // 初始化地址和运单信息Map
        Map<String, KwtLogisticsOrderAddress> logisticsOrderAddressMap = Maps.newHashMap();
        Map<Long, KwtWaybillOrderSubtask> waybillOrderSubtaskMap = Maps.newHashMap();
        
        // 如果存在运单ID，则查询相关运单和地址信息
        if (CollectionUtils.isNotEmpty(waybillOrderNos)){
            // 查询运单信息
            List<KwtWaybillOrderSubtask> subtasks = waybillOrderSubtaskRepository.queryByWOrderIds(waybillOrderNos);
            List<Long> logisticOrderIds = Lists.newArrayList();
            
            // 如果查询到运单信息，则提取物流订单ID
            if (CollectionUtils.isNotEmpty(subtasks)){
                logisticOrderIds = subtasks.stream().map(KwtWaybillOrderSubtask::getLOrderId)
                        .distinct()
                        .collect(Collectors.toList());
                // 构建运单ID到运单信息的映射关系
                waybillOrderSubtaskMap = subtasks.stream()
                        .collect(Collectors.toMap(KwtWaybillOrderSubtask::getWOrderId, Function.identity(), (k1, k2) -> k1));
            }
            
            // 如果存在物流订单ID，则查询相关地址信息
            if (CollectionUtils.isNotEmpty(logisticOrderIds)){
                // 查询地址信息
                List<KwtLogisticsOrderAddress> logisticOrderAddresses = logisticsOrderAddressRepository.queryByLogOrderIds(logisticOrderIds);
                // 构建物流订单ID+地址类型到地址信息的映射关系
                logisticsOrderAddressMap = Optional.ofNullable(logisticOrderAddresses)
                        .orElse(List.of())
                        .stream().collect(Collectors.toMap(x -> x.getLOrderId() + "_" + x.getAddressType(), Function.identity(), (k1, k2) -> k1));
            }
        }
        
        // 将查询结果转换为VO对象
        final Map<String, Integer> finalLocationStatusMap = truckLocationStatusMap;
        Map<String, KwtLogisticsOrderAddress> finalLogisticsOrderAddressMap = logisticsOrderAddressMap;
        Map<Long, KwtWaybillOrderSubtask> finalWaybillOrderSubtaskMap = waybillOrderSubtaskMap;
        
        // 遍历异常图片记录，构建VO对象列表
        List<VehicleExceptionVo> voList = records.stream()
                .map(image -> buildVehicleExceptionVo(image, finalLocationStatusMap, finalWaybillOrderSubtaskMap, finalLogisticsOrderAddressMap))
                // 过滤掉空值
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        // 如果有定位状态筛选条件，再次过滤结果
        if (req.getLocationStatus() != null) {
            voList = voList.stream()
                    .filter(vo -> req.getLocationStatus().equals(vo.getLocationStatus()))
                    .collect(Collectors.toList());
        }

        // 返回分页结果
        return PageDataResult.of(page, voList);
    }
}
