package com.yuchen.saas.park.service.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuchen.saas.park.api.entity.park.FireFacilityEntity;
import com.yuchen.saas.park.api.entity.park.FireFacilityPartEntity;
import com.yuchen.saas.park.api.entity.park.FireInspectFacilityRelEntity;
import com.yuchen.saas.park.api.entity.park.PmgBatParkInfo;
import com.yuchen.saas.park.api.request.FireFacilityAddRequest;
import com.yuchen.saas.park.api.request.FireFacilityDeleteRequest;
import com.yuchen.saas.park.api.request.FireFacilityQueryRequest;
import com.yuchen.saas.park.api.request.FireFacilityUpdateRequest;
import com.yuchen.saas.park.api.response.FireFacilityPartResponse;
import com.yuchen.saas.park.api.response.FireFacilityResponse;
import com.yuchen.saas.park.service.mapper.FireFacilityMapper;
import com.yuchen.saas.park.service.service.FireFacilityPartService;
import com.yuchen.saas.park.service.service.FireFacilityService;
import com.yuchen.saas.park.service.service.FireInspectFacilityRelService;
import com.yuchen.saas.park.service.service.PmgBatParkInfoService;
import org.apache.commons.collections4.CollectionUtils;
import org.nest.springwrap.core.log.exception.ServiceException;
import org.nest.springwrap.core.mp.base.BaseServiceImpl;
import org.nest.springwrap.core.mp.support.Condition;
import org.nest.springwrap.core.mp.support.Query;
import org.nest.springwrap.core.secure.ContextUser;
import org.nest.springwrap.core.secure.utils.AuthUtil;
import org.nest.springwrap.core.tool.api.R;
import org.nest.springwrap.core.tool.utils.Func;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName FireFacilityServiceImpl
 * @Description 消防设施服务实现类
 * @Author 肖祥
 * @Date 2022/10/18 14:52
 * @Version 1.0。0
 **/
@Service
public class FireFacilityServiceImpl extends BaseServiceImpl<FireFacilityMapper, FireFacilityEntity>
        implements FireFacilityService {
    @Resource
    private PmgBatParkInfoService pmgBatParkInfoService;

    @Resource
    private FireFacilityPartService fireFacilityPartService;

    @Resource
    private FireInspectFacilityRelService fireInspectFacilityRelService;


    /**
     * @Description 新增消防设施请求类
     * @author 肖祥
     * @date  2022/10/18 17:42
     * @param fireFacilityAddRequest:
     * @return org.nest.springwrap.core.tool.api.R
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R add(FireFacilityAddRequest fireFacilityAddRequest) {
        //校验
        LambdaQueryWrapper<FireFacilityEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(FireFacilityEntity::getName,fireFacilityAddRequest.getName());
        FireFacilityEntity fireFacility = baseMapper.selectOne(queryWrapper);
        if(fireFacility != null){
            throw new ServiceException("设施重复:"+fireFacility.getName());
        }
        //检查部件是否重复定义map
        Map<String,String> map = new HashMap<>(fireFacilityAddRequest.getFacilityPartAddRequestList().size());
        fireFacilityAddRequest.getFacilityPartAddRequestList().forEach(facilityAddRequest->{
            if(map.get(facilityAddRequest.getPartName()) != null){
                throw new ServiceException("部件重复:"+facilityAddRequest.getPartName());
            }
            map.put(facilityAddRequest.getPartName(),facilityAddRequest.getInspectStandard());
        });

        //新增设施
        FireFacilityEntity fireFacilityEntity = new FireFacilityEntity();
        fireFacilityEntity.setParkId(fireFacilityAddRequest.getParkId());
        fireFacilityEntity.setName(fireFacilityAddRequest.getName());
        Boolean addFacility = save(fireFacilityEntity);

        //新增设施部件
        List<FireFacilityPartEntity> facilityPartEntityList = new ArrayList<>();
        fireFacilityAddRequest.getFacilityPartAddRequestList().forEach(facilityAddRequest->{
            FireFacilityPartEntity facilityPart = new FireFacilityPartEntity();
            facilityPart.setParkId(fireFacilityAddRequest.getParkId());
            facilityPart.setFacilityId(fireFacilityEntity.getId());
            facilityPart.setName(facilityAddRequest.getPartName());
            facilityPart.setInspectStandard(facilityAddRequest.getInspectStandard());
            facilityPartEntityList.add(facilityPart);
        });
       boolean  addPart = fireFacilityPartService.saveBatch(facilityPartEntityList);
       if(!addFacility || addPart == false){
           throw new ServiceException("新增消防设施失败");
       }
        return R.success("操作成功");
    }

    @Override
    public R<IPage<FireFacilityResponse>> page(FireFacilityQueryRequest queryRequest) {
        ContextUser contextUser = AuthUtil.getUser();
        if (Func.isEmpty(contextUser)){
            return R.data(Condition.getPage(queryRequest));
        }
        List<PmgBatParkInfo> pmgBatParkInfoList = pmgBatParkInfoService.getAllParkV1(null,contextUser.getIsAdmin(), contextUser.getDeptId(), contextUser.getTenantId(), contextUser.getOrgUserId());
        if (Func.isEmpty(pmgBatParkInfoList)){
            return R.data(Condition.getPage(queryRequest));
        }
        if (Func.isNotBlank(queryRequest.getParkName())){
            pmgBatParkInfoList=pmgBatParkInfoList.stream().filter(e->e.getParkName().contains(queryRequest.getParkName())).collect(Collectors.toList());
        }
        Query query = new Query();
        query.setCurrent(queryRequest.getCurrent());
        query.setSize(queryRequest.getSize());
        LambdaQueryWrapper<FireFacilityEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(Func.isNotBlank(queryRequest.getName()),FireFacilityEntity::getName,queryRequest.getName());
        lambdaQueryWrapper.in(FireFacilityEntity::getParkId,pmgBatParkInfoList.stream().map(PmgBatParkInfo::getId).collect(Collectors.toList()));
        lambdaQueryWrapper.eq(Func.isNotEmpty(queryRequest.getParkId()),FireFacilityEntity::getParkId,queryRequest.getParkId());
        lambdaQueryWrapper.orderByDesc(FireFacilityEntity::getCreateTime);
        IPage<FireFacilityEntity> iPage = this.page(Condition.getPage(query),lambdaQueryWrapper);

        //组装返回response
        IPage<FireFacilityResponse> pageVo = new Page(iPage.getCurrent(), iPage.getSize(), iPage.getTotal());
        List<FireFacilityResponse> records = this.listVO(iPage.getRecords());
        pageVo.setRecords(records);
        return R.data(pageVo);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Boolean> delete(FireFacilityDeleteRequest fireFacilityDeleteRequest) {
        Integer count = fireInspectFacilityRelService.lambdaQuery().eq(FireInspectFacilityRelEntity::getFacilityId, fireFacilityDeleteRequest.getId()).count();
        if (count>0){
            throw new ServiceException("当前设施有绑定控制点，无法删除");
        }
        //删除
        LambdaUpdateWrapper<FireFacilityEntity> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(FireFacilityEntity::getIsDeleted,1);
        wrapper.eq(FireFacilityEntity::getId,fireFacilityDeleteRequest.getId());
        Boolean fireFacility = update(new FireFacilityEntity(),wrapper);

        List<FireFacilityPartEntity> list = fireFacilityPartService.lambdaQuery()
                .eq(FireFacilityPartEntity::getFacilityId,fireFacilityDeleteRequest.getId())
                .list();
        List<Long> ids = new ArrayList<>();
        boolean fireFacilityPart = false;
        if(CollectionUtils.isNotEmpty(list)){
            for (FireFacilityPartEntity facilityPart : list) {
                ids.add(facilityPart.getId());
            }
            fireFacilityPart =  fireFacilityPartService.deleteLogic(ids);
        }
        if(!fireFacility || !fireFacilityPart){
            throw new ServiceException("删除消防设施失败");
        }
        return R.success("操作成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Boolean> update(FireFacilityUpdateRequest fireFacilityUpdateRequest) {

        //更新
        LambdaUpdateWrapper<FireFacilityEntity> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(FireFacilityEntity::getName,fireFacilityUpdateRequest.getName());
        wrapper.set(FireFacilityEntity::getParkId,fireFacilityUpdateRequest.getParkId());
        wrapper.eq(FireFacilityEntity::getId,fireFacilityUpdateRequest.getId());
        boolean fireFacility = update(new FireFacilityEntity(),wrapper);
        //删除部件
        List<FireFacilityPartEntity> list = fireFacilityPartService.lambdaQuery()
                .eq(FireFacilityPartEntity::getFacilityId,fireFacilityUpdateRequest.getId())
                .list();
        List<Long> ids = new ArrayList<>();
        boolean fireFacilityPart = false;
        if(CollectionUtils.isNotEmpty(list)){
            for (FireFacilityPartEntity facilityPart : list) {
                ids.add(facilityPart.getId());
            }

        }
        //新增设施部件
        List<FireFacilityPartEntity> facilityPartEntityList = new ArrayList<>();
        fireFacilityUpdateRequest.getFacilityPartUpdateRequestList().forEach(facilityUpdateRequest->{
            FireFacilityPartEntity facilityPart = new FireFacilityPartEntity();
            facilityPart.setParkId(fireFacilityUpdateRequest.getParkId());
            if (CollectionUtils.isNotEmpty(ids)){
                if (ids.contains(facilityUpdateRequest.getId())){
                    facilityPart.setId(facilityUpdateRequest.getId());
                }
            }
            facilityPart.setFacilityId(fireFacilityUpdateRequest.getId());
            facilityPart.setName(facilityUpdateRequest.getPartName());
            facilityPart.setInspectStandard(facilityUpdateRequest.getInspectStandard());
            facilityPartEntityList.add(facilityPart);
        });
        boolean  addPart = fireFacilityPartService.saveOrUpdateBatch(facilityPartEntityList,facilityPartEntityList.size());
        List<FireFacilityPartEntity> newList = fireFacilityPartService.lambdaQuery()
                .eq(FireFacilityPartEntity::getFacilityId,fireFacilityUpdateRequest.getId())
                .list();

        if (CollectionUtils.isNotEmpty(newList)){
            List<Long> newIds = facilityPartEntityList.stream().map(FireFacilityPartEntity::getId).collect(Collectors.toList());
            List<Long> deleteIds = newList.stream().map(FireFacilityPartEntity::getId).filter(e -> !newIds.contains(e)).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(deleteIds)){
                Integer count = fireInspectFacilityRelService.lambdaQuery().in(FireInspectFacilityRelEntity::getPartId, deleteIds).count();
                if (count>0){
                    throw new ServiceException("当前部件有绑定控制点，无法删除");
                }
                fireFacilityPart =  fireFacilityPartService.deleteLogic(deleteIds);
            }else {
                fireFacilityPart=true;
            }
        }

        if(!fireFacility || !fireFacilityPart || !addPart){
            throw new ServiceException("更新消防设施失败");
        }
        return R.success("操作成功");
    }

    @Override
    public R<FireFacilityResponse> detail(Long id) {
        FireFacilityResponse fireFacilityResponse = new FireFacilityResponse();
        FireFacilityEntity fireFacilityEntity =  baseMapper.selectById(id);
        fireFacilityResponse.setId(fireFacilityEntity.getId());
        fireFacilityResponse.setName(fireFacilityEntity.getName());
        fireFacilityResponse.setParkId(fireFacilityEntity.getParkId());
        List<FireFacilityPartEntity> facilityPartEntityList = fireFacilityPartService.lambdaQuery()
                .eq(FireFacilityPartEntity::getFacilityId,id)
                .eq(FireFacilityPartEntity::getIsDeleted,0)
                .list();
        if(CollectionUtils.isNotEmpty(facilityPartEntityList)){
            List<FireFacilityPartResponse> fireFacilityPartResponseList = facilityPartEntityList
                    .stream().map(part->{
                        FireFacilityPartResponse facilityPart = new FireFacilityPartResponse();
                        BeanUtils.copyProperties(part,facilityPart);
                        facilityPart.setName(part.getName());
                        facilityPart.setParentId(fireFacilityEntity.getId());
                        return facilityPart;
                    })
                    .collect(Collectors.toList());
            fireFacilityResponse.setFireFacilityPartResponseList(fireFacilityPartResponseList);
        }
        PmgBatParkInfo parkInfo = pmgBatParkInfoService.getById(fireFacilityResponse.getParkId());
        if (Func.isNotEmpty(parkInfo)){
            fireFacilityResponse.setParkName(parkInfo.getParkName());
        }
        return R.data(fireFacilityResponse);
    }

    @Override
    public R<List<FireFacilityResponse>> list(FireFacilityQueryRequest queryRequest) {
        ContextUser contextUser = AuthUtil.getUser();
        if (Func.isEmpty(contextUser)){
            return R.data(new ArrayList<>());
        }
        List<PmgBatParkInfo> pmgBatParkInfoList = pmgBatParkInfoService.getAllParkV1(null,contextUser.getIsAdmin(), contextUser.getDeptId(), contextUser.getTenantId(), contextUser.getOrgUserId());
        if (Func.isEmpty(pmgBatParkInfoList)){
            return R.data(new ArrayList<>());
        }
        LambdaQueryWrapper<FireFacilityEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.like(Func.isNotBlank(queryRequest.getName()),FireFacilityEntity::getName,queryRequest.getName());
        lambdaQueryWrapper.in(FireFacilityEntity::getParkId,pmgBatParkInfoList.stream().map(PmgBatParkInfo::getId).collect(Collectors.toList()));
        lambdaQueryWrapper.orderByDesc(FireFacilityEntity::getCreateTime);
        List<FireFacilityEntity> facilityEntityList =  this.list(lambdaQueryWrapper);
        if(CollectionUtils.isEmpty(facilityEntityList)){
            return R.data(Collections.EMPTY_LIST);
        }
        List<FireFacilityResponse> responseList =  listVO(facilityEntityList);
        return R.data(responseList);
    }

    private  List<FireFacilityResponse> listVO(List<FireFacilityEntity> list) {
        return (List)list.stream().map(entity->{
            FireFacilityResponse fireFacilityResponse = detail(entity.getId()).getData();
            return fireFacilityResponse;
        }).collect(Collectors.toList());
    }
}
