/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.base.pigpen.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.omg.CORBA.OBJ_ADAPTER;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.listener.CommonDataChangeEventCenter;
import vip.xiaonuo.common.page.CommonPageRequest;
import vip.xiaonuo.core.enums.BaseDataTypeEnum;
import vip.xiaonuo.core.param.OrgIdParam;
import vip.xiaonuo.modular.base.pigpen.entity.BasePigpen;
import vip.xiaonuo.modular.base.pigpen.entity.vo.BasePigpenMobileVo;
import vip.xiaonuo.modular.base.pigpen.mapper.BasePigpenMapper;
import vip.xiaonuo.modular.base.pigpen.param.*;
import vip.xiaonuo.modular.base.pigpen.service.BasePigpenService;
import vip.xiaonuo.modular.energy.energyDevice.entity.EnergyDevice;
import vip.xiaonuo.modular.energy.energyDevice.mapper.EnergyDeviceMapper;
import vip.xiaonuo.modular.env.envdevice.entity.EnvDevice;
import vip.xiaonuo.modular.env.envdevice.mapper.EnvDeviceMapper;
import vip.xiaonuo.sys.core.enums.SysDataTypeEnum;


import javax.validation.constraints.NotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * base_pigpenService接口实现类
 *
 * @author newspaper
 * @date  2023/12/05 08:55
 **/
@Service
public class BasePigpenServiceImpl extends ServiceImpl<BasePigpenMapper, BasePigpen> implements BasePigpenService {
    @Autowired
    private EnvDeviceMapper envDeviceMapper;
    @Autowired
    private EnergyDeviceMapper energyDeviceMapper;

    @Override
    public Page<BasePigpen> page(BasePigpenPageParam basePigpenPageParam) {
        String orgId = basePigpenPageParam.getOrgId();
        QueryWrapper<BasePigpen> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(BasePigpen::getOrgId,orgId);
        if(ObjectUtil.isNotEmpty(basePigpenPageParam.getParentId())) {
            queryWrapper.lambda().eq(BasePigpen::getParentId, basePigpenPageParam.getParentId());
        }
        if(ObjectUtil.isNotEmpty(basePigpenPageParam.getSearchKey())) {
            queryWrapper.lambda().like(BasePigpen::getBuildName, basePigpenPageParam.getSearchKey());
        }
        if(ObjectUtil.isAllNotEmpty(basePigpenPageParam.getSortField(), basePigpenPageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(basePigpenPageParam.getSortOrder());
            queryWrapper.orderBy(true, basePigpenPageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
                    StrUtil.toUnderlineCase(basePigpenPageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(BasePigpen::getSort);
        }
        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(BasePigpenAddParam basePigpenAddParam) {
        String orgId = basePigpenAddParam.getOrgId();
        BasePigpen basePigpen = BeanUtil.toBean(basePigpenAddParam, BasePigpen.class);
        if (basePigpen.getParentId().equals("0")){
            basePigpen.setType(0);
            basePigpen.setPids("0");
            basePigpen.setFullName(basePigpen.getBuildName());
        }else {
            BasePigpen pigpen = this.getById(basePigpen.getParentId());
            if (pigpen.getType() == 2){
                throw new CommonException("无法将单元作为上级栋舍!");
            }
            basePigpen.setPids(pigpen.getPids() + "," + pigpen.getId());
            basePigpen.setFullName(pigpen.getFullName()+basePigpen.getBuildName());
            basePigpen.setType(this.queryEntity(basePigpen.getParentId()).getType()+1);
        }
        basePigpen.setOrgId(orgId);
        boolean repeatName = this.count(new LambdaQueryWrapper<BasePigpen>()
                .eq(BasePigpen::getParentId, basePigpen.getParentId())
                .eq(BasePigpen::getOrgId,orgId)
                .eq(BasePigpen::getBuildName, basePigpen.getBuildName())) > 0;
        if(repeatName) {
            throw new CommonException("存在重复的同级栋舍，名称为：{}", basePigpen.getBuildName());
        }
        this.save(basePigpen);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(BasePigpenEditParam basePigpenEditParam) {
        BasePigpen basePigpen = this.queryEntity(basePigpenEditParam.getId());
        BeanUtil.copyProperties(basePigpenEditParam, basePigpen);
        if (basePigpen.getParentId().equals("0")){
            if (basePigpen.getType() != 0){
                throw new CommonException("顶级只能作为栋舍的上级栋舍!");
            }
            basePigpen.setType(0);
            basePigpen.setPids("0");
            basePigpen.setFullName(basePigpen.getBuildName());
        }else {
            BasePigpen pigpen = this.getById(basePigpen.getParentId());
            if (!basePigpen.getType().equals(pigpen.getType()+1)){
                throw new CommonException("上级栋舍只能为上一级!");
            }
            if (pigpen.getType() == 2){
                throw new CommonException("无法将单元作为上级栋舍!");
            }
            basePigpen.setPids(pigpen.getPids() + "," + pigpen.getId());
            basePigpen.setFullName(pigpen.getFullName()+basePigpen.getBuildName());
            basePigpen.setType(this.queryEntity(basePigpen.getParentId()).getType()+1);
        }

        boolean repeatName = this.count(new LambdaQueryWrapper<BasePigpen>()
                .eq(BasePigpen::getParentId, basePigpen.getParentId())
                .eq(BasePigpen::getBuildName, basePigpen.getBuildName())
                .eq(BasePigpen::getOrgId,basePigpen.getOrgId())
                .ne(BasePigpen::getId, basePigpen.getId())) > 0;
        if(repeatName) {
            throw new CommonException("存在重复的同级栋舍，名称为：{}", basePigpen.getBuildName());
        }
        List<BasePigpen> originDataList = this.getAllPigpenList(basePigpen.getOrgId());
        boolean errorLevel = this.getChildListById(originDataList, basePigpen.getId(), true).stream()
                .map(BasePigpen::getId).collect(Collectors.toList()).contains(basePigpen.getParentId());
        if(errorLevel) {
            throw new CommonException("不可选择上级栋舍：{}", this.getById(originDataList, basePigpen.getParentId()).getBuildName());
        }
        this.updateById(basePigpen);
        List<BasePigpen> child = this.list(new QueryWrapper<BasePigpen>().lambda().eq(BasePigpen::getParentId, basePigpen.getId()));
        if (CollectionUtil.isNotEmpty(child)){
            for (BasePigpen pigpen : child) {
                pigpen.setPids(basePigpen.getPids()+","+basePigpen.getId());
                pigpen.setFullName(basePigpen.getFullName()+pigpen.getBuildName());
                this.updateById(pigpen);
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<BasePigpenIdParam> basePigpenIdParamList) {
        List<String> toDeletePigpenIdList = CollStreamUtil.toList(basePigpenIdParamList, BasePigpenIdParam::getId);
        // 执行删除
        for (String pigpenId : toDeletePigpenIdList) {
            if (this.count(new LambdaQueryWrapper<BasePigpen>().eq(BasePigpen::getParentId,pigpenId)) > 0){
                throw new CommonException("{}存在下级栋舍", this.getById(pigpenId).getBuildName());
            }
            if (energyDeviceMapper.selectCount(new QueryWrapper<EnergyDevice>().lambda().eq(EnergyDevice::getInstallPosition,pigpenId)) > 0){
                throw new CommonException("{}存在能耗设备", this.getById(pigpenId).getBuildName());
            }
            if (envDeviceMapper.selectCount(new QueryWrapper<EnvDevice>().lambda().eq(EnvDevice::getInstallPosition,pigpenId)) > 0){
                throw new CommonException("{}存在环控设备设备", this.getById(pigpenId).getBuildName());
            }
        }
        this.removeByIds(toDeletePigpenIdList);
        // 发布删除事件
        CommonDataChangeEventCenter.doDeleteWithDataId(BaseDataTypeEnum.PIGPEN.getValue(), toDeletePigpenIdList);
    }

    @Override
    public BasePigpen detail(BasePigpenIdParam basePigpenIdParam) {
        return this.queryEntity(basePigpenIdParam.getId());
    }

    @Override
    public BasePigpen queryEntity(String id) {
        BasePigpen basePigpen = this.getById(id);
        if(ObjectUtil.isEmpty(basePigpen)) {
            throw new CommonException("栋舍不存在，id值为：{}", id);
        }
        return basePigpen;
    }

    @Override
    public List<BasePigpen> getAllPigpenList(String orgId) {
        List<BasePigpen> orgList = this.list(new LambdaQueryWrapper<BasePigpen>().eq(BasePigpen::getOrgId,orgId).orderByAsc(BasePigpen::getId));
        return orgList;
    }

    @Override
    public List<BasePigpen> getChildListById(List<BasePigpen> originDataList, String id, boolean includeSelf) {
        List<BasePigpen> resultList = CollectionUtil.newArrayList();
        execRecursionFindChild(originDataList, id, resultList);
        if (includeSelf) {
            BasePigpen self = this.getById(originDataList, id);
            if (ObjectUtil.isNotEmpty(self)) {
                resultList.add(self);
            }
        }
        return resultList;
    }

    public void execRecursionFindChild(List<BasePigpen> originDataList, String id, List<BasePigpen> resultList) {
        originDataList.forEach(item -> {
            if(item.getParentId().equals(id)) {
                resultList.add(item);
                execRecursionFindChild(originDataList, item.getId(), resultList);
            }
        });
    }

    @Override
    public BasePigpen getById(List<BasePigpen> originDataList, String id) {
        int index = CollStreamUtil.toList(originDataList, BasePigpen::getId).indexOf(id);
        return index == -1?null:originDataList.get(index);
    }

    @Override
    public List<Tree<String>> tree(BasePigpenOrgIdParam basePigpenOrgIdParam) {
        String orgId = basePigpenOrgIdParam.getOrgId();
        List<BasePigpen> allPigpenList = this.getAllPigpenList(orgId);
        List<TreeNode<String>> treeNodeList = allPigpenList.stream().map(basePigpen ->
                new TreeNode<>(basePigpen.getId(), basePigpen.getParentId(),
                        basePigpen.getBuildName(), basePigpen.getSort()).setExtra(JSONUtil.parseObj(basePigpen)))
                .collect(Collectors.toList());
        return TreeUtil.build(treeNodeList, "0");
    }

    @Override
    public List<BasePigpenMobileVo> mobileTree(BasePigpenOrgIdParam basePigpenOrgIdParam) {
        String orgId = basePigpenOrgIdParam.getOrgId();
        List<BasePigpenMobileVo> resultList = new ArrayList<>();

        // 根节点
        BasePigpenMobileVo root = new BasePigpenMobileVo();
        root.setName("全场");
        root.setId(null);
        root.setType(0);

        List<BasePigpenMobileVo> child = new ArrayList<>();
        child.add(createPigpenNode(null,"全场", 0));
        root.setChild(child);

        resultList.add(root);

        List<BasePigpen> basePigpenList = getPigpenListByTypeAndParentId(orgId, 0, 0);

        if (ObjectUtil.isNotEmpty(basePigpenList)) {
            for (BasePigpen basePigpen : basePigpenList) {
                BasePigpenMobileVo mobileVo = createPigpenNode(basePigpen.getId(), basePigpen.getFullName(), 1);

                List<BasePigpenMobileVo> child2 = new ArrayList<>();
                child2.add(createPigpenNode(basePigpen.getId(),basePigpen.getFullName() + "整栋", 1));

                List<BasePigpen> basePigpenList1 = getPigpenListByTypeAndPids(orgId, 2, basePigpen.getId());
                if (ObjectUtil.isNotEmpty(basePigpenList1)) {
                    basePigpenList1.forEach(pigpen -> child2.add(createPigpenNode(pigpen.getId(), pigpen.getFullName(), 2)));
                }

                mobileVo.setChild(child2);
                resultList.add(mobileVo);
            }
        }
        return resultList;
    }

    @Override
    public List<BasePigpen> listBuild(OrgIdParam orgIdParam) {
        String orgId = orgIdParam.getOrgId();
        List<BasePigpen> list = this.list(new QueryWrapper<BasePigpen>().lambda().eq(BasePigpen::getParentId, 0).eq(BasePigpen::getOrgId, orgId).orderByAsc(BasePigpen::getSort));
        return list;
    }

    @Override
    public List<BasePigpen> listUnit(BasePigpenIdParam basePigpenIdParam) {
        String id = basePigpenIdParam.getId();
        List<BasePigpen> list = this.list(new QueryWrapper<BasePigpen>().lambda().like(BasePigpen::getPids,id).eq(BasePigpen::getType, 2).orderByAsc(BasePigpen::getSort));
        return list;
    }

    private List<BasePigpen> getPigpenListByTypeAndPids(String orgId, int type, String pids) {
        return this.list(new QueryWrapper<BasePigpen>().lambda()
                .eq(BasePigpen::getType, type)
                .like(BasePigpen::getPids, pids)
                .eq(BasePigpen::getOrgId, orgId));
    }

    private List<BasePigpen> getPigpenListByTypeAndParentId(String orgId, int type, int parentId) {
        return this.list(new QueryWrapper<BasePigpen>().lambda()
                .eq(BasePigpen::getType, type)
                .eq(BasePigpen::getParentId, parentId)
                .eq(BasePigpen::getOrgId, orgId));
    }

    private BasePigpenMobileVo createPigpenNode(String id, String name, int type) {
        BasePigpenMobileVo mobileVo = new BasePigpenMobileVo();
        mobileVo.setId(id);
        mobileVo.setName(name);
        mobileVo.setType(type);
        return mobileVo;
    }
}
