package com.ningdatech.carapi.safe.manage;

import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

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

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.CollUtils;
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.MissCertEnum;
import com.ningdatech.carapi.common.constant.UserRoleTypeEnum;
import com.ningdatech.carapi.common.constant.ViolationTypeEnum;
import com.ningdatech.carapi.common.util.CodeUtil;
import com.ningdatech.carapi.safe.entity.NdVehicleViolation;
import com.ningdatech.carapi.safe.model.dto.ViolationPageQuery;
import com.ningdatech.carapi.safe.model.vo.NdVehicleViolationVO;
import com.ningdatech.carapi.safe.service.INdVehicleViolationService;
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 lombok.RequiredArgsConstructor;

/**
 * @author PoffyZhang
 * @date 2022/10/19 上午11:18
 */
@Component
@RequiredArgsConstructor
public class VehicleViolationManage {

    private final INdVehicleViolationService vehicleViolationService;
    private final OperatorsCacheHelper operatorsCacheHelper;
    private final IVehicleBaseInfoService vehicleBaseInfoService;

    public PageVo<NdVehicleViolationVO> query(ViolationPageQuery violationPageQuery) {
        Page<NdVehicleViolation> page = violationPageQuery.page();
        Integer pageNumber = violationPageQuery.getPageNumber();
        Integer pageSize = violationPageQuery.getPageSize();
        Integer violationType = violationPageQuery.getViolationType();

        // 按照登录用户，如果是运营商账号登录，删选出该运营商关联的车辆信息
        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<Long> companyIds = baseInfoList.stream()
                    .map(NdVehicleBaseInfo::getCompanyId)
                    .collect(Collectors.toList());
            List<String> carPlateList = baseInfoList.stream().map(NdVehicleBaseInfo::getCarPlate).collect(Collectors.toList());
            HashSet<Long> set = new HashSet<>();
            List<Long> companyIdList = companyIds.stream().filter(c -> set.add(c)).collect(Collectors.toList());
            // 若为无证驾驶列表，过滤掉不在这些企业下的数据,否则根据车牌号筛选
            if (ViolationTypeEnum.MISS_CERT.getCode().equals(violationPageQuery.getViolationType())) {
                violationPageQuery.setCompanyIds(companyIdList);
            }else {
                violationPageQuery.setCarPlateList(carPlateList);
            }
        }

        LambdaQueryWrapper<NdVehicleViolation> wrapper = Wrappers.lambdaQuery(NdVehicleViolation.class);
        List<NdVehicleViolation> violationList = ((VehicleViolationManage) AopContext.currentProxy()).commonSearch(page, wrapper, violationPageQuery);
        // 对结果进行去重,并统计对应违章次数
        List<NdVehicleViolation> data = removeDuplicate(violationList,violationType);
        if (CollUtil.isEmpty(data)){
            return PageVo.empty();
        }
        List<NdVehicleViolation> records = data.stream()
                .skip((long) (pageNumber - 1) * pageSize)
                .limit(pageSize)
                .collect(Collectors.toList());
        List<NdVehicleViolationVO> results = CollUtils.convert(records, e -> {
            NdVehicleViolationVO vo = new NdVehicleViolationVO();
            BeanUtils.copyProperties(e,vo);
            if(Objects.nonNull(vo.getViolationType())){
                vo.setViolationTypeName(ViolationTypeEnum.getDescByCode(vo.getViolationType()));
            }
            if(Objects.nonNull(vo.getMissingCertificateType())){
                vo.setMissingCertificateTypeName(MissCertEnum.getDescByCode(vo.getMissingCertificateType()));
            }
            CodeUtil.searchCompanyNameAndRegionName(vo);
            return vo;
        });
        return PageVo.of(results, records.size());
    }

    private List<NdVehicleViolation> removeDuplicate(List<NdVehicleViolation> violationList, Integer violationType) {
        List<NdVehicleViolation> data;
        switch (violationType) {
            // 无证驾驶
            case 1:
                HashSet<Object> missCertSet = new HashSet<>();
                data = violationList.stream().filter(v ->
                        missCertSet.add(v.getDriverName() + v.getCarPlate() +
                                v.getViolationDate() + v.getMissingCertificateType()))
                        .collect(Collectors.toList());
                break;
            // 闯红灯
            case 2:
                HashSet<Object> redLightSet = new HashSet<>();
                data = violationList.stream().filter(v ->
                                redLightSet.add(v.getDriverName() + v.getCarPlate() +
                                        v.getViolationDate() + v.getAddressRedLight()))
                        .collect(Collectors.toList());
                break;
            // 超载
            case 3:
                HashSet<Object> overLoadSet = new HashSet<>();
                data = violationList.stream().filter(v ->
                                overLoadSet.add(v.getDriverName() + v.getCarPlate() +
                                        v.getViolationTimes() + v.getViolationDate()))
                        .collect(Collectors.toList());
                countViolationTimes(data);
                break;
            // 闯禁行路段
            case 4:
                HashSet<Object> sectionSet = new HashSet<>();
                data = violationList.stream().filter(v ->
                                sectionSet.add(v.getDriverName() + v.getCarPlate() +
                                        v.getWaySection() + v.getViolationTimes() +
                                        v.getViolationDate()))
                        .collect(Collectors.toList());
                countViolationTimes(data);
                break;
            // 闯禁行时间
            case 5:
                HashSet<Object> periodSet = new HashSet<>();
                data = violationList.stream().filter(v ->
                                periodSet.add(v.getDriverName() + v.getCarPlate() +
                                        v.getViolationPeriod() + v.getViolationTimes()))
                        .collect(Collectors.toList());
                countViolationTimes(data);
                break;
            default:
                throw new IllegalStateException("Unexpected value: " + violationType);
        }
        return data;
    }

    private void countViolationTimes(List<NdVehicleViolation> data) {
        data.forEach(d -> {
            String carPlate = d.getCarPlate();
            if (StringUtils.isNotBlank(carPlate)) {
                List<NdVehicleViolation> violations = data.stream()
                        .filter(c -> carPlate.equals(c.getCarPlate()))
                        .collect(Collectors.toList());
                d.setViolationTimes(violations.size());
            }
        });
    }

    @BuildChildrenRegionWrapper(entityIndex = 2,wrapperIndex = 1)
    public List<NdVehicleViolation> commonSearch(Page<NdVehicleViolation> page,LambdaQueryWrapper<NdVehicleViolation> wrapper, ViolationPageQuery violationPageQuery) {
        wrapper.ge(Objects.nonNull(violationPageQuery.getStartTime()), NdVehicleViolation::getViolationDate, violationPageQuery.getStartTime())
                .le(Objects.nonNull(violationPageQuery.getEndTime()), NdVehicleViolation::getViolationDate, violationPageQuery.getEndTime())
                .like(Objects.nonNull(violationPageQuery.getDriverName()), NdVehicleViolation::getDriverName, violationPageQuery.getDriverName())
                .like(StringUtils.isNotBlank(violationPageQuery.getCompanyName()), NdVehicleViolation::getCompanyName, violationPageQuery.getCompanyName())
                .like(Objects.nonNull(violationPageQuery.getIdCard()), NdVehicleViolation::getIdCard, violationPageQuery.getIdCard())
                .like(Objects.nonNull(violationPageQuery.getCarPlate()), NdVehicleViolation::getCarPlate, violationPageQuery.getCarPlate())
                .eq(Objects.nonNull(violationPageQuery.getViolationType()), NdVehicleViolation::getViolationType, violationPageQuery.getViolationType())
                // 过滤掉不在这些运营商下车辆关联企业下的数据
                .in(CollUtil.isNotEmpty(violationPageQuery.getCompanyIds()),NdVehicleViolation::getCompanyId,violationPageQuery.getCompanyIds())
                .in(CollUtil.isNotEmpty(violationPageQuery.getCarPlateList()),NdVehicleViolation::getCarPlate,violationPageQuery.getCarPlateList())
                .orderBy(Boolean.TRUE, Boolean.FALSE, NdVehicleViolation::getViolationDate);

        return vehicleViolationService.pageDataScope(page, wrapper);
    }
}
