package com.ningdatech.carapi.sys.manage;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
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.google.common.collect.Lists;
import com.ningdatech.basic.exception.BaseUncheckedException;
import com.ningdatech.basic.exception.BizException;
import com.ningdatech.basic.model.PageVo;
import com.ningdatech.basic.util.CollUtils;
import com.ningdatech.basic.util.StrPool;
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.util.CodeUtil;
import com.ningdatech.carapi.company.entity.NdCompanyCreditLevel;
import com.ningdatech.carapi.company.enumeration.CompanyCreditLevelEnum;
import com.ningdatech.carapi.company.enumeration.CompanyTypeEnum;
import com.ningdatech.carapi.company.enumeration.ProductCompanyType;
import com.ningdatech.carapi.company.service.INdCompanyCreditLevelService;
import com.ningdatech.carapi.datascope.aop.LambdaDataScope;
import com.ningdatech.carapi.datascope.contants.LambdaDataScopeTypeEnum;
import com.ningdatech.carapi.driver.entity.DriverInfo;
import com.ningdatech.carapi.driver.service.IDriverInfoService;
import com.ningdatech.carapi.sys.entity.Company;
import com.ningdatech.carapi.sys.entity.CompanyType;
import com.ningdatech.carapi.sys.entity.CompanyTypeRelated;
import com.ningdatech.carapi.sys.entity.dto.*;
import com.ningdatech.carapi.sys.entity.vo.CompanyVO;
import com.ningdatech.carapi.sys.helper.CompaniesCacheHelper;
import com.ningdatech.carapi.sys.helper.RegionsCacheHelper;
import com.ningdatech.carapi.sys.service.CompanyService;
import com.ningdatech.carapi.sys.service.CompanyTypeRelatedService;
import com.ningdatech.carapi.sys.service.CompanyTypeService;
import com.ningdatech.carapi.user.entity.NdUserAuth;
import com.ningdatech.carapi.user.entity.NdUserInfo;
import com.ningdatech.carapi.user.service.INdUserAuthService;
import com.ningdatech.carapi.user.service.INdUserInfoService;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpStatus;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @Classname CompanyManage
 * @Description
 * @Date 2022/10/12 11:26
 * @Created by PoffyZhang
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class CompanyManage {

    private final CompanyService companyService;
    private final RegionsCacheHelper regionsCacheHelper;

    private final CompanyTypeService companyTypeService;
    private final CompanyTypeRelatedService companyTypeRelatedService;

    private final CompaniesCacheHelper companiesCacheHelper;
    private final IDriverInfoService driverInfoService;
    private final IVehicleBaseInfoService vehicleBaseInfoService;
    private final INdCompanyCreditLevelService companyCreditLevelService;
    private final INdUserInfoService userInfoService;
    private final INdUserAuthService userAuthService;

    /**
     * 公司列表查询
     * @param companyPageQuery
     * @return
     */
    public PageVo<CompanyVO> queryList(CompanyPageQuery companyPageQuery) {
        Integer pageNumber = companyPageQuery.getPageNumber();
        Integer pageSize = companyPageQuery.getPageSize();

        LambdaQueryWrapper<Company> wrapper = Wrappers.lambdaQuery(Company.class);
        // 未传入筛选条件时,筛选掉管理企业
        if (CollUtil.isEmpty(companyPageQuery.getCompanyTypeList())) {
            companyPageQuery.setCompanyTypeList(Lists.newArrayList(1, 2, 3));
        }
        ((CompanyManage)AopContext.currentProxy()).buildQueryWrapper(wrapper, companyPageQuery);

        // 获取所有符合传入条件的企业列表
        List<Company> companyList = companyService.list(wrapper);

        // 筛选出非管理企业的企业(根据传入的企业类型可筛选出生产企业、物流企业、其他企业)
        List<Long> companyIdList = companyList.stream().map(Company::getId).collect(Collectors.toList());

        Map<Long, List<NdCompanyCreditLevel>> listMap = companyCreditLevelService.list().stream()
                .filter(c -> companyIdList.contains(c.getCompanyId()))
                .collect(Collectors.groupingBy(NdCompanyCreditLevel::getCompanyId));

        Map<Long, List<CompanyTypeRelated>> companyTypeRelatedMap = companyTypeRelatedService.list().stream()
                .collect(Collectors.groupingBy(CompanyTypeRelated::getCompanyId));

        List<Company> dataList = Lists.newArrayList();
        Integer companyType = companyPageQuery.getCompanyType();
        Integer productCompanyType = companyPageQuery.getProductCompanyType();
        // 如果是生产企业列表具体生产企业类型的筛选
        if (CompanyTypeEnum.PRODUCT_BU.getCode().equals(companyType)
                && Objects.nonNull(productCompanyType)){
            // 关联表中筛选出对应类型的生产企业
            List<Long> relatedCompanyIds = companyTypeRelatedService.list(Wrappers.lambdaQuery(CompanyTypeRelated.class)
                            .in(CompanyTypeRelated::getCompanyId, companyIdList)
                            .eq(CompanyTypeRelated::getCompanyTypeId, productCompanyType))
                    .stream().map(CompanyTypeRelated::getCompanyId).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(relatedCompanyIds)) {
                dataList = companyList.stream()
                        .filter(c -> relatedCompanyIds.contains(c.getId()))
                        .collect(Collectors.toList());
            }
        }else {
            // 非生产企业类型的列表筛选，就根据企业类型返回对应的数据
            dataList = companyList;
        }

        List<CompanyVO> data = CollUtils.convert(dataList, c -> {
            CompanyVO vo = new CompanyVO();
            BeanUtils.copyProperties(c, vo);
            CodeUtil.searchRegionName(vo);
            // 根据企业ID获取企业信用等级
            Long companyId = c.getId();
            List<NdCompanyCreditLevel> creditLevelList = listMap.get(companyId);
            if (CollUtil.isNotEmpty(creditLevelList)) {
                // 过滤出当前时间年份的信用等级
                String year = String.valueOf(LocalDateTime.now().getYear());
                List<NdCompanyCreditLevel> levels =
                    creditLevelList.stream().filter(d -> year.equals(d.getYear())).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(levels)) {
                    NdCompanyCreditLevel creditLevel = levels.get(0);
                    vo.setDangerLevel(creditLevel.getLevel());
                    vo.setDangerLevelName(CompanyCreditLevelEnum.getDescByCode(creditLevel.getLevel()));
                }
            } else {
                log.info("该企业{}不在企业信用等级列表中", companyId);
                // 默认赋红码
                vo.setDangerLevel(CompanyCreditLevelEnum.E.getCode());
                vo.setDangerLevelName(CompanyCreditLevelEnum.E.getDesc());
            }

            // 如果是生产企业类型列表，要展示具体的生产企业类型
            if (Objects.nonNull(vo.getCompanyType())) {
                if (CompanyTypeEnum.PRODUCT_BU.getCode().equals(vo.getCompanyType())) {
                    List<CompanyTypeRelated> relatedList = companyTypeRelatedMap.get(vo.getId());
                    if (CollUtil.isNotEmpty(relatedList)) {
                        List<String> nameList = relatedList.stream()
                                .map(r -> ProductCompanyType.getDescByCode(r.getCompanyTypeId()))
                                .collect(Collectors.toList());
                        String typeName = nameList.stream().collect(Collectors.joining(StrPool.COMMA));
                        vo.setCompanyTypeName(typeName);
                    }
                } else {
                    vo.setCompanyTypeName(CompanyTypeEnum.getDescByCode(vo.getCompanyType()));
                }
            }
            return vo;
        });

        // 分页
        List<CompanyVO> vos = data.stream()
                .skip((long) (pageNumber - 1) * pageSize)
                .limit(pageSize).collect(Collectors.toList());

        return PageVo.of(vos, data.size());
    }

    /**
     * 查询详情
     * @param id
     * @return
     */
    public CompanyQueryDTO getDetails(Long id) {
        LambdaQueryWrapper<Company> wrapper = Wrappers.lambdaQuery(Company.class);
        CompanyManage context = (CompanyManage) AopContext.currentProxy();
        context.buildQuery(wrapper, id);
        Company company = companyService.getOne(wrapper);
        if (Objects.isNull(company)){
            return null;
        }
        //Company company = companyService.getById(id);

        CompanyQueryDTO query = BeanUtil.toBean(company, CompanyQueryDTO.class);
        query.setCompanyTypeName(CompanyTypeEnum.getDescByCode(company.getCompanyType()));
        //查询区域
        CodeUtil.searchRegionName(query);
        //查询企业类型
        List<CompanyTypeRelated> companyTypeRelateds = searchEnterpriseType(query.getId());
        if(CollUtil.isNotEmpty(companyTypeRelateds)){
            query.setEnterpriseTypes(companyTypeRelateds.stream().map(CompanyTypeRelated::getCompanyTypeId).collect(Collectors.toList()));
            query.setEnterpriseTypesName(companyTypeRelateds.stream().map(r -> {
                Long companyTypeId = r.getCompanyTypeId();
                CompanyType companyType = companyTypeService.getById(companyTypeId);
                return Objects.nonNull(companyType) ? companyType.getName() : StringUtils.EMPTY;
            }).filter(StringUtils::isNotBlank).collect(Collectors.joining(StrPool.COMMA)));
        }
        return query;
    }

    @LambdaDataScope(type = LambdaDataScopeTypeEnum.ONLY_REGION)
    public void buildQuery(LambdaQueryWrapper<Company> wrapper, Long id) {
        wrapper.eq(Company::getId,id);
    }

    /**
     * 查询 此企业的类型
     * @param companyId
     */
    public List<CompanyTypeRelated> searchEnterpriseType(Long companyId) {
        return companyTypeRelatedService.list(Wrappers.lambdaQuery(CompanyTypeRelated.class).eq(CompanyTypeRelated::getCompanyId, companyId));
    }

    /**
     * 企业类型
     * @return
     */
    public List<CascadeDTO> queryCompanyTypes() {
        List<CompanyType> companyTypes = companyTypeService.list();

        return buildCompanyChildren(companyTypes);
    }

    private List<CascadeDTO> buildCompanyChildren(List<CompanyType> companyTypes) {
        if(CollUtil.isEmpty(companyTypes)){
            return Collections.emptyList();
        }
        List<CascadeDTO> res = Lists.newArrayList();

        for(CompanyType companyType: companyTypes){
            // 获取生产企业的子菜单
            if(companyType.getPid().equals(Long.valueOf(CompanyTypeEnum.PRODUCT_BU.getCode()))){
                CascadeDTO cascade = CascadeDTO.of(companyType.getId(), companyType.getName(),null);
                res.add(cascade);
            }
        }

        return res;
    }


    /**
     * 处理地区
     * @param wrapper
     * @param companyPageQuery
     */
    @BuildChildrenRegionWrapper
    @LambdaDataScope(type = LambdaDataScopeTypeEnum.COMPANY_TABLE)
    public void buildQueryWrapper(LambdaQueryWrapper<Company> wrapper, CompanyPageQuery companyPageQuery) {
        wrapper.like(StringUtils.isNotBlank(companyPageQuery.getName()),Company::getName, companyPageQuery.getName())
                .eq(Objects.nonNull(companyPageQuery.getBlackList()),Company::getBlackList,companyPageQuery.getBlackList())
                // 根据传入的企业类型获取相对应的企业（信息管理列表要筛选掉管理企业）
                .in(CollUtil.isNotEmpty(companyPageQuery.getCompanyTypeList()),Company::getCompanyType,companyPageQuery.getCompanyTypeList())
                .eq(Objects.nonNull(companyPageQuery.getCompanyType()),Company::getCompanyType, companyPageQuery.getCompanyType())
                //// 区县、市散办审核通过的企业才展示
                //.eq(Company::getRegionAuditStatus, AuditStateEnum.AUDIT_SUCESS.getCode())
                //.eq(Company::getCityAuditStatus,AuditStateEnum.AUDIT_SUCESS.getCode())
                .orderBy(Boolean.TRUE,Boolean.TRUE,Company::getName);
    }

    /**
     * 使用企业列表查询
     * @param wrapper
     * @param companyPageQuery
     */
    public void buildUseQueryWrapper(LambdaQueryWrapper<Company> wrapper, CompanyPageQuery companyPageQuery) {
        wrapper.like(StringUtils.isNotBlank(companyPageQuery.getName()),Company::getName, companyPageQuery.getName())
                .eq(Objects.nonNull(companyPageQuery.getBlackList()),Company::getBlackList,companyPageQuery.getBlackList())
                // 根据传入的企业类型获取相对应的企业（信息管理列表要筛选掉管理企业）
                .in(CollUtil.isNotEmpty(companyPageQuery.getCompanyTypeList()),Company::getCompanyType,companyPageQuery.getCompanyTypeList())
                .eq(Objects.nonNull(companyPageQuery.getCompanyType()),Company::getCompanyType, companyPageQuery.getCompanyType())
                .orderBy(Boolean.TRUE,Boolean.TRUE,Company::getName);
    }

    /**
     * 获取企业ids 用区域ids
     * @param regionIds
     * @return
     */
    public List<Long> getIdsByRegionIds(List<Long> regionIds) {
        List<Long> regionArr = Lists.newArrayList();

        if (CollUtil.isEmpty(regionIds)) {
            return Collections.emptyList();
        }

        regionIds.stream().forEach(regionId -> {
            List<Long> regions = regionsCacheHelper.listChildRegionId(regionId);
            if (CollUtil.isNotEmpty(regions)) {
                regionArr.addAll(regions);
            }
        });

        LambdaQueryWrapper<Company> wrapper = Wrappers.lambdaQuery(Company.class);
        wrapper.in(Company::getRegionId, regionArr);
        List<Company> companies = companyService.list(wrapper);

        if (CollUtil.isEmpty(companies)) {
            return Collections.emptyList();
        }

        return companies.stream().map(Company::getId).collect(Collectors.toList());
    }

    public Company save(CompanySaveDTO data, Long userId) {
        Company company = companyService.save(data, userId);
        companiesCacheHelper.refresh(company.getId());
        return company;
    }

    public Company update(CompanyUpdateDTO data, Long userId) {
        Company old = companyService.getById(data.getId());
        if (Objects.isNull(old)) {
            throw new BaseUncheckedException(HttpStatus.HTTP_OK, String.format("修改企业｛｝ 不存在", data.getId()));
        }
        if (StringUtils.isNotBlank(data.getName())) {
            Assert.isFalse(companyService.check(data.getName(), old.getId()), "企业名{} 已经存在",
                    data.getName());
        }
        Company company = companyService.update(data, userId);
        companiesCacheHelper.refresh(company.getId());

        // 更新企业登录账号所关联的企业法人、法人手机号、登录账号(企业名称)等信息
        // 根据企业名称和企业ID获取原来企业信息员的用户信息
        NdUserInfo companyUserInfo = userInfoService.getOne(Wrappers.lambdaQuery(NdUserInfo.class)
                .eq(NdUserInfo::getCompanyId, old.getId())
                .eq(NdUserInfo::getUsername, old.getName()));
        if (Objects.nonNull(companyUserInfo)) {
            // 更新了企业名称、法人联系电话
            companyUserInfo.setUsername(data.getName());
            companyUserInfo.setMobile(data.getLegalPersonPhone());
            try {
                userInfoService.updateById(companyUserInfo);
            } catch (Exception e) {
                throw new BizException("该法人手机号绑定的用户已存在!");
            }
            // 更新登录账号为修改后的企业名称
            Long companyUserId = companyUserInfo.getId();
            NdUserAuth companyUserAuth = userAuthService.getOne(Wrappers.lambdaQuery(NdUserAuth.class)
                    .eq(NdUserAuth::getUserId, companyUserId));
            companyUserAuth.setIdentifier(companyUserInfo.getUsername());
            userAuthService.updateById(companyUserAuth);
        }

        List<Long> enterpriseTypes = data.getEnterpriseTypes();
        if (CollUtil.isNotEmpty(enterpriseTypes)){
            // 先删除原来关联的信息，再保存
            companyTypeRelatedService.remove(Wrappers.lambdaQuery(CompanyTypeRelated.class)
                    .eq(CompanyTypeRelated::getCompanyId,company.getId()));
            for (Long enterpriseType : enterpriseTypes) {
                CompanyTypeRelated companyTypeRelated = new CompanyTypeRelated();
                companyTypeRelated.setCompanyId(company.getId());
                companyTypeRelated.setCompanyTypeId(enterpriseType);
                companyTypeRelatedService.save(companyTypeRelated);
            }
        }

        // 查询出驾驶员档案中所属公司为该企业的所有驾驶员
        List<DriverInfo> driverInfoList = driverInfoService.list(Wrappers.lambdaQuery(DriverInfo.class)
                .eq(DriverInfo::getCompanyId, company.getId()));
        driverInfoList.forEach(driverInfo -> driverInfo.setRegionId(data.getRegionId()));
        // 更新驾驶员档案信息中所属公司为该企业的所属区域
        driverInfoService.updateBatchById(driverInfoList);
        // 查询出车辆档案信息中所属公司为该企业的所有车辆
        List<NdVehicleBaseInfo> ndVehicleBaseInfoList = vehicleBaseInfoService.list(Wrappers.lambdaQuery(NdVehicleBaseInfo.class)
                .eq(NdVehicleBaseInfo::getCompanyId, company.getId()));
        ndVehicleBaseInfoList.forEach(v -> {
            v.setRegionId(data.getRegionId());
            v.setRegionName(regionsCacheHelper.getDisplayName(data.getRegionId()));
        });
        // 更新车辆档案信息中所属公司为该企业的所属区域
        vehicleBaseInfoService.updateBatchById(ndVehicleBaseInfoList);
        return company;
    }

    public Boolean removeByIdWithCache(List<Long> ids) {
        List<Long> list = Lists.newArrayList();
        CompanyManage context = (CompanyManage) AopContext.currentProxy();
        for (Long id : ids) {
            LambdaQueryWrapper<Company> wrapper = Wrappers.lambdaQuery(Company.class);
            context.buildQuery(wrapper, id);
            Company company = companyService.getOne(wrapper);
            if (Objects.nonNull(company)) {
                list.add(company.getId());
            }
        }
        Boolean res = companyService.removeByIdWithCache(list);
        companiesCacheHelper.refresh(list);
        return res;
    }

    public PageVo<CompanyVO> queryUseCompanyList(CompanyPageQuery companyPageQuery) {
        Integer pageNumber = companyPageQuery.getPageNumber();
        Integer pageSize = companyPageQuery.getPageSize();

        LambdaQueryWrapper<Company> wrapper = Wrappers.lambdaQuery(Company.class);
        // 未传入筛选条件时,筛选掉管理企业
        if (CollUtil.isEmpty(companyPageQuery.getCompanyTypeList())) {
            companyPageQuery.setCompanyTypeList(Lists.newArrayList(1, 2, 3));
        }
        buildUseQueryWrapper(wrapper, companyPageQuery);

        // 获取所有符合传入条件的企业列表
        List<Company> companyList = companyService.list(wrapper);

        // 筛选出非管理企业的企业(根据传入的企业类型可筛选出生产企业、物流企业、其他企业)
        List<Long> companyIdList = companyList.stream().map(Company::getId).collect(Collectors.toList());

        Map<Long, List<NdCompanyCreditLevel>> listMap = companyCreditLevelService.list().stream()
                .filter(c -> companyIdList.contains(c.getCompanyId()))
                .collect(Collectors.groupingBy(NdCompanyCreditLevel::getCompanyId));

        Map<Long, List<CompanyTypeRelated>> companyTypeRelatedMap = companyTypeRelatedService.list().stream()
                .collect(Collectors.groupingBy(CompanyTypeRelated::getCompanyId));

        List<Company> dataList = Lists.newArrayList();
        Integer companyType = companyPageQuery.getCompanyType();
        Integer productCompanyType = companyPageQuery.getProductCompanyType();
        // 如果是生产企业列表具体生产企业类型的筛选
        if (CompanyTypeEnum.PRODUCT_BU.getCode().equals(companyType)
                && Objects.nonNull(productCompanyType)){
            // 关联表中筛选出对应类型的生产企业
            List<Long> relatedCompanyIds = companyTypeRelatedService.list(Wrappers.lambdaQuery(CompanyTypeRelated.class)
                            .in(CompanyTypeRelated::getCompanyId, companyIdList)
                            .eq(CompanyTypeRelated::getCompanyTypeId, productCompanyType))
                    .stream().map(CompanyTypeRelated::getCompanyId).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(relatedCompanyIds)) {
                dataList = companyList.stream()
                        .filter(c -> relatedCompanyIds.contains(c.getId()))
                        .collect(Collectors.toList());
            }
        }else {
            // 非生产企业类型的列表筛选，就根据企业类型返回对应的数据
            dataList = companyList;
        }

        List<CompanyVO> data = CollUtils.convert(dataList, c -> {
            CompanyVO vo = new CompanyVO();
            BeanUtils.copyProperties(c, vo);
            CodeUtil.searchRegionName(vo);
            // 根据企业ID获取企业信用等级
            Long companyId = c.getId();
            List<NdCompanyCreditLevel> creditLevelList = listMap.get(companyId);
            if (CollUtil.isNotEmpty(creditLevelList)) {
                // 过滤出当前时间年份的信用等级
                String year = String.valueOf(LocalDateTime.now().getYear());
                List<NdCompanyCreditLevel> levels =
                        creditLevelList.stream().filter(d -> year.equals(d.getYear())).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(levels)) {
                    NdCompanyCreditLevel creditLevel = levels.get(0);
                    vo.setDangerLevel(creditLevel.getLevel());
                    vo.setDangerLevelName(CompanyCreditLevelEnum.getDescByCode(creditLevel.getLevel()));
                }
            } else {
                log.info("该企业{}不在企业信用等级列表中", companyId);
                // 默认赋红码
                vo.setDangerLevel(CompanyCreditLevelEnum.E.getCode());
                vo.setDangerLevelName(CompanyCreditLevelEnum.E.getDesc());
            }

            // 如果是生产企业类型列表，要展示具体的生产企业类型
            if (Objects.nonNull(vo.getCompanyType())) {
                if (CompanyTypeEnum.PRODUCT_BU.getCode().equals(vo.getCompanyType())) {
                    List<CompanyTypeRelated> relatedList = companyTypeRelatedMap.get(vo.getId());
                    if (CollUtil.isNotEmpty(relatedList)) {
                        List<String> nameList = relatedList.stream()
                                .map(r -> ProductCompanyType.getDescByCode(r.getCompanyTypeId()))
                                .collect(Collectors.toList());
                        String typeName = nameList.stream().collect(Collectors.joining(StrPool.COMMA));
                        vo.setCompanyTypeName(typeName);
                    }
                } else {
                    vo.setCompanyTypeName(CompanyTypeEnum.getDescByCode(vo.getCompanyType()));
                }
            }
            return vo;
        });

        // 分页
        List<CompanyVO> vos = data.stream()
                .skip((long) (pageNumber - 1) * pageSize)
                .limit(pageSize).collect(Collectors.toList());

        return PageVo.of(vos, data.size());
    }
}
