package com.ningdatech.carapi.industry.manage;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
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.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.constant.CommonConstant;
import com.ningdatech.carapi.common.constant.UserRoleTypeEnum;
import com.ningdatech.carapi.common.constant.VehicleStatusEnum;
import com.ningdatech.carapi.common.util.CodeUtil;
import com.ningdatech.carapi.common.util.ExcelDownUtil;
import com.ningdatech.carapi.common.util.ExcelExportStyle;
import com.ningdatech.carapi.industry.entity.DataQualityMonitorDynamics;
import com.ningdatech.carapi.industry.entity.DataQualityMonitorGps;
import com.ningdatech.carapi.industry.entity.DataQualityMonitorStatic;
import com.ningdatech.carapi.industry.enums.DataQualityMonitorGpsEnum;
import com.ningdatech.carapi.industry.model.dto.*;
import com.ningdatech.carapi.industry.model.vo.DataQualityMonitorDynamicsVO;
import com.ningdatech.carapi.industry.model.vo.DataQualityMonitorGpsVO;
import com.ningdatech.carapi.industry.model.vo.DataQualityMonitorStaticVO;
import com.ningdatech.carapi.industry.service.IDataQualityMonitorDynamicsService;
import com.ningdatech.carapi.industry.service.IDataQualityMonitorGpsService;
import com.ningdatech.carapi.industry.service.IDataQualityMonitorStaticService;
import com.ningdatech.carapi.sys.entity.dto.OperatorQueryDTO;
import com.ningdatech.carapi.sys.helper.OperatorsCacheHelper;
import com.ningdatech.carapi.sys.helper.RegionsCacheHelper;
import com.ningdatech.carapi.user.security.auth.model.UserInfoDetails;
import com.ningdatech.carapi.user.util.LoginUserUtil;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @Classname DataQualityMonitorManage
 * @Description
 * @Date 2022/11/07 17:57
 * @Created by PoffyZhang
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class DataQualityMonitorManage {

    private final IDataQualityMonitorStaticService dataQualityMonitorStaticService;
    private final IDataQualityMonitorDynamicsService dataQualityMonitorDynamicsService;
    private final IDataQualityMonitorGpsService dataQualityMonitorGpsService;

    private final RegionsCacheHelper regionsCacheHelper;
    private final OperatorsCacheHelper operatorsCacheHelper;
    private final IVehicleBaseInfoService vehicleBaseInfoService;

    public PageVo<DataQualityMonitorStaticVO> staticList(DataQualityMonitorStaticPageParamDTO param) {
        Page<DataQualityMonitorStatic> page = param.page();

        // 按照登录用户，如果是运营商账号登录，删选出该运营商关联的车辆信息
        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();
            // 查询出该运营商下所有车辆所在的所有企业
            List<Long> companyIds = vehicleBaseInfoService.list(Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
                            .eq(NdVehicleBaseInfo::getOperatorId, operatorId))
                    .stream().map(NdVehicleBaseInfo::getCompanyId).collect(Collectors.toList());
            HashSet<Long> set = new HashSet<>();
            List<Long> companyIdList = companyIds.stream().filter(c -> set.add(c)).collect(Collectors.toList());
            // 过滤掉不在这些企业下的数据
            param.setCompanyIds(companyIdList);
        }

        searchStatic(page,param);
        if(CollUtil.isEmpty(page.getRecords())){
            return PageVo.of(Collections.emptyList(), page.getTotal());
        }
        List<DataQualityMonitorStaticVO> data = page.getRecords().stream().map(w -> convertStatic(w)).collect(Collectors.toList());
        return PageVo.of(data, page.getTotal());
    }

    public DataQualityMonitorStaticVO staticDetails(Long id) {
        DataQualityMonitorStatic record = dataQualityMonitorStaticService.getById(id);

        return convertStatic(record);
    }

    public PageVo<DataQualityMonitorDynamicsVO> dynamicsList(DataQualityMonitorDynamicsPageParamDTO param) {
        Page<DataQualityMonitorDynamics> page = param.page();

        // 按照登录用户，如果是运营商账号登录，删选出该运营商关联的车辆信息
        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();
            // 查询出该运营商下所有车辆所在的所有企业
            List<NdVehicleBaseInfo> baseInfoList = vehicleBaseInfoService.list(Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
                    .eq(NdVehicleBaseInfo::getOperatorId, operatorId));
            List<String> carPlateList = baseInfoList.stream()
                    .map(NdVehicleBaseInfo::getCarPlate)
                    .collect(Collectors.toList());
            // 过滤掉不在这些企业下的数据
            param.setCarPlateList(carPlateList);
        }

        searchDynamics(page,param);
        if(CollUtil.isEmpty(page.getRecords())){
            return PageVo.of(Collections.emptyList(), page.getTotal());
        }
        List<DataQualityMonitorDynamicsVO> data = page.getRecords().stream().map(w -> convertDynamics(w)).collect(Collectors.toList());
        return PageVo.of(data, page.getTotal());
    }

    public DataQualityMonitorDynamicsVO dynamicsDetails(Long id) {
        DataQualityMonitorDynamics record = dataQualityMonitorDynamicsService.getById(id);

        return convertDynamics(record);
    }

    public PageVo<DataQualityMonitorGpsVO> gpsList(DataQualityMonitorGpsPageParamDTO param) {

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

        Page<DataQualityMonitorGps> page = param.page();
        LambdaQueryWrapper<DataQualityMonitorGps> wrapper = Wrappers.lambdaQuery(DataQualityMonitorGps.class);
        searchGps(page, param,wrapper);

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

        dataQualityMonitorGpsService.page(page, wrapper);
        if (CollUtil.isEmpty(page.getRecords())) {
            return PageVo.of(Collections.emptyList(), page.getTotal());
        }
        List<DataQualityMonitorGpsVO> data = page.getRecords().stream().map(this::convertGps).collect(Collectors.toList());
        return PageVo.of(data, page.getTotal());

    }

    public DataQualityMonitorGpsVO gpsDetails(Long id) {
        DataQualityMonitorGps record = dataQualityMonitorGpsService.getById(id);

        return convertGps(record);
    }

    /**
     * 查询
     * @param page
     * @param param
     */
    private void searchStatic(Page<DataQualityMonitorStatic> page, DataQualityMonitorStaticPageParamDTO param) {
        LambdaQueryWrapper<DataQualityMonitorStatic> wrapper = Wrappers.lambdaQuery(DataQualityMonitorStatic.class);
        wrapper.like(StringUtils.isNotBlank(param.getBatchNo()), DataQualityMonitorStatic::getBatchNo, param.getBatchNo())
                .like(Objects.nonNull(param.getState()), DataQualityMonitorStatic::getState, param.getState())
                .ge(Objects.nonNull(param.getStartTime()), DataQualityMonitorStatic::getDataTime, param.getStartTime())
                .le(Objects.nonNull(param.getEndTime()), DataQualityMonitorStatic::getDataTime, param.getEndTime())
                .in(CollUtil.isNotEmpty(param.getCompanyIds()),DataQualityMonitorStatic::getCompanyId,param.getCompanyIds())
                .orderBy(Boolean.TRUE,Boolean.FALSE, DataQualityMonitorStatic::getDataTime);
        dataQualityMonitorStaticService.page(page, wrapper);
    }

    private void searchDynamics(Page<DataQualityMonitorDynamics> page, DataQualityMonitorDynamicsPageParamDTO param) {
        LambdaQueryWrapper<DataQualityMonitorDynamics> wrapper = Wrappers.lambdaQuery(DataQualityMonitorDynamics.class);
        wrapper.like(StringUtils.isNotBlank(param.getCarPlate()), DataQualityMonitorDynamics::getCarPlate, param.getCarPlate())
                .like(Objects.nonNull(param.getState()), DataQualityMonitorDynamics::getState, param.getState())
                .ge(Objects.nonNull(param.getStartTime()), DataQualityMonitorDynamics::getDataTime, param.getStartTime())
                .le(Objects.nonNull(param.getEndTime()), DataQualityMonitorDynamics::getDataTime, param.getEndTime())
                .in(CollUtil.isNotEmpty(param.getCarPlateList()),DataQualityMonitorDynamics::getCarPlate,param.getCarPlateList())
                .orderBy(Boolean.TRUE,Boolean.FALSE, DataQualityMonitorDynamics::getDataTime);
        dataQualityMonitorDynamicsService.page(page, wrapper);
    }

    private void searchGps(Page<DataQualityMonitorGps> page, DataQualityMonitorGpsPageParamDTO param, LambdaQueryWrapper<DataQualityMonitorGps> wrapper) {
        if(Objects.nonNull(param.getRegionId())){
            List<Long> regionIds = regionsCacheHelper.listChildRegionId(param.getRegionId());
            wrapper.in(CollUtil.isNotEmpty(regionIds), DataQualityMonitorGps::getRegionId,regionIds);
        }
        wrapper.like(StringUtils.isNotBlank(param.getCompanyName()), DataQualityMonitorGps::getCompanyName, param.getCompanyName())
                .like(Objects.nonNull(param.getVehicleType()), DataQualityMonitorGps::getVehicleType, param.getVehicleType())
                .like(StringUtils.isNotBlank(param.getCarPlate()), DataQualityMonitorGps::getCarPlate, param.getCarPlate())
                .like(StringUtils.isNotBlank(param.getPlateColor()), DataQualityMonitorGps::getPlateColor, param.getPlateColor())
                .like(StringUtils.isNotBlank(param.getOperatorName()), DataQualityMonitorGps::getOperatorName, param.getOperatorName())
                .ge(Objects.nonNull(param.getStartTime()), DataQualityMonitorGps::getDataTime, param.getStartTime())
                .le(Objects.nonNull(param.getEndTime()), DataQualityMonitorGps::getDataTime, param.getEndTime())
                .orderBy(Boolean.TRUE,Boolean.FALSE, DataQualityMonitorGps::getDataTime);
    }

    private DataQualityMonitorStaticVO convertStatic(DataQualityMonitorStatic data) {
        return BeanUtil.copyProperties(data, DataQualityMonitorStaticVO.class);
    }

    private DataQualityMonitorDynamicsVO convertDynamics(DataQualityMonitorDynamics data) {
        if(Objects.isNull(data)){
            return null;
        }
        DataQualityMonitorDynamicsVO vo = BeanUtil.copyProperties(data, DataQualityMonitorDynamicsVO.class);
        CodeUtil.searchCompanyNameAndRegionName(vo);
        return vo;
    }

    private DataQualityMonitorGpsVO convertGps(DataQualityMonitorGps data) {
        if(Objects.isNull(data)){
            return null;
        }
        DataQualityMonitorGpsVO vo = BeanUtil.copyProperties(data, DataQualityMonitorGpsVO.class);
        vo.setAbnormalCausesName(DataQualityMonitorGpsEnum.getDescByCode(vo.getAbnormalCauses()));
        CodeUtil.searchCompanyNameAndRegionName(vo);
        return vo;
    }

    public void exportStatic(HttpServletResponse response, DataQualityMonitorStaticPageParamDTO param) {
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        PageVo<DataQualityMonitorStaticVO> page = staticList(param);
        List<DataQualityMonitorStaticVO> collect = page.getRecords().stream().map(w -> BeanUtil.copyProperties(w, DataQualityMonitorStaticVO.class)).collect(Collectors.toList());
        String fileName = "静态监控采集列表";
        ExcelDownUtil.setFileName(fileName, response);
        // 数据导出处理函数
        try {
            EasyExcel.write(response.getOutputStream(), DataQualityMonitorStaticExportDTO.class)
                    .autoCloseStream(false)
                    .registerWriteHandler(ExcelExportStyle.formalStyle())
                    .sheet(fileName)
                    .doWrite(collect);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void exportDynamics(HttpServletResponse response, DataQualityMonitorDynamicsPageParamDTO param) {
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        PageVo<DataQualityMonitorDynamicsVO> page = dynamicsList(param);
        List<DataQualityMonitorDynamicsVO> collect = page.getRecords().stream().map(w ->
                BeanUtil.copyProperties(w, DataQualityMonitorDynamicsVO.class)).collect(Collectors.toList());
        String fileName = "动态监控采集列表";
        ExcelDownUtil.setFileName(fileName, response);
        // 数据导出处理函数
        try {
            EasyExcel.write(response.getOutputStream(), DataQualityMonitorDynamicsExportDTO.class)
                    .autoCloseStream(false)
                    .registerWriteHandler(ExcelExportStyle.formalStyle())
                    .sheet(fileName)
                    .doWrite(collect);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void exportGps(HttpServletResponse response, DataQualityMonitorGpsPageParamDTO param) {
        param.page(CommonConstant.EXPORT_PAGE_NUMBER, CommonConstant.EXPORT_PAGE_SIZE);
        PageVo<DataQualityMonitorGpsVO> page = gpsList(param);
        List<DataQualityMonitorGpsExportDTO> collect = page.getRecords().stream().map(w -> {
            DataQualityMonitorGpsExportDTO gpsExportDTO = new DataQualityMonitorGpsExportDTO();
            BeanUtils.copyProperties(w,gpsExportDTO);
            String timeStr = NdDateUtils.format(w.getDataTime(), NdDateUtils.DEFAULT_DATE_TIME_FORMAT);
            gpsExportDTO.setDataTime(timeStr);
            gpsExportDTO.setState(VehicleStatusEnum.getDescByCode(w.getState()));
            return gpsExportDTO;
        }).collect(Collectors.toList());
        String fileName = "GPS监控采集列表";
        ExcelDownUtil.setFileName(fileName, response);
        // 数据导出处理函数
        try {
            EasyExcel.write(response.getOutputStream(), DataQualityMonitorGpsExportDTO.class)
                    .autoCloseStream(false)
                    .registerWriteHandler(ExcelExportStyle.formalStyle())
                    .sheet(fileName)
                    .doWrite(collect);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

}
