package com.qmth.sop.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qmth.sop.business.bean.dto.AreaDto;
import com.qmth.sop.business.bean.dto.DataPermissionDto;
import com.qmth.sop.business.bean.params.ServiceRegionParam;
import com.qmth.sop.business.bean.result.CrmServiceResult;
import com.qmth.sop.business.bean.result.ServiceRegionResult;
import com.qmth.sop.business.bean.result.SysUserBriefResult;
import com.qmth.sop.business.entity.*;
import com.qmth.sop.business.mapper.TBServiceRegionMapper;
import com.qmth.sop.business.service.*;
import com.qmth.sop.common.base.BaseEntity;
import com.qmth.sop.common.contant.SystemConstant;
import com.qmth.sop.common.enums.*;
import com.qmth.sop.common.util.ServletUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 服务区域规划表 服务实现类
 * </p>
 *
 * @author wangliang
 * @since 2023-08-01
 */
@Service
public class TBServiceRegionServiceImpl extends ServiceImpl<TBServiceRegionMapper, TBServiceRegion> implements TBServiceRegionService {
    @Resource
    private TBServiceService tbServiceService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private TBServiceRegionDetailService tbServiceRegionDetailService;
    @Resource
    private TBCrmService tbCrmService;
    @Resource
    private SysUserRoleService sysUserRoleService;
    @Resource
    private TBUserArchivesAllocationService tbUserArchivesAllocationService;
    @Resource
    private TBUserArchivesService tbUserArchivesService;

    @Override
    public IPage<ServiceRegionResult> findServiceRegionPage(Long serviceUnitId, String regionName, Long leadId, String city, Integer pageNumber, Integer pageSize) {
        if (regionName != null && regionName.length() > 0) {
            regionName = SystemConstant.translateSpecificSign(regionName);
        }
        if (city != null && city.length() > 0) {
            city = SystemConstant.translateSpecificSign(city);
        }
        SysUser requestUser = (SysUser) ServletUtil.getRequestUser();
        DataPermissionDto dpr = sysUserService.buildUserDataPermission(requestUser.getId());

        IPage<ServiceRegionResult> page = this.baseMapper.findServiceRegionPage(new Page<>(pageNumber, pageSize), serviceUnitId, regionName, leadId, city, ServiceStatusEnum.CANCEL, dpr);
        List<ServiceRegionResult> records = page.getRecords();
        if (records.size() > 0) {
            // 涉及的服务单元id集合
            List<Long> serviceUnitIdList = records.stream().map(ServiceRegionResult::getServiceUnitId).distinct().collect(Collectors.toList());

            // 派单
            List<CrmServiceResult> crmServiceResultList = tbCrmService.findCrmOrderByServiceIdList(serviceUnitIdList);
            // 规划位置
            List<Long> serviceRegionIdList = records.stream().map(ServiceRegionResult::getServiceRegionId).distinct().collect(Collectors.toList());
            List<TBServiceRegionDetail> tbServiceRegionDetailList = tbServiceRegionDetailService.list(new QueryWrapper<TBServiceRegionDetail>().lambda().in(TBServiceRegionDetail::getServiceRegionId, serviceRegionIdList));

            for (ServiceRegionResult record : records) {
                Long unitId = record.getServiceUnitId();
                Long regionId = record.getServiceRegionId();

                List<TBServiceRegionDetail> detailList = tbServiceRegionDetailList
                        .stream()
                        .filter(e -> regionId.equals(e.getServiceRegionId()))
                        .collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(detailList)) {
                    int orderCount = 0;
                    StringBuilder regionInfo = new StringBuilder();
                    for (TBServiceRegionDetail detail : detailList) {
                        String detailProvince = detail.getProvince();
                        String detailCity = detail.getCity();
                        String regionInfoCell = detailProvince + detailCity;

                        List<CrmServiceResult> crmList = crmServiceResultList.stream()
                                .filter(e -> unitId.equals(e.getServiceUnitId())
                                        && detailProvince.equals(e.getProvince())
                                        && detailCity.equals(e.getCity()))
                                .collect(Collectors.toList());
                        int count = crmList.size();
                        regionInfoCell = regionInfoCell + "(" + count + ")";
                        orderCount = orderCount + count;
                        regionInfo.append(regionInfoCell).append("、");
                    }
                    if (regionInfo.length() > 0) {
                        regionInfo = new StringBuilder(regionInfo.substring(0, regionInfo.length() - 1));
                    }
                    record.setOrderCount(orderCount);
                    record.setRegionInfo(regionInfo.toString());
                }

                List<AreaDto> areaDtoList = detailList.stream().flatMap(e -> {
                    AreaDto areaDto = new AreaDto();
                    areaDto.setCountry(e.getCountry());
                    areaDto.setProvince(e.getProvince());
                    areaDto.setCity(e.getCity());
                    areaDto.setArea(e.getArea());
                    areaDto.setAddress(e.getAddress());
                    return Stream.of(areaDto);
                }).collect(Collectors.toList());
                record.setAreaDtoList(areaDtoList);
            }
        }
        return page;
    }

    @Transactional
    @Override
    public Long editServiceRegion(ServiceRegionParam serviceRegionParam) {
        final String sign = "-";

        Long serviceRegionId = serviceRegionParam.getServiceRegionId();
        Long serviceUnitId = serviceRegionParam.getServiceUnitId();
        String regionName = serviceRegionParam.getRegionName();
        Long leadId = serviceRegionParam.getLeadId();
        List<AreaDto> areaDtoList = serviceRegionParam.getAreaDtoList();
        List<String> areaStrList = areaDtoList.stream().flatMap(e -> {
            String areaStr = e.getProvince() + sign + e.getCity();
            return Stream.of(areaStr);
        }).collect(Collectors.toList());

        TBService tbServiceUnit = tbServiceService.getById(serviceUnitId);
        if (Objects.isNull(tbServiceUnit)) {
            throw ExceptionResultEnum.ERROR.exception("服务单元不存在");
        }

        List<TBServiceRegion> regionUnCheckList = this.list(new QueryWrapper<TBServiceRegion>()
                .lambda()
                .eq(TBServiceRegion::getServiceId, serviceUnitId)
                .eq(TBServiceRegion::getRegionName, regionName));
        if (CollectionUtils.isNotEmpty(regionUnCheckList)) {
            if (regionUnCheckList.size() > 1) {
                throw ExceptionResultEnum.ERROR.exception("大区规划信息异常: 同一个服务单元下存在相同的大区名称");
            } else {
                TBServiceRegion regionCheck = regionUnCheckList.get(0);
                if (!Objects.equals(regionCheck.getId(), serviceRegionParam.getServiceRegionId())) {
                    throw ExceptionResultEnum.ERROR.exception(String.format("该服务单元已存在大区名称[%s]", regionCheck.getRegionName()));
                }
            }
        }

        SysUser leader = sysUserService.getById(leadId);
        if (Objects.isNull(leader)) {
            throw ExceptionResultEnum.ERROR.exception("大区经理不存在");
        }
        if (!sysUserRoleService.userContainsRoles(leadId, RoleTypeEnum.REGION_MANAGER)) {
            throw ExceptionResultEnum.ERROR.exception("所选用户没有大区经理角色");
        }

        TBServiceRegion tbServiceRegion = new TBServiceRegion();
        tbServiceRegion.setServiceId(serviceUnitId);
        tbServiceRegion.setLeadId(leadId);
        tbServiceRegion.setRegionName(regionName);

        // 更新区域规划信息
        if (Objects.isNull(serviceRegionId)) {
            // 新增
            tbServiceRegion.setEnable(true);
            this.save(tbServiceRegion);
            serviceRegionId = tbServiceRegion.getId();
        } else {
            // 修改大区判断1 - 修改大区经理
            TBServiceRegion dbServiceRegion = this.getById(serviceRegionId);
            if (!Objects.equals(leadId, dbServiceRegion.getLeadId())) {
                List<TBCrm> alreadyPublished = tbCrmService.list(new QueryWrapper<TBCrm>().lambda()
                        .eq(TBCrm::getEnable, true)
                        .ne(TBCrm::getStatus, CrmStatusEnum.UN_PUBLISH));
                if (alreadyPublished.size() > 0) {
                    String s = alreadyPublished.stream().map(e -> e.getCrmNo() + "(" + e.getName() + ")").collect(Collectors.joining(","));
                    throw ExceptionResultEnum.ERROR.exception(String.format("该大区规划中存在已经发布或已完结的派单[%s],不能修改大区经理", s));
                }
            }


            // 编辑
            List<TBServiceRegionDetail> tbServiceRegionDetailList = tbServiceRegionDetailService
                    .list(new QueryWrapper<TBServiceRegionDetail>()
                            .lambda()
                            .eq(TBServiceRegionDetail::getServiceRegionId, serviceRegionId));

            // 将要删除的服务区域规划
            List<Long> willDeleteRegionDetailIdList = tbServiceRegionDetailList.stream().filter(e -> {
                        String key = e.getProvince() + sign + e.getCity();
                        return !areaStrList.contains(key);
                    }).map(TBServiceRegionDetail::getId)
                    .distinct()
                    .collect(Collectors.toList());


            // 清空之前派单绑定的资源信息
            if (CollectionUtils.isNotEmpty(willDeleteRegionDetailIdList)) {
                List<TBCrm> willDisposeCrmList = tbCrmService.list(new QueryWrapper<TBCrm>().lambda().in(TBCrm::getRegionDetailId, willDeleteRegionDetailIdList));

                for (TBCrm tbCrm : willDisposeCrmList) {
                    // 修改大区判断2 - 修改大区区域
                    if (!CrmStatusEnum.UN_PUBLISH.equals(tbCrm.getStatus())) {
                        throw ExceptionResultEnum.ERROR.exception("该大区规划中存在已经发布或已完结的派单[" + tbCrm.getCrmNo() + "(" + tbCrm.getName() + ")" + "]不能修改区域");
                    }
                    // 之前派单有划定在服务单元 -> 解绑派单所有资源信息
                    List<TBUserArchivesAllocation> dbAllocationList = tbUserArchivesAllocationService.list(new QueryWrapper<TBUserArchivesAllocation>().lambda()
                            .eq(TBUserArchivesAllocation::getCrmNo, tbCrm.getCrmNo())
                            .eq(TBUserArchivesAllocation::getServiceId, tbCrm.getServiceId()));

                    if (CollectionUtils.isNotEmpty(dbAllocationList)) {
                        // 释放工程师资源
                        List<Long> archivesIdList = dbAllocationList.stream().map(TBUserArchivesAllocation::getArchivesId).distinct().collect(Collectors.toList());
                        if (CollectionUtils.isNotEmpty(archivesIdList)) {
                            UpdateWrapper<TBUserArchives> archivesUpdateWrapper = new UpdateWrapper<>();
                            archivesUpdateWrapper.lambda()
                                    .in(TBUserArchives::getId, archivesIdList)
                                    .set(TBUserArchives::getStatus, UserArchivesStatusEnum.FREE);
                            tbUserArchivesService.update(archivesUpdateWrapper);
                        }
                        // 删除之前的派单分配详情
                        tbUserArchivesAllocationService.removeByIds(dbAllocationList.stream().map(TBUserArchivesAllocation::getId).distinct().collect(Collectors.toList()));
                    }
                }

                UpdateWrapper<TBCrm> crmUpdateWrapper = new UpdateWrapper<>();
                crmUpdateWrapper.lambda()
                        .in(TBCrm::getRegionDetailId, willDeleteRegionDetailIdList)
                        .set(TBCrm::getRegionCoordinatorId, null)
                        .set(TBCrm::getRegionId, null)
                        .set(TBCrm::getRegionDetailId, null)
                        .set(TBCrm::getLeadId, null);
                tbCrmService.update(crmUpdateWrapper);
            }
            tbServiceRegion.setId(serviceRegionId);
            this.updateById(tbServiceRegion);
        }

        // 同一个服务单元
        List<Long> regionIdList = this.list(new QueryWrapper<TBServiceRegion>()
                        .lambda()
                        .eq(TBServiceRegion::getServiceId, serviceUnitId))
                .stream()
                .map(BaseEntity::getId)
                .collect(Collectors.toList());
        regionIdList.remove(serviceRegionId);
        if (CollectionUtils.isNotEmpty(regionIdList)) {
            List<TBServiceRegionDetail> detailList = tbServiceRegionDetailService.list(new QueryWrapper<TBServiceRegionDetail>()
                    .lambda()
                    .in(TBServiceRegionDetail::getServiceRegionId, regionIdList));
            for (AreaDto areaDto : areaDtoList) {
                if (detailList.stream().anyMatch(e -> e.getCity().equals(areaDto.getCity()) && e.getProvince().equals(areaDto.getProvince()))) {
                    throw ExceptionResultEnum.ERROR.exception(String.format("服务单元[%s]已经存在[%s]省，[%s]市的区域规划", tbServiceUnit.getName(), areaDto.getProvince(), areaDto.getCity()));
                }
            }

        }

        // 更新详细信息
        tbServiceRegionDetailService.bindServiceRegionAreas(serviceRegionId, areaDtoList);
        return serviceRegionId;
    }

    @Transactional
    @Override
    public void removeServiceRegion(List<Long> serviceRegionIdList) {
        for (Long serviceRegionId : serviceRegionIdList) {
            // 物理删除
            TBServiceRegion tbServiceRegion = this.getById(serviceRegionId);
            if (Objects.isNull(tbServiceRegion)) {
                throw ExceptionResultEnum.ERROR.exception("服务区域规划不存在");
            }

            // 删除派单规划详情
            List<Long> willDeleteRegionDetailIdList = tbServiceRegionDetailService.list(new QueryWrapper<TBServiceRegionDetail>()
                            .lambda()
                            .eq(TBServiceRegionDetail::getServiceRegionId, tbServiceRegion.getId()))
                    .stream()
                    .map(TBServiceRegionDetail::getId)
                    .distinct()
                    .collect(Collectors.toList());

            // 清空之前派单绑定的资源信息
            if (CollectionUtils.isNotEmpty(willDeleteRegionDetailIdList)) {
                List<TBCrm> willDisposeCrmList = tbCrmService.list(new QueryWrapper<TBCrm>().lambda().in(TBCrm::getRegionDetailId, willDeleteRegionDetailIdList));

                for (TBCrm tbCrm : willDisposeCrmList) {
                    if (!CrmStatusEnum.UN_PUBLISH.equals(tbCrm.getStatus())) {
                        throw ExceptionResultEnum.ERROR.exception("该大区规划中存在已经发布的派单[" + tbCrm.getCrmNo() + "(" + tbCrm.getName() + ")" + "]不能修改区域");
                    }
                    // 之前派单有划定在服务单元 -> 解绑派单所有资源信息
                    List<TBUserArchivesAllocation> dbAllocationList = tbUserArchivesAllocationService.list(new QueryWrapper<TBUserArchivesAllocation>().lambda()
                            .eq(TBUserArchivesAllocation::getCrmNo, tbCrm.getCrmNo())
                            .eq(TBUserArchivesAllocation::getServiceId, tbCrm.getServiceId()));

                    if (CollectionUtils.isNotEmpty(dbAllocationList)) {
                        // 释放工程师资源
                        List<Long> archivesIdList = dbAllocationList.stream().map(TBUserArchivesAllocation::getArchivesId).distinct().collect(Collectors.toList());
                        if (CollectionUtils.isNotEmpty(archivesIdList)) {
                            UpdateWrapper<TBUserArchives> archivesUpdateWrapper = new UpdateWrapper<>();
                            archivesUpdateWrapper.lambda()
                                    .in(TBUserArchives::getId, archivesIdList)
                                    .set(TBUserArchives::getStatus, UserArchivesStatusEnum.FREE);
                            tbUserArchivesService.update(archivesUpdateWrapper);
                        }
                        // 删除之前的派单分配详情
                        tbUserArchivesAllocationService.removeByIds(dbAllocationList.stream().map(TBUserArchivesAllocation::getId).distinct().collect(Collectors.toList()));
                    }
                }

                UpdateWrapper<TBCrm> crmUpdateWrapper = new UpdateWrapper<>();
                crmUpdateWrapper.lambda()
                        .in(TBCrm::getRegionDetailId, willDeleteRegionDetailIdList)
                        .set(TBCrm::getRegionCoordinatorId, null)
                        .set(TBCrm::getRegionId, null)
                        .set(TBCrm::getRegionDetailId, null)
                        .set(TBCrm::getLeadId, null);
                tbCrmService.update(crmUpdateWrapper);
            }

            // 删除派单规划
            tbServiceRegionDetailService.removeByIds(willDeleteRegionDetailIdList);
            this.removeById(tbServiceRegion);
        }
    }

    @Override
    public List<SysUserBriefResult> findCanChooseLeader(Long serviceUnitId) {
        List<SysUserBriefResult> regionLeaderList = sysUserService.findUserListByRoleType(RoleTypeEnum.REGION_MANAGER);
        List<Long> cantChooseLeader = this.list(new QueryWrapper<TBServiceRegion>()
                        .lambda()
                        .eq(TBServiceRegion::getServiceId, serviceUnitId)
                        .eq(TBServiceRegion::getEnable, true))
                .stream()
                .map(TBServiceRegion::getLeadId)
                .distinct()
                .collect(Collectors.toList());

        return regionLeaderList.stream().filter(e -> !cantChooseLeader.contains(e.getId())).collect(Collectors.toList());
    }
}
