package com.ruoyi.ibs.draw.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.ibs.draw.domain.dto.draw.ShapeAddDTO;
import com.ruoyi.ibs.draw.domain.dto.draw.ShapeInfoEditDTO;
import com.ruoyi.ibs.draw.domain.dto.draw.ShapeOverlapDTO;
import com.ruoyi.ibs.draw.domain.dto.draw.ShapeWktEditDTO;
import com.ruoyi.ibs.draw.domain.dto.grid.CustCountDTO;
import com.ruoyi.ibs.draw.domain.entity.DrawLayerAudit;
import com.ruoyi.ibs.draw.domain.entity.DrawShape;
import com.ruoyi.ibs.draw.domain.vo.DrawShapeVO;
import com.ruoyi.ibs.draw.mapper.DrawLayerAuditMapper;
import com.ruoyi.ibs.draw.mapper.DrawLayerMapper;
import com.ruoyi.ibs.draw.mapper.DrawShapeCustMapper;
import com.ruoyi.ibs.draw.mapper.DrawShapeMapper;
import com.ruoyi.ibs.draw.service.DrawGridCustService;
import com.ruoyi.ibs.draw.service.DrawShapeService;
import com.ruoyi.ibs.draw.utils.DrawUtils;
import com.ruoyi.ibs.grid.service.AddressAnalyseService;
import com.ruoyi.system.service.ISysUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableAsync;
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;

/**
 * @Author 吴凯程
 * @Date 2024/12/20
 **/
@Service
@Slf4j
@EnableAsync
public class DrawShapeServiceImpl implements DrawShapeService {

    @Resource
    private DrawShapeMapper drawShapeMapper;

    @Resource
    private DrawShapeCustMapper drawShapeCustMapper;

    @Resource
    private DrawGridCustService drawGridCustService;

    @Resource
    private AddressAnalyseService addressAnalyseService;

    @Resource
    private ISysUserService sysUserService;

    @Resource
    private DrawLayerMapper drawLayerMapper;

    @Resource
    private DrawLayerAuditMapper drawLayerAuditMapper;

    @Resource
    private RedisCache redisCache;

    private final static String shapeCountRedisKey = "DRAW_SHAPE_COUNT_";

    /**
     * @param shapeAddDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String addShapeToLayer(ShapeAddDTO shapeAddDTO) {
        isShapeNameValid(shapeAddDTO.getLayerId(), shapeAddDTO.getShapeName());
        if (!addressAnalyseService.checkWktValid(shapeAddDTO.getShapeWkt())) {
            throw new ServiceException("暂不支持在该区域进行绘制");
        }
        List<String> wktList = getWktsInLayersById(shapeAddDTO.getLayerId(), shapeAddDTO.getOpsDept());
        if (DrawUtils.checkOverlap(shapeAddDTO.getShapeWkt(), wktList)) {
            throw new ServiceException("图形存在重叠");
        }
//        if (drawGridCustService.getCodeByWkt(shapeAddDTO.getShapeWkt()).size() > 10) {
//            throw new ServiceException("图形绘制过大");
//        }
        DrawShape drawShape = new DrawShape();
        BeanUtils.copyProperties(shapeAddDTO, drawShape);
        //新增时将区域设置为待审核
        drawShape.setAuditStatus("0");
        if (drawShapeMapper.insert(drawShape) > 0) {
            // 审核列表新增一条信息，需创建后查询对应shapeId。
            insertAudit(drawShape);
            drawGridCustService.updateCustListByShape(drawShape.getShapeId());
        }

        return "图形创建成功";
    }

    /**
     * @param shapeInfoEditDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String editShapeInfo(ShapeInfoEditDTO shapeInfoEditDTO) {
        DrawShape drawShape = drawShapeMapper.selectById(shapeInfoEditDTO.getShapeId());
        if (Objects.isNull(drawShape)) {
            throw new ServiceException("图形不存在");
        }
        if (Objects.nonNull(shapeInfoEditDTO.getShapeName()) && !drawShape.getShapeName().equals(shapeInfoEditDTO.getShapeName())) {
            LambdaQueryWrapper<DrawShape> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(DrawShape::getLayerId, shapeInfoEditDTO.getLayerId())
                    .ne(DrawShape::getShapeId, shapeInfoEditDTO.getShapeId())
                    .eq(DrawShape::getShapeName, shapeInfoEditDTO.getShapeName());
            if (drawShapeMapper.selectCount(queryWrapper) > 0) {
                throw new ServiceException("图层中存在相同的图形名称");
            }
            drawShape.setShapeName(shapeInfoEditDTO.getShapeName());
        }
        drawShape.setRemark(shapeInfoEditDTO.getRemark());
        drawShapeMapper.updateById(drawShape);
        return "图形名称修改成功";
    }

    /**
     * @param layerId
     * @param shapeName
     * @return
     */
    @Override
    public Boolean checkShapeNameValid(Long layerId, String shapeName) {
        LambdaQueryWrapper<DrawShape> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DrawShape::getLayerId, layerId)
                .eq(DrawShape::getShapeName, shapeName);
        return drawShapeMapper.selectCount(queryWrapper) < 1;
    }

    private void isShapeNameValid(Long layerId, String shapeName) {
        LambdaQueryWrapper<DrawShape> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DrawShape::getLayerId, layerId)
                .eq(DrawShape::getShapeName, shapeName);
        if (drawShapeMapper.selectCount(queryWrapper) > 0) {
            throw new ServiceException("图层中存在相同的图形名称");
        }
    }

    /**
     * @param shapeWktEditDTO
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String editShapeWkt(ShapeWktEditDTO shapeWktEditDTO) {
        DrawShape drawShape = drawShapeMapper.selectById(shapeWktEditDTO.getShapeId());
        if (Objects.isNull(drawShape)) {
            throw new ServiceException("图形不存在");
        }
        if (!addressAnalyseService.checkWktValid(shapeWktEditDTO.getShapeWkt())) {
            throw new ServiceException("暂不支持在该区域进行绘制");
        }
        LambdaQueryWrapper<DrawShape> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DrawShape::getLayerId, shapeWktEditDTO.getLayerId())
                .eq(DrawShape::getOpsDept, drawShape.getOpsDept());
        List<String> wktList = drawShapeMapper.selectList(queryWrapper).stream().filter(d -> !d.getShapeId().equals(shapeWktEditDTO.getShapeId()))
                .map(DrawShape::getShapeWkt).collect(Collectors.toList());
        if (DrawUtils.checkOverlap(shapeWktEditDTO.getShapeWkt(), wktList)) {
            throw new ServiceException("图形在该图层中存在重叠");
        }
        drawShape.setShapeWkt(shapeWktEditDTO.getShapeWkt());

        if (!drawShape.getAuditStatus().equals("0")){
        //待审核状态下不需要
            // 审核列表新增一条信息
            insertAudit(drawShape);
        }
        //编辑图形将图形设置为待审核状态
        drawShape.setAuditStatus("0");
        if (drawShapeMapper.updateById(drawShape) > 0) {
            drawGridCustService.updateCustListByShape(drawShape.getShapeId());
        }
        // TODO 更新图形管护关系表
        return "图形编辑成功";
    }

    /**
     * @param
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String deleteShape(List<Long> idList) {
        idList.forEach(shapeId -> {
            DrawShape drawShape = drawShapeMapper.selectById(shapeId);
            if (Objects.isNull(drawShape)) {
                throw new ServiceException("图形不存在");
            }
            if (drawShape.getRelateFlag()) {
                String gridNameByShapeId = drawShapeMapper.getGridNameByShapeId(drawShape.getShapeId());
                throw new ServiceException("图形已与特色网格" + gridNameByShapeId + "关联，请先解除关联");
            }
            drawShapeCustMapper.batchDelete(shapeId, String.valueOf(SecurityUtils.getDeptId()).substring(0, 3));
            //删除图层时，删除对应的审批中心消息
            drawLayerAuditMapper.delete(new LambdaQueryWrapper<DrawLayerAudit>().eq(DrawLayerAudit::getShapeId,shapeId));
            drawShapeMapper.deleteById(drawShape);
        });
        return "图形删除成功";
    }

    /**
     * @param layerId
     * @param opsDept
     * @return
     */
    @Override
    public List<String> getWktsInLayersById(Long layerId, String opsDept) {
        LambdaQueryWrapper<DrawShape> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DrawShape::getLayerId, layerId)
                .eq(DrawShape::getOpsDept, opsDept);
        return drawShapeMapper.selectList(queryWrapper).stream().map(DrawShape::getShapeWkt).collect(Collectors.toList());
    }

    @Override
    public List<DrawShapeVO> getShapeList(Long layerId,Long shapeId,String shapeName,String createBy,String ops, Boolean isRelate,String auditStatus) {
        LambdaQueryWrapper<DrawShape> queryWrapper = new LambdaQueryWrapper<>();
        String opsDept;
        if (ops != null &&!ops.equals("")){
            opsDept=ops;
        }else {
            opsDept = SecurityUtils.getOpsDept();
        }
        if (SecurityUtils.userRole().equals("head")){
            queryWrapper.eq(DrawShape::getLayerId, layerId)
                    .orderByDesc(DrawShape::getOpsDept)
                    .orderByAsc(DrawShape::getAuditStatus)
                    .orderByDesc(DrawShape::getUpdateTime);
            if (ops!=null&& !ops.equals("")){
                queryWrapper.eq(DrawShape::getOpsDept,ops);
            }
        }else if (SecurityUtils.userRole().equals("branch")){
            queryWrapper.eq(DrawShape::getLayerId, layerId)
                    .eq(DrawShape::getDeptId,SecurityUtils.getDeptId())
                    .orderByAsc(DrawShape::getAuditStatus)
//                    .eq(DrawShape::getCreateBy,SecurityUtils.getUsername())
                    .orderByDesc(DrawShape::getUpdateTime);
            if (ops!=null&& !ops.equals("")){
                queryWrapper.eq(DrawShape::getOpsDept,ops);
            }
        }else{
            queryWrapper.eq(DrawShape::getLayerId, layerId)
                    .eq(DrawShape::getOpsDept,opsDept)
                    .orderByAsc(DrawShape::getAuditStatus)
                    .orderByDesc(DrawShape::getUpdateTime);
        }
        if (shapeName!=null&&!shapeName.equals("")){
            queryWrapper.like(DrawShape::getShapeName,shapeName);
        }
        if (createBy!=null&&!createBy.equals("")){
            queryWrapper.like(DrawShape::getCreateBy,createBy);
        }
        if (isRelate!=null){
            queryWrapper.eq(DrawShape::getRelateFlag,isRelate);
        }
        if (auditStatus!=null){
            queryWrapper.eq(DrawShape::getAuditStatus,auditStatus);
        }
        if (shapeId!=null){
            queryWrapper.eq(DrawShape::getShapeId,shapeId);
        }
        return drawShapeMapper.selectList(queryWrapper).stream().map(drawShape -> {
            DrawShapeVO drawShapeVO = new DrawShapeVO(drawShape);
            drawShapeVO.setDeptId(drawShape.getDeptId().toString());
            drawShapeVO.setCreateBy(sysUserService.selectUserByUserName(drawShape.getCreateBy()).getNickName()+"-"+drawShape.getCreateBy());
            CustCountDTO custCountDTO = new CustCountDTO();
            if (!drawShape.getBatchFlag()) {
                custCountDTO = drawGridCustService.countCustByShape(drawShape.getShapeId());
            }
            BeanUtils.copyProperties(custCountDTO, drawShapeVO);
            return drawShapeVO;
        }).collect(Collectors.toList());
    }

    /**
     * @param layerId
     * @param opsDept
     * @return
     */
    @Override
    public List<DrawShapeVO> getShapeAvailableList(Long layerId, String opsDept) {
        LambdaQueryWrapper<DrawShape> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DrawShape::getLayerId, layerId)
                .eq(DrawShape::getOpsDept, opsDept)
                .eq(DrawShape::getRelateFlag, Boolean.FALSE)
                .eq(DrawShape::getAuditStatus, "1")
                .eq(DrawShape::getRelateFlag, Boolean.FALSE)
                .eq(DrawShape::getDeptId, SecurityUtils.getDeptId());
        return drawShapeMapper.selectList(queryWrapper).stream().map(drawShape -> {
            DrawShapeVO drawShapeVO = new DrawShapeVO(drawShape);
            return drawShapeVO;
        }).collect(Collectors.toList());
    }

    @Override
    public Boolean checkShapeOverlap(ShapeOverlapDTO shapeOverlapDTO) {
        LambdaQueryWrapper<DrawShape> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DrawShape::getLayerId, shapeOverlapDTO.getLayerId());
        List<DrawShape> drawShapes = drawShapeMapper.selectList(queryWrapper);
        List<String> wktList;
        if (Objects.nonNull(shapeOverlapDTO.getShapeId())) {
            wktList = drawShapes.stream().filter(drawShape -> drawShape.getShapeId().equals(shapeOverlapDTO.getShapeId()))
                    .map(DrawShape::getShapeWkt).collect(Collectors.toList());
        } else {
            wktList = drawShapes.stream().map(DrawShape::getShapeWkt).collect(Collectors.toList());
        }
        return DrawUtils.checkOverlap(shapeOverlapDTO.getWkt(), wktList);
    }



    /**
     * @param shapeIds
     * @return
     */
    @Override
    public Boolean checkShapeRelate(List<Long> shapeIds) {
        LambdaQueryWrapper<DrawShape> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(DrawShape::getShapeId, shapeIds);
        List<DrawShape> drawShapes = drawShapeMapper.selectList(queryWrapper);
        for (DrawShape drawShape : drawShapes) {
            if (!drawShape.getRelateFlag()) {
                return Boolean.FALSE;
            }
        }
        return Boolean.TRUE;
    }

    /**
     * @param
     */
    @Override
    public void updateShapeRelate(Long shapeId) {
        DrawShape drawShape = drawShapeMapper.selectById(shapeId);
        if (Objects.isNull(drawShape)) {
            throw new ServiceException("图形不存在");
        }
        drawShape.setRelateFlag(!drawShape.getRelateFlag());
        drawShapeMapper.updateById(drawShape);
    }

    @Override
    public String updateCustList(Long shapeId) {
        DrawShape drawShape = drawShapeMapper.selectById(shapeId);
        if (Objects.isNull(drawShape)) {
            throw new ServiceException("图形不存在");
        }
        if (drawShape.getBatchFlag()) {
            throw new ServiceException("当前图形正在获取客户列表，请稍等");
        }
        drawGridCustService.updateCustListByShape(drawShape.getShapeId());
        return "开始刷新图形客户列表，请稍等";
    }

    @Override
    public String isEdit(Long shapeId) {
        DrawShape drawShape = drawShapeMapper.selectById(shapeId);
        if (!SecurityUtils.getUsername().equals(drawShape.getCreateBy())){
            throw new ServiceException("非创建者，暂无编辑权限");
        }
        return "可编辑";
    }

    @Override
    public int insertAudit(DrawShape drawShape){
        DrawLayerAudit drawLayerAudit = new DrawLayerAudit();
        drawLayerAudit.setId(0);
        drawLayerAudit.setDeleteStatus(0);
        drawLayerAudit.setUserName(SecurityUtils.getUsername());
        drawLayerAudit.setNickName(SecurityUtils.getLoginUser().getUser().getNickName());
        drawLayerAudit.setOpsDept(drawShape.getOpsDept());
        drawLayerAudit.setDeptId(SecurityUtils.getDeptId().toString());
        drawLayerAudit.setDeptName(SecurityUtils.getLoginUser().getUser().getDept().getDeptName());
        drawLayerAudit.setLayerId(drawShape.getLayerId().toString());
        drawLayerAudit.setLayerName(drawLayerMapper.selectById(drawShape.getLayerId()).getLayerName());
        drawLayerAudit.setShapeId(drawShape.getShapeId().toString());
        drawLayerAudit.setShapeName(drawShape.getShapeName());
        return drawLayerAuditMapper.insert(drawLayerAudit);
    }

    @Override
    @Transactional
    public String drawShapeReAudit(DrawShape drawShape) {
        DrawShape drawShape1 = drawShapeMapper.selectById(drawShape.getShapeId());
        drawShape1.setAuditStatus("0");
        drawShape1.setAuditRemark(drawShape.getAuditRemark());
        drawShapeMapper.updateById(drawShape1);
        insertAudit(drawShape1);
        return "已重新提交审核";
    }


}
