package com.ningdatech.carapi.homepage.manage;

import java.text.NumberFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.aop.framework.AopContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.carapi.archives.enums.AuditStateEnum;
import com.ningdatech.carapi.car.datascreen.model.dto.DataScreenParam;
import com.ningdatech.carapi.car.vehicle.model.NdVehicleBaseInfo;
import com.ningdatech.carapi.car.vehicle.service.IVehicleBaseInfoService;
import com.ningdatech.carapi.common.aop.BuildChildrenRegionWrapper;
import com.ningdatech.carapi.common.constant.DeletedEnum;
import com.ningdatech.carapi.common.constant.UserRoleTypeEnum;
import com.ningdatech.carapi.common.util.BizUtils;
import com.ningdatech.carapi.datascope.aop.LambdaDataScope;
import com.ningdatech.carapi.driver.entity.DriverAbnormalBehaviorAnalysis;
import com.ningdatech.carapi.driver.entity.DriverAbnormalBehaviorAnalysisPageParamDTO;
import com.ningdatech.carapi.driver.manage.BehaviourAnalysisManage;
import com.ningdatech.carapi.driver.model.vo.BehaviourAnalysisVO;
import com.ningdatech.carapi.homepage.constant.HomepageConstant;
import com.ningdatech.carapi.homepage.entity.dto.HomepageAbnormalBehaviorPageParamDTO;
import com.ningdatech.carapi.homepage.entity.model.OnlineNumCnt;
import com.ningdatech.carapi.homepage.entity.po.DriverAbnormalBehaviorNumPO;
import com.ningdatech.carapi.homepage.entity.po.VehicleNumPO;
import com.ningdatech.carapi.homepage.entity.vo.HomepageDriverAbnormalBehaviorVo;
import com.ningdatech.carapi.homepage.entity.vo.HomepageVo;
import com.ningdatech.carapi.homepage.service.IHomepageService;
import com.ningdatech.carapi.sys.entity.dto.OperatorQueryDTO;
import com.ningdatech.carapi.sys.helper.OperatorsCacheHelper;
import com.ningdatech.carapi.user.security.auth.model.UserInfoDetails;
import com.ningdatech.carapi.user.util.LoginUserUtil;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.StopWatch;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author CMM
 * @description
 * @since 2022/12/08 17:10
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class HomepageManage {

    private final BehaviourAnalysisManage behaviourAnalysisManage;
    private final IHomepageService homepageService;
    private final OperatorsCacheHelper operatorsCacheHelper;
    private final IVehicleBaseInfoService vehicleBaseInfoService;
    private final StringRedisTemplate stringRedisTemplate;
    /**
     * 驾驶员异常行为列表及数据统计
     * @param param
     * @return
     */
    public HomepageDriverAbnormalBehaviorVo abnormalBehaviorList(HomepageAbnormalBehaviorPageParamDTO param) {
        
        LambdaQueryWrapper<DriverAbnormalBehaviorAnalysis> wrapper = Wrappers.lambdaQuery(DriverAbnormalBehaviorAnalysis.class);
        HomepageManage context = (HomepageManage) AopContext.currentProxy();

        // 装配今年查询时间
        LocalDate year = LocalDate.now();
        HomepageAbnormalBehaviorPageParamDTO paramDTO = getAbnormalBehaviorQueryTimeParamDTO(year, param);
        // 根据传入的筛选时间参数和当前时间，从告警表中查出今年的告警异常行为总数、已督办的总数、已处理的总数
        HomepageDriverAbnormalBehaviorVo currentYearResult = context.search(wrapper, paramDTO);

        // 装配去年查询时间
        LocalDate lastYear = LocalDate.now().minusYears(1);
        HomepageAbnormalBehaviorPageParamDTO lastYearParamDTO = getAbnormalBehaviorQueryTimeParamDTO(lastYear, param);
        // 根据传入的筛选时间参数和当前时间，从告警表中查出上一年同期的告警异常行为总数
        HomepageDriverAbnormalBehaviorVo lastYearResult = context.search(wrapper, lastYearParamDTO);
        Long samePeriodTotalNum = lastYearResult.getAbnormalBehaviorTotalNum();

        log.info("同期告警事件总数为:" + samePeriodTotalNum);

        Long total = currentYearResult.getAbnormalBehaviorTotalNum();
        Long overSeedCount = currentYearResult.getOverSeedTotalNum();
        Long processedCount = currentYearResult.getProcessedTotalNum();
        log.info("告警事件的总数为:" + total);
        log.info("告警事件已督办的总数为:" + overSeedCount);
        log.info("告警事件已处理的总数为:" + processedCount);

        // 计算督办率
        String overSeedRate = BizUtils.percent(overSeedCount, total);
        log.info("督办率为:" + overSeedRate);
        currentYearResult.setOverSeedRate(overSeedRate);
        // 计算处理率
        String processedRate = BizUtils.percent(processedCount, total);
        log.info("处理率为:" + processedRate);
        currentYearResult.setProcessedRate(processedRate);

        // 计算同比增长率
        if (Objects.isNull(total)){
            total = 0L;
        }
        if (Objects.isNull(samePeriodTotalNum)){
            samePeriodTotalNum = 0L;
        }
        String growthRate = BizUtils.percent(total - samePeriodTotalNum, total);
        log.info("同期增长率为:" + growthRate);
        currentYearResult.setGrowthRate(growthRate);

        return currentYearResult;
    }

    /**
     * 获取去年同期查询时间
     * @param param
     * @return
     */
    private HomepageAbnormalBehaviorPageParamDTO getAbnormalBehaviorQueryTimeParamDTO(LocalDate year, HomepageAbnormalBehaviorPageParamDTO param) {
        HomepageAbnormalBehaviorPageParamDTO paramDTO = new HomepageAbnormalBehaviorPageParamDTO();
        LocalDateTime queryStartTime = null;
        LocalDateTime queryEndTime = null;
        String time = param.getTimeFlag();

        if (HomepageConstant.YEAR_FLAG.equals(time)) {
            // 获取传入年份的第一天及最后一天
            queryStartTime =
                LocalDateTime.of(LocalDate.from(year.with(TemporalAdjusters.firstDayOfYear())), LocalTime.MIN);
            queryEndTime =
                LocalDateTime.of(LocalDate.from(year.with(TemporalAdjusters.lastDayOfYear())), LocalTime.MAX);
        } else if (HomepageConstant.MONTH_FLAG.equals(time)) {
            // 获取传入年份当前月第一天及最后一天
            queryStartTime =
                LocalDateTime.of(LocalDate.from(year.with(TemporalAdjusters.firstDayOfMonth())), LocalTime.MIN);
            queryEndTime =
                LocalDateTime.of(LocalDate.from(year.with(TemporalAdjusters.lastDayOfMonth())), LocalTime.MAX);
        } else if (HomepageConstant.DAY_FLAG.equals(time)) {
            // 获取传入年份当天的起始时间
            queryStartTime = LocalDateTime.of(year, LocalTime.MIN);
            queryEndTime = LocalDateTime.of(year, LocalTime.MAX);
        }

        paramDTO.setQueryStartTime(queryStartTime);
        paramDTO.setQueryEndTime(queryEndTime);
        paramDTO.setTimeFlag(param.getTimeFlag());
        return paramDTO;
    }

    /**
     * 驾驶员异常行为按时间标志查询
     * @param wrapper
     * @param param
     * @return
     */
    @LambdaDataScope
    public HomepageDriverAbnormalBehaviorVo search(LambdaQueryWrapper<DriverAbnormalBehaviorAnalysis> wrapper, HomepageAbnormalBehaviorPageParamDTO param) {
        HomepageDriverAbnormalBehaviorVo resVo = new HomepageDriverAbnormalBehaviorVo();
        wrapper.orderByDesc(DriverAbnormalBehaviorAnalysis::getAlarmTime);

        // 获取异常行为列表请求实体
        DriverAbnormalBehaviorAnalysisPageParamDTO paramDTO = new DriverAbnormalBehaviorAnalysisPageParamDTO();
        //获取统计数据请求实体
        HomepageAbnormalBehaviorPageParamDTO po = new HomepageAbnormalBehaviorPageParamDTO();
        // 异常行为列表
        PageVo<BehaviourAnalysisVO> of = null;

        LocalDateTime queryStartTime = param.getQueryStartTime();
        LocalDateTime queryEndTime = param.getQueryEndTime();
        po.setQueryStartTime(queryStartTime);
        po.setQueryEndTime(queryEndTime);
        if (Objects.nonNull(param.getTimeFlag())) {
            paramDTO.setStartTime(queryStartTime);
            paramDTO.setEndTime(queryEndTime);
            paramDTO.setRegionId(param.getRegionId());
        }
        of = behaviourAnalysisManage.behaviorAnalysisList(paramDTO);

        resVo.setOf(of);
        // 根据传入的时间标志查询出告警事件的总数以及已督办、已处理事件的总数.
        DriverAbnormalBehaviorNumPO driverAbnormalBehaviorNum = homepageService.driverAbnormalBehaviorNum(po);
        if (Objects.nonNull(driverAbnormalBehaviorNum)) {
            resVo.setAbnormalBehaviorTotalNum(Objects.isNull(driverAbnormalBehaviorNum.getTotal()) ? 0L : driverAbnormalBehaviorNum.getTotal());
            resVo.setOverSeedTotalNum(Objects.isNull(driverAbnormalBehaviorNum.getOverSeedCount()) ? 0L : driverAbnormalBehaviorNum.getOverSeedCount());
            resVo.setProcessedTotalNum(Objects.isNull(driverAbnormalBehaviorNum.getProcessedCount()) ? 0L : driverAbnormalBehaviorNum.getProcessedCount());
        }
        return resVo;
    }

    /**
     * 根据传入的区域id查询车辆状态信息
     *
     * @param param
     * @return
     */
    public HomepageVo queryVehicleStatistics(DataScreenParam param) {
        HomepageVo result = new HomepageVo();

        // 按照登录用户，如果是运营商账号登录，删选出该运营商关联的车辆信息
        UserInfoDetails userDetail = LoginUserUtil.loginUserDetail();
        Long roleId = userDetail.getRoleId();

        if (UserRoleTypeEnum.OPERATOR_ROLE_ID.getId().equals(roleId)) {
            String companyName = userDetail.getCompanyName();
            // 暂时控制运营商名称和运营商所在企业名称相同
            OperatorQueryDTO operatorQueryDTO = operatorsCacheHelper.getByName(companyName);
            // 获取运营商id
            Long operatorId = operatorQueryDTO.getId();
            param.setOperatorId(operatorId);
        }

        LambdaQueryWrapper<NdVehicleBaseInfo> wrapper = Wrappers.lambdaQuery(NdVehicleBaseInfo.class);
        HomepageManage context = (HomepageManage) AopContext.currentProxy();
        context.buildSearchQuery(wrapper, param);
        List<NdVehicleBaseInfo> vehicleBaseInfos = vehicleBaseInfoService.list(wrapper);

        VehicleNumPO vehicleNumPo = homepageService.vehicleNum(param);
        Integer vehicleNum = vehicleNumPo.getTotalNum();
        Integer onlineVehicleNum = 0;
        Integer offlineVehicleNum = 0;

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Long cnt = vehicleBaseInfos.stream().filter(o -> Objects.nonNull(o) &&
                Objects.nonNull(o.getStatus()) && o.getStatus() == 1).count();
        stopWatch.stop();
        log.info("共耗时 {}s", stopWatch.getTotalTimeSeconds());
        log.info("缓存中车辆在线数为：" + cnt);
        onlineVehicleNum = cnt.intValue();
        offlineVehicleNum = vehicleNum - onlineVehicleNum;
        Integer accumulativeOnlineNumber = onlineVehicleNum;
        log.info("车辆总数为：" + vehicleNum);
        log.info("车辆在线数为：" + onlineVehicleNum);
        log.info("车辆离线数为：" + offlineVehicleNum);
        log.info("车辆累积在线数为：" + accumulativeOnlineNumber);

        result.setVehicleNum(vehicleNum);

        result.setOnlineVehicleNum(onlineVehicleNum);
        result.setOfflineVehicleNum(offlineVehicleNum);
        result.setAccumulativeOnlineNumber(accumulativeOnlineNumber);
        try {
            NumberFormat numberFormat = NumberFormat.getInstance();
            numberFormat.setMaximumFractionDigits(2);
            String vehicleOnlineRate = vehicleNum.equals(0) ? "0%"
                : numberFormat.format((float)onlineVehicleNum / (float)vehicleNum * 100) + "%";
            log.info("车辆上线率为：" + vehicleOnlineRate);
            result.setVehicleOnlineRate(vehicleOnlineRate);

            String vehicleOfflineRate = vehicleNum.equals(0) ? "0%"
                : numberFormat.format((float)offlineVehicleNum / (float)vehicleNum * 100) + "%";
            log.info("车辆离线率为：" + vehicleOfflineRate);
            result.setVehicleOfflineRate(vehicleOfflineRate);

            String accumulativeOnlineRate = vehicleNum.equals(0) ? "0%"
                : numberFormat.format((float)accumulativeOnlineNumber / (float)vehicleNum * 100) + "%";
            log.info("车辆累积在线率为：" + accumulativeOnlineRate);
            result.setAccumulativeOnlineRate(accumulativeOnlineRate);
        } catch (Exception e) {
            log.error("AI工作台异常{}", e.getMessage());
        }
        return result;
    }

    @LambdaDataScope
    @BuildChildrenRegionWrapper
    public void buildSearchQuery(LambdaQueryWrapper<NdVehicleBaseInfo> wrapper, DataScreenParam param) {
        wrapper.eq(NdVehicleBaseInfo::getDeleted, DeletedEnum.NO_DELETED.getCode())
                .eq(NdVehicleBaseInfo::getAuditState, AuditStateEnum.AUDIT_SUCCESS.getCode())
                .eq(Objects.nonNull(param.getOperatorId()),NdVehicleBaseInfo::getOperatorId,param.getOperatorId())
                .in(Objects.nonNull(param.getCompanyIds()),NdVehicleBaseInfo::getCompanyId,param.getCompanyIds());
    }
}
