package com.ningdatech.carapi.driver.manage;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Component;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.NdDateUtils;
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.CommonConstant;
import com.ningdatech.carapi.common.model.FileBasicInfo;
import com.ningdatech.carapi.common.util.ExcelDownUtil;
import com.ningdatech.carapi.common.util.ExcelExportStyle;
import com.ningdatech.carapi.datascope.aop.LambdaDataScope;
import com.ningdatech.carapi.datascope.contants.LambdaDataScopeTypeEnum;
import com.ningdatech.carapi.driver.constant.DriverAbnormalBehaviorAppendixTypeEnum;
import com.ningdatech.carapi.driver.constant.DriverAbnormalBehaviorProcessingEnum;
import com.ningdatech.carapi.driver.entity.*;
import com.ningdatech.carapi.driver.model.vo.BehaviourAnalysisVO;
import com.ningdatech.carapi.driver.model.vo.DriverAbnormalBehaviorAnalysisDetailVO;
import com.ningdatech.carapi.driver.model.vo.DriverDailyAlarmEvent;
import com.ningdatech.carapi.driver.service.IBehaviorAnalysisProcessingModeService;
import com.ningdatech.carapi.driver.service.IBehaviourAnalysisService;
import com.ningdatech.carapi.driver.service.IDriverInfoService;
import com.ningdatech.carapi.scheduler.contants.TaskConstant;
import com.ningdatech.carapi.sys.entity.Company;
import com.ningdatech.carapi.sys.service.CompanyService;
import com.ningdatech.carapi.user.util.LoginUserUtil;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author CMM
 * @Classname BehaviourAnalysisManage
 * @Description
 * @Date 2022/11/7 16:30
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class BehaviourAnalysisManage {

    private final IBehaviourAnalysisService behaviourAnalysisService;
    private final IDriverInfoService driverInfoService;
    private final IBehaviorAnalysisProcessingModeService behaviorAnalysisProcessingModeService;
    private final CompanyService companyService;
    private final IVehicleBaseInfoService vehicleBaseInfoService;


    public PageVo<BehaviourAnalysisVO> behaviorAnalysisList(DriverAbnormalBehaviorAnalysisPageParamDTO param) {
        Page<DriverAbnormalBehaviorAnalysis> page = param.page();

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        Map<Long, Company> companyMap = companyService.list(Wrappers.lambdaQuery(Company.class)
                .select(Company::getId,Company::getName)).stream().collect(Collectors.toMap(Company::getId, c -> c));
        Map<String, NdVehicleBaseInfo> vehicleBaseInfoMap = vehicleBaseInfoService.list(Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
                        .select(NdVehicleBaseInfo::getCarPlate,NdVehicleBaseInfo::getCompanyId)).stream()
                .collect(Collectors.toMap(v -> v.getCarPlate() + v.getCompanyId(), v -> v));
        stopWatch.stop();
        log.info("1共耗时 {}s", stopWatch.getTotalTimeSeconds());

        StopWatch stopWatch2 = new StopWatch();
        stopWatch2.start();
        LambdaQueryWrapper<DriverAbnormalBehaviorAnalysis> wrapper = Wrappers.lambdaQuery(DriverAbnormalBehaviorAnalysis.class);
        BehaviourAnalysisManage context = (BehaviourAnalysisManage) AopContext.currentProxy();
        context.buildBehaviourAnalysisQuery(wrapper, param);
        behaviourAnalysisService.page(page, wrapper);
        stopWatch2.stop();
        log.info("2共耗时 {}s", stopWatch2.getTotalTimeSeconds());

        // 驾驶员异常行为列表查询
        if (0L == page.getTotal()) {
            return PageVo.empty();
        }

        List<BehaviourAnalysisVO> behaviourAnalysisVOList = page.getRecords().stream().map(b -> {
            BehaviourAnalysisVO resVo = new BehaviourAnalysisVO();
            BeanUtil.copyProperties(b, resVo);
            BigDecimal speed = BigDecimal.valueOf(b.getSpeed()).multiply(TaskConstant.Math.SPEED_UNITS)
                    .setScale(BigDecimal.ROUND_CEILING, RoundingMode.HALF_UP);
            resVo.setSpeed(speed);
            String alarmPictureAppendix = b.getAlarmPictureAppendix();
            String alarmVideoAppendix = b.getAlarmVideoAppendix();
            List<FileBasicInfo> list = getFileBasicInfos(alarmPictureAppendix, alarmVideoAppendix);
            resVo.setAlarmAppendix(list);
            NdVehicleBaseInfo vehicleBaseInfo = vehicleBaseInfoMap.get(b.getCarPlate() + b.getCompanyId());
            if (Objects.nonNull(vehicleBaseInfo)) {
                resVo.setCompanyId(vehicleBaseInfo.getCompanyId());
                Company company = companyMap.get(vehicleBaseInfo.getCompanyId());
                resVo.setCompanyName(company.getName());
            }
            return resVo;
        }).collect(Collectors.toList());
        return PageVo.of(behaviourAnalysisVOList, page.getTotal());
    }

    private List<FileBasicInfo> getFileBasicInfos(String alarmPic, String alarmVideo) {
        List<FileBasicInfo> list = new ArrayList<>();
        if (StrUtil.isNotBlank(alarmPic) && !HttpUtil.isHttps(alarmPic) && !HttpUtil.isHttp(alarmPic)) {
            FileBasicInfo filePictureBasicInfo = new FileBasicInfo();
            filePictureBasicInfo.setFileType(DriverAbnormalBehaviorAppendixTypeEnum.PICTURE.getCode());
            filePictureBasicInfo.setFilePath(alarmPic);
            list.add(filePictureBasicInfo);
        }
        if (StrUtil.isNotBlank(alarmVideo) && !HttpUtil.isHttps(alarmVideo) && !HttpUtil.isHttp(alarmVideo)) {
            FileBasicInfo fileVideoBasicInfo = new FileBasicInfo();
            fileVideoBasicInfo.setFileType(DriverAbnormalBehaviorAppendixTypeEnum.VIDEO.getCode());
            fileVideoBasicInfo.setFilePath(alarmVideo);
            list.add(fileVideoBasicInfo);
        }
        return list;
    }

    @LambdaDataScope
    @BuildChildrenRegionWrapper
    public void buildBehaviourAnalysisQuery(LambdaQueryWrapper<DriverAbnormalBehaviorAnalysis> wrapper, DriverAbnormalBehaviorAnalysisPageParamDTO param) {
        wrapper.like(StringUtils.isNotBlank(param.getCarPlate()), DriverAbnormalBehaviorAnalysis::getCarPlate, param.getCarPlate())
                .eq(Objects.nonNull(param.getLevel()), DriverAbnormalBehaviorAnalysis::getAlarmLevel, param.getLevel())
                .ge(Objects.nonNull(param.getStartTime()), DriverAbnormalBehaviorAnalysis::getAlarmTime, param.getStartTime())
                .le(Objects.nonNull(param.getEndTime()), DriverAbnormalBehaviorAnalysis::getAlarmTime, param.getEndTime())
                .in(Objects.nonNull(param.getAlarmType()), DriverAbnormalBehaviorAnalysis::getAlarmType, param.getAlarmType())
                .eq(Objects.nonNull(param.getProcessingStatus()), DriverAbnormalBehaviorAnalysis::getProcessingStatus, param.getProcessingStatus())
                .eq(Objects.nonNull(param.getOverseeStatus()), DriverAbnormalBehaviorAnalysis::getOverseeStatus, param.getOverseeStatus())
                .orderBy(Boolean.TRUE, Boolean.FALSE, DriverAbnormalBehaviorAnalysis::getAlarmTime);
    }

    public Boolean oversee(DriverAbnormalBehaviorAnalysisOverseeDTO param, Long userId) {
        return behaviourAnalysisService.oversee(param, userId);
    }

    public DriverAbnormalBehaviorAnalysisDetailVO getBehaviourAnalysisDetail(Long id) {

        LambdaQueryWrapper<DriverAbnormalBehaviorAnalysis> wrapper = Wrappers.lambdaQuery(DriverAbnormalBehaviorAnalysis.class);
        BehaviourAnalysisManage context = (BehaviourAnalysisManage) AopContext.currentProxy();
        context.buildQuery(wrapper, id);
        DriverAbnormalBehaviorAnalysis driverAbnormalBehaviorAnalysis = behaviourAnalysisService.getOne(wrapper);
        if (Objects.isNull(driverAbnormalBehaviorAnalysis)) {
            throw new BizException("异常行为不存在");
        }
        //DriverAbnormalBehaviorAnalysis driverAbnormalBehaviorAnalysis = behaviourAnalysisService.getById(id);
        DriverAbnormalBehaviorAnalysisDetailVO resVo = BeanUtil.copyProperties(driverAbnormalBehaviorAnalysis, DriverAbnormalBehaviorAnalysisDetailVO.class);
        Optional.ofNullable(driverAbnormalBehaviorAnalysis.getSpeed()).ifPresent(c -> resVo.setSpeed(BigDecimal.valueOf(c).multiply(TaskConstant.Math.SPEED_UNITS)
                .setScale(BigDecimal.ROUND_CEILING, RoundingMode.HALF_UP).intValue()));
        
        //统计该驾驶员当日异常行为告警事件
        //获取当前日期的起始时间和结束时间
        LocalDateTime startTime = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
        LocalDateTime endTime = NdDateUtils.endOfDay(LocalDateTime.now());

        LambdaQueryWrapper<DriverAbnormalBehaviorAnalysis> query = Wrappers.lambdaQuery(DriverAbnormalBehaviorAnalysis.class);
        query.eq(DriverAbnormalBehaviorAnalysis::getDriverId, driverAbnormalBehaviorAnalysis.getDriverId())
                .ge(DriverAbnormalBehaviorAnalysis::getAlarmTime, startTime)
                .le(DriverAbnormalBehaviorAnalysis::getAlarmTime, endTime)
                .orderByDesc(DriverAbnormalBehaviorAnalysis::getAlarmTime);
        List<DriverAbnormalBehaviorAnalysis> driverAbnormalBehaviorAnalysisList = behaviourAnalysisService.list(query);
        List<DriverDailyAlarmEvent> data = new ArrayList<>();
        for (DriverAbnormalBehaviorAnalysis abnormalBehaviorAnalysis : driverAbnormalBehaviorAnalysisList) {
            DriverDailyAlarmEvent driverDailyAlarmEvent = BeanUtil.copyProperties(abnormalBehaviorAnalysis, DriverDailyAlarmEvent.class);
            List<FileBasicInfo> fileBasicInfos = getFileBasicInfos(abnormalBehaviorAnalysis.getAlarmPictureAppendix(),
                    abnormalBehaviorAnalysis.getAlarmVideoAppendix());
            driverDailyAlarmEvent.setAlarmAppendix(fileBasicInfos);
            data.add(driverDailyAlarmEvent);
        }
        resVo.setAlarmEventList(data);
        return resVo;
    }
    @LambdaDataScope(type = LambdaDataScopeTypeEnum.ALL)
    public void buildQuery(LambdaQueryWrapper<DriverAbnormalBehaviorAnalysis> wrapper, Long id) {
        wrapper.eq(DriverAbnormalBehaviorAnalysis::getId,id);
    }

    public Boolean deal(DriverAbnormalBehaviorAnalysisNoticeDTO param, Long userId) {
        //根据异常行为数据ID查询驾驶员信息
        DriverAbnormalBehaviorAnalysis driverAbnormalBehaviorAnalysis = behaviourAnalysisService.getById(param.getId());
        String processingDescription = param.getProcessingDescription();
        String processingMode = param.getProcessingMode().toString();

        driverAbnormalBehaviorAnalysis.setProcessingDescription(processingDescription);
        driverAbnormalBehaviorAnalysis.setProcessingMode(processingMode);
        driverAbnormalBehaviorAnalysis.setProcessingStatus(DriverAbnormalBehaviorProcessingEnum.DEAL.getCode());
        driverAbnormalBehaviorAnalysis.setProcessingTime(LocalDateTime.now());
        driverAbnormalBehaviorAnalysis.setProcessingUser(LoginUserUtil.getUsername());
        driverAbnormalBehaviorAnalysis.setUpdateOn(LocalDateTime.now());
        driverAbnormalBehaviorAnalysis.setUpdateBy(userId);
        behaviourAnalysisService.updateById(driverAbnormalBehaviorAnalysis);
        return Boolean.TRUE;
    }

    public void driverAbnormalBehaviorAnalysisListExport(HttpServletResponse response, DriverAbnormalBehaviorAnalysisPageParamDTO param) {
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        PageVo<BehaviourAnalysisVO> page = behaviorAnalysisList(param);
        Collection<BehaviourAnalysisVO> records = page.getRecords();
        List<BehaviourAnalysisExportDTO> collect = records.stream().map(c -> {
            BehaviourAnalysisExportDTO exportDTO = BeanUtil.copyProperties(c, BehaviourAnalysisExportDTO.class);
            List<FileBasicInfo> alarmAppendix = c.getAlarmAppendix();
            for (FileBasicInfo fileBasicInfo : alarmAppendix) {
                if (DriverAbnormalBehaviorAppendixTypeEnum.PICTURE.getCode().equals(fileBasicInfo.getFileType())) {
                    exportDTO.setAlarmPictureAppendix(fileBasicInfo.getFilePath());
                } else {
                    exportDTO.setAlarmVideoAppendix(fileBasicInfo.getFilePath());
                }
            }
            return exportDTO;
        }).collect(Collectors.toList());
        String fileName = "驾驶员异常行为分析列表";
        ExcelDownUtil.setFileName(fileName, response);
        // 数据导出处理函数
        try {
            EasyExcel.write(response.getOutputStream(), BehaviourAnalysisExportDTO.class)
                    .autoCloseStream(false)
                    .registerWriteHandler(ExcelExportStyle.formalStyle())
                    .sheet(fileName)
                    .doWrite(collect);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public List<BehaviorAnalysisProcessingMode> processingModeDetail() {
        return behaviorAnalysisProcessingModeService.list();
    }

    public Boolean addProcessingMode(String req) {
        BehaviorAnalysisProcessingMode behaviorAnalysisProcessingMode = new BehaviorAnalysisProcessingMode();
        behaviorAnalysisProcessingMode.setProcessingModeName(req);
        behaviorAnalysisProcessingModeService.save(behaviorAnalysisProcessingMode);
        return Boolean.TRUE;
    }

    public Boolean deleteProcessingMode(Integer id) {
        behaviorAnalysisProcessingModeService.removeById(id);
        return Boolean.TRUE;
    }
}
