package com.cico.nest.lcdp.boot.core.qxsd.application.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.vo.tunnelHole.TunnelHoleRespVO;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.vo.tunnelHoleLine.TunnelHoleMarkerlineRespVO;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.vo.tunnelPassage.TunnelPassageRespVO;
import com.cico.nest.lcdp.boot.core.qxsd.application.service.TunnelBaseService;
import com.cico.nest.lcdp.boot.core.qxsd.domain.tunnel.TunnelTypeEnums;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.TunnelHoleMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.TunnelHoleMarkerlineMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.TunnelPassageMapper;
import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.dataobject.*;
import com.cico.nest.lcdp.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import jakarta.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.cico.nest.lcdp.framework.common.pojo.PageResult;
import com.cico.nest.lcdp.framework.common.pojo.PageParam;
import com.cico.nest.lcdp.framework.common.util.object.BeanUtils;
import static com.cico.nest.lcdp.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
import static com.cico.nest.lcdp.framework.common.exception.util.ServiceExceptionUtil.exception;

import com.cico.nest.lcdp.boot.core.qxsd.infrastructure.gatewayimpl.database.TunnelBaseMapper;
import com.cico.nest.lcdp.boot.core.qxsd.adapter.web.vo.tunnelBase.*;

/**
 * 隧道设施基础信息 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
@Slf4j
public class TunnelBaseServiceImpl implements TunnelBaseService {

    @Resource
    private TunnelBaseMapper tunnelBaseMapper;
    @Resource
    private TunnelHoleMapper tunnelHoleMapper;
    @Resource
    private TunnelHoleMarkerlineMapper tunnelHoleMarkerlineMapper;
    @Resource
    private TunnelPassageMapper tunnelPassageMapper;

    @Override
    public String createTunnel(TunnelInfoVo createReqVO) {
        if (Objects.isNull(createReqVO.getTunnelBase()) || Objects.isNull(createReqVO.getTunnelHoles())){
            return null;
        }
        // 插入隧道基础
        TunnelBaseRespVO tunnelBaseRespVO = createReqVO.getTunnelBase();
        String baseId = StringUtils.isNotEmpty(tunnelBaseRespVO.getId())?tunnelBaseRespVO.getId():IdUtil.getSnowflakeNextIdStr();
        tunnelBaseRespVO.setId(baseId);
        TunnelBaseDO tunnelBase = BeanUtils.toBean(tunnelBaseRespVO, TunnelBaseDO.class);
        tunnelBase.setEnable(tunnelBaseRespVO.getEnable()==null?0:tunnelBaseRespVO.getEnable());//新增隧道，默认设置不可用
        tunnelBaseMapper.insert(tunnelBase);
        //插入上下行洞
        for(TunnelHoleRespVO hole : createReqVO.getTunnelHoles()){
            String holeId = StringUtils.isNotEmpty(hole.getId())?hole.getId():IdUtil.getSnowflakeNextIdStr();
            TunnelHoleV2DO tunnelholeDO = BeanUtils.toBean(hole, TunnelHoleV2DO.class);
            tunnelholeDO.setTunnelId(baseId);
            tunnelholeDO.setId(holeId);
            tunnelHoleMapper.insert(tunnelholeDO);
            //上下行洞内标志线
            List<TunnelHoleMarkerlineRespVO> marklines = hole.getMakerlines() ;
            if (CollectionUtils.isNotEmpty(marklines)){
                List<TunnelHoleMarkerlineDO> markerlineDOS = Lists.newArrayListWithCapacity(marklines.size());
                for(TunnelHoleMarkerlineRespVO markline : marklines){
                    String lineId = StringUtils.isNotEmpty(markline.getId())?markline.getId():IdUtil.getSnowflakeNextIdStr();
                    TunnelHoleMarkerlineDO makrlineDO = BeanUtils.toBean(markline, TunnelHoleMarkerlineDO.class);
                    makrlineDO.setMileArray(TunnelHoleMarkerlineRespVO.convertMileStr(markline.getMileList()));
                    makrlineDO.setId(lineId);
                    makrlineDO.setTunnelId(baseId);
                    makrlineDO.setHoleId(holeId);
                    markerlineDOS.add(makrlineDO);
                }
                tunnelHoleMarkerlineMapper.insertBatch(markerlineDOS);
            }
        }
        //插入横通道
        if (CollectionUtils.isNotEmpty(createReqVO.getTunnelPassages())) {
            List<TunnelPassageDO> passageDOS = new ArrayList<>();
            for (TunnelPassageRespVO passage : createReqVO.getTunnelPassages()) {
                String passageId = StringUtils.isNotEmpty(passage.getId()) ? passage.getId() : IdUtil.getSnowflakeNextIdStr();
                TunnelPassageDO passageDO = BeanUtils.toBean(passage, TunnelPassageDO.class);
                passageDO.setTunnelId(baseId);
                passageDO.setId(passageId);
                passageDOS.add(passageDO);
            }
            tunnelPassageMapper.insertBatch(passageDOS);
        }
        // 返回
        return baseId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createTunnelBase(TunnelBaseSaveReqVO createReqVO) {
        // 插入
        TunnelBaseDO tunnelBase = BeanUtils.toBean(createReqVO, TunnelBaseDO.class);
        tunnelBaseMapper.insert(tunnelBase);
        // 返回
        return tunnelBase.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTunnel(TunnelInfoVo updateReqVO) {
        TunnelBaseRespVO updateBaseVO = updateReqVO.getTunnelBase();
        LocalDateTime currentTime = LocalDateTime.now();
        String tunnelId = updateBaseVO.getId();
        // 校验存在
        validateTunnelBaseExists(tunnelId);
        TunnelBaseDO tunnelBase = BeanUtils.toBean(updateBaseVO, TunnelBaseDO.class);
        //更新隧道基础信息
        tunnelBase.setUpdateTime(currentTime);
        tunnelBaseMapper.updateById(tunnelBase);
        //查詢已有的上下行洞
        LambdaQueryWrapper<TunnelHoleV2DO> queryHoleWrapper = new LambdaQueryWrapperX<TunnelHoleV2DO>()
                .eq(TunnelHoleV2DO::getTunnelId,updateBaseVO.getId())
                .eq(TunnelHoleV2DO::getDeleted,0);
        List<TunnelHoleV2DO> existsHoles = tunnelHoleMapper.selectList(queryHoleWrapper);
        List<String> needDeleteHoleIds = existsHoles.stream().map(a->a.getId()).collect(Collectors.toList());
        //更新上下行洞
        for(TunnelHoleRespVO hole : updateReqVO.getTunnelHoles()) {
            TunnelHoleV2DO tunnelholeDO = BeanUtils.toBean(hole, TunnelHoleV2DO.class);
            tunnelholeDO.setUpdateTime(currentTime);
            if (StringUtils.isEmpty(hole.getId())){
                String holeId = IdUtil.getSnowflakeNextIdStr();
                tunnelholeDO.setId(holeId);
                tunnelholeDO.setTunnelId(tunnelId);
                tunnelholeDO.setCreateTime(currentTime);
                tunnelHoleMapper.insert(tunnelholeDO);
            }else {
                tunnelholeDO.setTunnelId(tunnelId);
                tunnelholeDO.setUpdateTime(currentTime);
                tunnelHoleMapper.updateById(tunnelholeDO);
            }
            if (needDeleteHoleIds.contains(hole.getId())){
                needDeleteHoleIds.remove(hole.getId());
            }
            //更新标志线
            updateMarklins(tunnelholeDO,hole.getMakerlines());
        }
        //刪除多的洞
        if (CollectionUtils.isNotEmpty(needDeleteHoleIds)){
            tunnelHoleMapper.deleteBatchIds(needDeleteHoleIds);
            //同时删除洞下面的标志线
            LambdaQueryWrapper<TunnelHoleMarkerlineDO> deleteLinesWrapper = new LambdaQueryWrapperX<TunnelHoleMarkerlineDO>()
                    .eq(TunnelHoleMarkerlineDO::getTunnelId,tunnelId)
                    .in(TunnelHoleMarkerlineDO::getHoleId,needDeleteHoleIds)
                    .eq(TunnelHoleMarkerlineDO::getDeleted,0);
            tunnelHoleMarkerlineMapper.delete(deleteLinesWrapper);
        }
        //更新横通道信息
        updatePassages(tunnelId,updateReqVO.getTunnelPassages());
    }

    /**
     * 更新隧道洞内标志线
     * @param tunnelholeDO
     * @param marklines
     */
    private void updateMarklins(TunnelHoleV2DO tunnelholeDO, List<TunnelHoleMarkerlineRespVO> marklines){
        LocalDateTime currentTime = LocalDateTime.now();
        //查詢已有的标志线
        LambdaQueryWrapper<TunnelHoleMarkerlineDO> queryMarklineWrapper = new LambdaQueryWrapperX<TunnelHoleMarkerlineDO>()
                .eq(TunnelHoleMarkerlineDO::getTunnelId,tunnelholeDO.getTunnelId())
                .eq(TunnelHoleMarkerlineDO::getHoleId,tunnelholeDO.getId())
                .eq(TunnelHoleMarkerlineDO::getDeleted,0);
        List<TunnelHoleMarkerlineDO> existsMarklines = tunnelHoleMarkerlineMapper.selectList(queryMarklineWrapper);
        List<String> needDeleteLineIds = existsMarklines.stream().map(a->a.getId()).collect(Collectors.toList());
        List<TunnelHoleMarkerlineDO> addMarkerlineDOS =new ArrayList<>();
        List<TunnelHoleMarkerlineDO> updateMarkerlineDOS =new ArrayList<>();
        if (CollectionUtils.isNotEmpty(marklines)){
            for(TunnelHoleMarkerlineRespVO markline : marklines){
                TunnelHoleMarkerlineDO makrlineDO = BeanUtils.toBean(markline, TunnelHoleMarkerlineDO.class);
                makrlineDO.setMileArray(TunnelHoleMarkerlineRespVO.convertMileStr(markline.getMileList()));
                if (StringUtils.isNotEmpty(markline.getId())){
                    //更新
                    makrlineDO.setTunnelId(tunnelholeDO.getTunnelId());
                    makrlineDO.setHoleId(tunnelholeDO.getId());
                    makrlineDO.setUpdateTime(currentTime);
                    updateMarkerlineDOS.add(makrlineDO);
                }else {
                    String lineId = IdUtil.getSnowflakeNextIdStr();
                    //新增
                    makrlineDO.setId(lineId);
                    makrlineDO.setTunnelId(tunnelholeDO.getTunnelId());
                    makrlineDO.setHoleId(tunnelholeDO.getId());
                    makrlineDO.setCreateTime(currentTime);
                    addMarkerlineDOS.add(makrlineDO);
                }
                if (needDeleteLineIds.contains(makrlineDO.getId())){
                    needDeleteLineIds.remove(makrlineDO.getId());
                }
            }
        }
        if (CollectionUtils.isNotEmpty(addMarkerlineDOS)){
            tunnelHoleMarkerlineMapper.insertBatch(addMarkerlineDOS);
        }
        if (CollectionUtils.isNotEmpty(updateMarkerlineDOS)){
            tunnelHoleMarkerlineMapper.updateBatch(updateMarkerlineDOS);
        }
        if (CollectionUtils.isNotEmpty(needDeleteLineIds)){
            tunnelHoleMarkerlineMapper.deleteBatchIds(needDeleteLineIds);
        }
    }

    /**
     * 更新横通道
     * @param tunnelId
     * @param passageVOS
     */
    private void updatePassages(String tunnelId, List<TunnelPassageRespVO> passageVOS){
        LocalDateTime currentTime = LocalDateTime.now();
        //查詢已有的横通道
        LambdaQueryWrapper<TunnelPassageDO> queryPassageWrapper = new LambdaQueryWrapperX<TunnelPassageDO>()
                .eq(TunnelPassageDO::getTunnelId,tunnelId)
                .eq(TunnelPassageDO::getDeleted,0);
        List<TunnelPassageDO> existsPassages = tunnelPassageMapper.selectList(queryPassageWrapper);
        List<String> needDeleteIds = existsPassages.stream().map(a->a.getId()).collect(Collectors.toList());
        List<TunnelPassageDO> addPassageDOS =new ArrayList<>();
        List<TunnelPassageDO> updatePassageDOS =new ArrayList<>();
        if (CollectionUtils.isNotEmpty(passageVOS)){
            for(TunnelPassageRespVO passage : passageVOS){
                TunnelPassageDO passageDO = BeanUtils.toBean(passage, TunnelPassageDO.class);
                if (StringUtils.isNotEmpty(passageDO.getId())){
                    //更新
                    passageDO.setTunnelId(tunnelId);
                    passageDO.setUpdateTime(currentTime);
                    updatePassageDOS.add(passageDO);
                }else {
                    String lineId = IdUtil.getSnowflakeNextIdStr();
                    //新增
                    passageDO.setId(lineId);
                    passageDO.setTunnelId(tunnelId);
                    passageDO.setCreateTime(currentTime);
                    addPassageDOS.add(passageDO);
                }
                if (needDeleteIds.contains(passageDO.getId())){
                    needDeleteIds.remove(passageDO.getId());
                }
            }
        }
        if (CollectionUtils.isNotEmpty(addPassageDOS)){
            tunnelPassageMapper.insertBatch(addPassageDOS);
        }
        if (CollectionUtils.isNotEmpty(updatePassageDOS)){
            tunnelPassageMapper.updateBatch(updatePassageDOS);
        }
        if (CollectionUtils.isNotEmpty(needDeleteIds)){
            tunnelPassageMapper.deleteBatchIds(needDeleteIds);
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTunnelBase(TunnelBaseSaveReqVO updateReqVO) {
        // 校验存在
        validateTunnelBaseExists(updateReqVO.getId());
        // 更新
        TunnelBaseDO updateObj = BeanUtils.toBean(updateReqVO, TunnelBaseDO.class);
        tunnelBaseMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTunnel(String id) {
        // 校验存在
        validateTunnelBaseExists(id);
        // 删除基础设施
        tunnelBaseMapper.deleteById(id);
        //删除上下行洞
        LambdaQueryWrapper<TunnelHoleV2DO> holeWrapper = new LambdaQueryWrapperX<TunnelHoleV2DO>()
                .eq(TunnelHoleV2DO::getTunnelId,id)
                .eq(TunnelHoleV2DO::getDeleted,0);
        tunnelHoleMapper.delete(holeWrapper);
        //删除标志线
        LambdaQueryWrapper<TunnelPassageDO> passageWrapper = new LambdaQueryWrapperX<TunnelPassageDO>()
                .eq(TunnelPassageDO::getTunnelId,id)
                .eq(TunnelPassageDO::getDeleted,0);
        tunnelPassageMapper.delete(passageWrapper);
        //删除标志线
        LambdaQueryWrapper<TunnelHoleMarkerlineDO> marklineWrapper = new LambdaQueryWrapperX<TunnelHoleMarkerlineDO>()
                .eq(TunnelHoleMarkerlineDO::getTunnelId,id)
                .eq(TunnelHoleMarkerlineDO::getDeleted,0);
        tunnelHoleMarkerlineMapper.delete(marklineWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTunnelBase(String id) {
        // 校验存在
        validateTunnelBaseExists(id);
        // 删除
        tunnelBaseMapper.deleteById(id);
    }

    private void validateTunnelBaseExists(String id) {
        if (tunnelBaseMapper.selectById(id) == null) {
            throw exception(INTERNAL_SERVER_ERROR.getCode(), "隧道基础设施不存在");
        }
    }

    @Override
    public TunnelBaseDO getTunnelBase(String id) {
        return tunnelBaseMapper.selectById(id);
    }

    @Override
    public PageResult<TunnelBaseDO> getTunnelBasePage(TunnelBasePageReqVO pageReqVO) {
        return tunnelBaseMapper.selectPage(pageReqVO);
    }

    @Override
    public TunnelInfoVo getTunnel(String tunnelId) {
        TunnelBaseDO tunnelBaseDO = getTunnelBase(tunnelId);
        TunnelBaseRespVO baseRespVO = BeanUtils.toBean(tunnelBaseDO, TunnelBaseRespVO.class);
        TunnelInfoVo vo= new TunnelInfoVo();
        vo.setTunnelBase(baseRespVO);
        //查询上下行洞
        LambdaQueryWrapper<TunnelHoleV2DO> holeWrapper = new LambdaQueryWrapperX<TunnelHoleV2DO>()
                .eq(TunnelHoleV2DO::getTunnelId,tunnelId)
                .eq(TunnelHoleV2DO::getDeleted,0);
        List<TunnelHoleV2DO> holeV2DOS = tunnelHoleMapper.selectList(holeWrapper);
        List<TunnelHoleRespVO> holeRespVOS = BeanUtils.toBean(holeV2DOS, TunnelHoleRespVO.class);
        //查询标志线
        for(TunnelHoleRespVO holeRespVO : holeRespVOS) {
            LambdaQueryWrapper<TunnelHoleMarkerlineDO> marklineWrapper = new LambdaQueryWrapperX<TunnelHoleMarkerlineDO>()
                    .eq(TunnelHoleMarkerlineDO::getTunnelId,tunnelId)
                    .eq(TunnelHoleMarkerlineDO::getHoleId,holeRespVO.getId())
                    .eq(TunnelHoleMarkerlineDO::getDeleted,0);
            List<TunnelHoleMarkerlineDO> markerlineDOS =tunnelHoleMarkerlineMapper.selectList(marklineWrapper);
            if (Objects.nonNull(markerlineDOS)) {
                List<TunnelHoleMarkerlineRespVO> markerlineVOS = BeanUtils.toBean(markerlineDOS, TunnelHoleMarkerlineRespVO.class);
                markerlineVOS.forEach(mk->mk.setMileList(TunnelHoleMarkerlineRespVO.convertMileList(mk.getMileArray())));
                holeRespVO.setMakerlines(markerlineVOS);
            }
        }
        vo.setTunnelHoles(holeRespVOS);
        //查询横通道
        LambdaQueryWrapper<TunnelPassageDO> passageWrapper = new LambdaQueryWrapperX<TunnelPassageDO>()
                .eq(TunnelPassageDO::getTunnelId, tunnelId)
                .eq(TunnelPassageDO::getDeleted, 0);
        List<TunnelPassageDO> passageDOS = tunnelPassageMapper.selectList(passageWrapper);
        List<TunnelPassageRespVO> passageVOS = BeanUtils.toBean(passageDOS, TunnelPassageRespVO.class);
        vo.setTunnelPassages(passageVOS);
        return vo;
    }

    @Override
    public void enable(String id) {
        tunnelBaseMapper.enable(id);
    }

    @Override
    public void disEnable(String id) {
        tunnelBaseMapper.disEnable(id);
    }

    @Override
    public List<TunnelBaseRespVO> getEnableList(String deptId) {
        List<TunnelBaseDO> baseDOS = tunnelBaseMapper.getEnableList(deptId);
        List<TunnelBaseRespVO> res = BeanUtils.toBean(baseDOS,TunnelBaseRespVO.class);
        return res;
    }

    @Override
    public PageResult<TunnelBaseRespVO> getTunnelPage(TunnelBasePageReqVO pageReqVO) {
        PageResult<TunnelBaseRespVO> res = tunnelBaseMapper.selectPageV2(pageReqVO);
        if (CollectionUtils.isNotEmpty(res.getList() )){
            res.getList().forEach(vo->vo.setTunnelTypeName(TunnelTypeEnums.getDesc(Integer.parseInt(vo.getTunnelDesignType()))));
        }
        return res;
    }

    @Override
    public List<TunnelBaseDO> getByIds(List<String> tunnelIds, List<String> sfIds) {
        if (CollectionUtils.isEmpty(tunnelIds) && CollectionUtils.isEmpty(sfIds)){
            return new ArrayList<>();
        }
        LambdaQueryWrapper<TunnelBaseDO> queryWrapper = new LambdaQueryWrapperX<TunnelBaseDO>()
                .inIfPresent(TunnelBaseDO::getId,tunnelIds)
                .inIfPresent(TunnelBaseDO::getSfTunnelId,sfIds)
                .eq(TunnelBaseDO::getDeleted,0);
        List<TunnelBaseDO> respVOS = tunnelBaseMapper.selectList(queryWrapper);
        return respVOS;
    }
}
