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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.ibs.draw.domain.dto.grid.CustCountDTO;
import com.ruoyi.ibs.draw.domain.dto.grid.DrawGridCustListDTO;
import com.ruoyi.ibs.draw.domain.dto.grid.UnbindUserDTO;
import com.ruoyi.ibs.draw.domain.entity.DrawGrid;
import com.ruoyi.ibs.draw.domain.entity.DrawGridCustUserUnbind;
import com.ruoyi.ibs.draw.domain.entity.DrawShape;
import com.ruoyi.ibs.draw.domain.entity.DrawShapeCust;
import com.ruoyi.ibs.draw.domain.vo.DrawGridCustVO;
import com.ruoyi.ibs.draw.domain.vo.ShapeCustVO;
import com.ruoyi.ibs.draw.mapper.DrawGridCustUserUnbindMapper;
import com.ruoyi.ibs.draw.mapper.DrawGridMapper;
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.utils.DrawUtils;
import com.ruoyi.ibs.grid.domain.entity.AdminDivision;
import com.ruoyi.ibs.grid.domain.entity.AdminDivisionFence;
import com.ruoyi.ibs.grid.domain.vo.AddressResultVO;
import com.ruoyi.ibs.grid.mapper.AdminDivisionFenceMapper;
import com.ruoyi.ibs.grid.mapper.AdminDivisionMapper;
import com.ruoyi.ibs.grid.mapper.AnchorMapper;
import com.ruoyi.ibs.grid.mapper.CustInfoMapper;
import com.ruoyi.ibs.grid.service.AddressAnalyseService;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysUserMapper;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Service;

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

/**
 * @Author 吴凯程
 * @Date 2024/12/26
 **/
@Service
@Slf4j
@EnableAsync
public class DrawGridCustServiceImpl implements DrawGridCustService {

    @Resource
    private DrawGridMapper drawGridMapper;

    @Resource
    private DrawShapeMapper drawShapeMapper;

    @Resource
    private DrawShapeCustMapper drawShapeCustMapper;

    @Resource
    private AdminDivisionMapper adminDivisionMapper;

    @Resource
    private AdminDivisionFenceMapper adminDivisionFenceMapper;

    @Resource
    private CustInfoMapper custInfoMapper;

    @Resource
    private DrawGridCustUserUnbindMapper drawGridCustUserUnbindMapper;

    @Resource
    private AddressAnalyseService addressAnalyseService;

    @Resource
    private SysDeptMapper sysDeptMapper;

    @Resource
    private SysUserMapper sysUserMapper;

    @Resource
    private AnchorMapper anchorMapper;

    @Resource
    private RedisCache redisCache;

    private final static String shapeCountRedisKey = "DRAW_SHAPE_COUNT_";

    private final GeometryFactory geometryFactory = new GeometryFactory();


    /**
     * @param shapeId
     * @return
     */
    @Override
    @Async
    public void updateCustListByShape(Long shapeId) {
        log.info("开始更新图形客户列表");
        DrawShape drawShape = drawShapeMapper.selectById(shapeId);
        String deptCode = String.valueOf(drawShape.getDeptId()).substring(0, 3);

        drawShapeMapper.updateBatchFlag(shapeId, Boolean.TRUE);
        drawShapeCustMapper.batchDelete(shapeId, deptCode);

        Long layerId = drawShape.getLayerId();
        Geometry geometry = DrawUtils.parseWkt(drawShape.getShapeWkt());
        List<String> codeByWkt = getCodeByWkt(drawShape.getShapeWkt());
        log.info("图形范围为：" + codeByWkt.toString());
        if (codeByWkt.isEmpty()) {
            log.info("图形范围不存在");
            return;
        }
        int pageNum = 1;
        int pageSize = 10000;
        PageInfo<ShapeCustVO> pageInfo;

        do {
            PageHelper.startPage(pageNum, pageSize);
            List<ShapeCustVO> shapeCustVOS = new ArrayList<>();
            if(drawShape.getOpsDept().equals("0")){
                shapeCustVOS = custInfoMapper.selectPrivateCustByCode(codeByWkt, deptCode);
            }else if(drawShape.getOpsDept().equals("1")){
                shapeCustVOS = custInfoMapper.selectPublicCustByCode(codeByWkt, deptCode);
            }else if(drawShape.getOpsDept().equals("2")){
                shapeCustVOS = custInfoMapper.selectCustByCode(codeByWkt, deptCode);
            }
            pageInfo = new PageInfo<>(shapeCustVOS);

            List<DrawShapeCust> custList = new ArrayList<>();
            for (ShapeCustVO shapeCustVO : pageInfo.getList()) {
                if (Objects.isNull(shapeCustVO.getLongitude())
                        || shapeCustVO.getLongitude().isEmpty()
                        || Objects.isNull(shapeCustVO.getLatitude())
                        || shapeCustVO.getLatitude().isEmpty()) {
                    continue;
                }
                Point point = geometryFactory.createPoint(new Coordinate(Double.valueOf(shapeCustVO.getLongitude()), Double.valueOf(shapeCustVO.getLatitude())));
                if (geometry.contains(point)) {
                    DrawShapeCust drawShapeCust = new DrawShapeCust();
                    BeanUtils.copyProperties(shapeCustVO, drawShapeCust);
                    drawShapeCust.setLayerId(layerId);
                    drawShapeCust.setShapeId(shapeId);
                    custList.add(drawShapeCust);
                }
            }
            if (!custList.isEmpty()) {
                drawShapeCustMapper.batchInsert(custList, deptCode);
            }
            pageNum++;
        } while (pageNum <= pageInfo.getPages());
        log.info("图形客户列表更新完成");
        drawShapeMapper.updateBatchFlag(shapeId, Boolean.FALSE);
    }

    /**
     *
     */
    @Override
    @Async
    public void updateShapeList() {
        log.info("开始全量更新图形列表");
        List<DrawShape> drawShapes = drawShapeMapper.selectList(null);
        for (DrawShape drawShape : drawShapes) {
            updateCustListByShape(drawShape.getShapeId());
        }
    }

    @Override
    public CustCountDTO countCustByShape(Long shapeId) {
        CustCountDTO custCountDTO = new CustCountDTO();
        custCountDTO.setRetailCount(drawShapeCustMapper.countRetail(shapeId));
        custCountDTO.setBusinessCount(drawShapeCustMapper.countBusiness(shapeId));
        custCountDTO.setMerchantCount(drawShapeCustMapper.countMerchant(shapeId));
        redisCache.setCacheObjectToEndDay(shapeCountRedisKey + shapeId, custCountDTO);
        return custCountDTO;
    }

    /**
     * @param wkt
     * @return
     */
    @Override
    public List<String> getCodeByWkt(String wkt) {
        Geometry geometry = DrawUtils.parseWkt(wkt);
        List<String> codeList = new ArrayList<>();
        int geoCount = geometry.getNumGeometries();
        for (int i = 0; i < geoCount; i++) {
            Polygon polygon = (Polygon) geometry.getGeometryN(i);
            for (Coordinate coordinate : polygon.getExteriorRing().getCoordinates()) {
                AddressResultVO addressResultVO = addressAnalyseService.pointInGeometry(coordinate.getX(), coordinate.getY());
                if (!addressResultVO.getStatus().equals(0)) {
                    continue;
                }
                if(addressResultVO.getCode().startsWith("33")){
                    String code = addressResultVO.getCode().length() == 9 ? addressResultVO.getCode() : addressResultVO.getCode().substring(0, 9);
                    if (!codeList.contains(code)) {
                        codeList.add(code);
                    }
                }else if (addressResultVO.getCode().startsWith("31")){
                    if (!codeList.contains(addressResultVO.getCode())) {
                        codeList.add(addressResultVO.getCode());
                    }
                }
            }
        }
        List<AdminDivision> adminDivisions = new ArrayList<>();
        List<String> zjCodeList = codeList.stream().filter(code -> code.startsWith("33")).collect(Collectors.toList());
        List<String> shCodeList = codeList.stream().filter(code -> code.startsWith("31")).collect(Collectors.toList());
        if (!zjCodeList.isEmpty()){
            LambdaQueryWrapper<AdminDivision> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(AdminDivision::getLevel, 5);
            queryWrapper.and(q -> {
                zjCodeList.forEach(code -> {
                    q.or().likeRight(AdminDivision::getCode, code);
                });
            });
            adminDivisions.addAll(adminDivisionMapper.selectList(queryWrapper));
        }
        if(!shCodeList.isEmpty()){
            LambdaQueryWrapper<AdminDivision> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.and(q -> {
                shCodeList.forEach(code -> {
                    q.or().likeRight(AdminDivision::getCode, code);
                });
            });
            adminDivisions.addAll(adminDivisionMapper.selectList(queryWrapper));
        }
        List<Integer> collect = adminDivisions.stream().map(adminDivision -> adminDivision.getId()).collect(Collectors.toList());
        List<String> output = new ArrayList<>();
        List<AdminDivisionFence> adminDivisionFences = adminDivisionFenceMapper.selectBatchIds(collect);
        for (AdminDivisionFence adminDivisionFence : adminDivisionFences) {
            if (Objects.isNull(adminDivisionFence.getGrid())) {
                continue;
            }
            Geometry g = DrawUtils.parseWkt(adminDivisionFence.getGrid());
            if (g.intersects(geometry) || geometry.overlaps(g) || g.overlaps(geometry)) {
                AdminDivision match = adminDivisions.stream().filter(ad -> ad.getId().equals(adminDivisionFence.getId())).findFirst().orElse(null);
                if (!output.contains(match.getCode())) {
                    output.add(match.getCode());
                }
            }
        }
        return output.stream().distinct().collect(Collectors.toList());
    }

    /**
     * @param shapeId
     * @return
     */
    @Override
    public List<DrawShapeCust> getCustListByShape(Long shapeId,String custType) {
        LambdaQueryWrapper<DrawShapeCust> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DrawShapeCust::getShapeId, shapeId).eq(DrawShapeCust::getCustType,custType).orderByAsc(DrawShapeCust::getCustType);
        return drawShapeCustMapper.selectList(queryWrapper);
    }

    /**
     * @return
     */
    @Override
    public List<DrawGridCustVO> getCustListByGrid(DrawGridCustListDTO drawGridCustListDTO) {
        List<DrawGridCustVO> custListByManager;
        if (!SecurityUtils.userRole().equals("manager")) {
            custListByManager = drawGridCustUserUnbindMapper.getCustList(drawGridCustListDTO);
        } else {
            custListByManager = drawGridCustUserUnbindMapper.getCustListByManager(drawGridCustListDTO);
        }
        if (Objects.isNull(custListByManager) || custListByManager.isEmpty()) {
            return custListByManager;
        }
        DrawGrid drawGrid = drawGridMapper.selectById(drawGridCustListDTO.getGridId());
        String creator = sysUserMapper.selectUserByUserName(drawGrid.getCreateBy()).getNickName() + '-' + drawGrid.getCreateBy();
        for (DrawGridCustVO drawGridCustVO : custListByManager) {
            drawGridCustVO.setAddress(anchorMapper.selectAddressByCustIdc(drawGridCustVO.getCustIdn()));
            drawGridCustVO.setCreator(creator);
            drawGridCustVO.setCustIdn(drawGridCustVO.getCustId().substring(3, drawGridCustVO.getCustId().length()));
            if (drawGridCustVO.getCustType().equals("0")) {
                drawGridCustVO.setCustType("个人");
            } else if (drawGridCustVO.getCustType().equals("1")) {
                drawGridCustVO.setCustType("商户");
            } else if (drawGridCustVO.getCustType().equals("2")) {
                drawGridCustVO.setCustType("企业");
            }
            SysUser sysUser = sysUserMapper.selectUserByUserName(drawGridCustVO.getUserName());
            SysDept sysDept = sysDeptMapper.selectDeptById(sysUser.getDeptId());
            if (sysDept.getDeptType().equals("outlet")) {
                drawGridCustVO.setOutletId(sysDept.getDeptId());
                drawGridCustVO.setOutletName(sysDept.getDeptName());
                drawGridCustVO.setBranchId(sysDept.getParentId());
                drawGridCustVO.setBranchName(sysDept.getParentName());
            } else {
                drawGridCustVO.setBranchId(sysDept.getDeptId());
                drawGridCustVO.setBranchName(sysDept.getDeptName());
            }

        }
        return custListByManager;
    }

    @Override
    public String unbindCustManager(UnbindUserDTO unbindUserDTO) {
        LambdaQueryWrapper<DrawGridCustUserUnbind> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DrawGridCustUserUnbind::getCustId, unbindUserDTO.getCustId())
                .eq(DrawGridCustUserUnbind::getGridId, unbindUserDTO.getGridId())
                .eq(DrawGridCustUserUnbind::getUserName, unbindUserDTO.getUserName());
        DrawGridCustUserUnbind prev = drawGridCustUserUnbindMapper.selectOne(queryWrapper);
        if (Objects.nonNull(prev)) {
            drawGridCustUserUnbindMapper.deleteById(prev);
            return "重新关联成功";
        } else {
            DrawGridCustUserUnbind drawGridCustUserUnbind = new DrawGridCustUserUnbind();
            BeanUtils.copyProperties(unbindUserDTO, drawGridCustUserUnbind);
            drawGridCustUserUnbindMapper.insert(drawGridCustUserUnbind);
            return "解绑成功";
        }
    }


}
