package com.ruoyi.ibs.grid.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.customerselect.service.IMyCustomerService;
import com.ruoyi.ibs.grid.domain.dto.RegionDataRemarkDTO;
import com.ruoyi.ibs.grid.domain.dto.RegionDataSelectDTO;
import com.ruoyi.ibs.grid.domain.entity.*;
import com.ruoyi.ibs.grid.domain.vo.GridRegionVO;
import com.ruoyi.ibs.grid.domain.vo.RegionDataVO;
import com.ruoyi.ibs.grid.domain.vo.RegionMapVO;
import com.ruoyi.ibs.grid.mapper.*;
import com.ruoyi.ibs.grid.service.AddressAnalyseService;
import com.ruoyi.ibs.grid.service.GridAreaFenceService;
import com.ruoyi.ibs.grid.service.RegionDataService;
import lombok.extern.slf4j.Slf4j;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.Polygon;
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/10/14
 **/
@Service
@Slf4j
public class RegionDataServiceImpl implements RegionDataService {

    @Resource
    private DeptRegionRelateMapper regionRelateMapper;

    @Resource
    private AdminDivisionMapper adminDivisionMapper;

    @Resource
    private AddressAnalyseService adminDivisionService;

    @Resource
    private RegionDataRemarkMapper regionDataRemarkMapper;

    @Resource
    private IMyCustomerService myCustomerService;

    @Resource
    private GridAreaFenceService gridAreaFenceService;

    @Resource
    private RegionGridMapper regionGridMapper;

    @Resource
    private RegionUserRelateMapper regionUserRelateMapper;

    @Resource
    private RegionAdminDivisionRelateMapper regionAdminDivisionRelateMapper;

    @Resource
    private RedisCache redisCache;

    private final String regionRetailCountRedisKey = "REGION_RETAIL_COUNT_";

    private final String regionBusinessCountRedisKey = "REGION_BUSINESS_COUNT_";

    private final String regionMerchantCountRedisKey = "REGION_MERCHANT_COUNT_";

    /**
     * 总行根据地理绑定关系获取行政区划
     * @return
     */
    @Override
    public List<String> getRegionListByHead() {
        Long deptId = SecurityUtils.getDeptId();
        LambdaQueryWrapper<DeptRegionRelate> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(DeptRegionRelate::getDeptId, deptId);
        List<DeptRegionRelate> deptRegionRelates = regionRelateMapper.selectList(queryWrapper);
        if (Objects.isNull(deptRegionRelates) || deptRegionRelates.isEmpty()) {
            throw new ServiceException("该机构未绑定行政区划！");
        }
        return deptRegionRelates.stream().map(DeptRegionRelate::getRegionCode).collect(Collectors.toList());
    }

    /**
     * 支行根据一级网格指定的行政区划管护关系获取行政区划
     *
     * @return
     */
    @Override
    public List<String> getRegionDataListByBranch() {
        Long deptId = SecurityUtils.getDeptId();
        LambdaQueryWrapper<RegionUserRelate> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RegionUserRelate::getRelateType, "2")
                .eq(RegionUserRelate::getRelateDeptId, deptId);
        List<Long> gridIds = regionUserRelateMapper.selectList(queryWrapper).stream().map(RegionUserRelate::getGridId).collect(Collectors.toList());
        if (gridIds.isEmpty()) {
            return null;
        }
        LambdaQueryWrapper<RegionAdminDivisionRelate> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.in(RegionAdminDivisionRelate::getGridId, gridIds);
        return regionAdminDivisionRelateMapper.selectList(queryWrapper1).stream().map(RegionAdminDivisionRelate::getCode).distinct().collect(Collectors.toList());
    }

    /**
     * 客户经理根据二级网格指定的行政区划管护关系获取行政区划数据
     *
     * @return
     */
    @Override
    public List<String> getRegionDataListByManager() {
        String username = SecurityUtils.getUsername();
        LambdaQueryWrapper<RegionUserRelate> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RegionUserRelate::getRelateType, "1")
                .eq(RegionUserRelate::getUserName, username);
        List<Long> gridIds = regionUserRelateMapper.selectList(queryWrapper).stream().map(RegionUserRelate::getGridId).collect(Collectors.toList());
        if (gridIds.isEmpty()) {
            return null;
        }
        LambdaQueryWrapper<RegionAdminDivisionRelate> queryWrapper1 = new LambdaQueryWrapper<>();
        queryWrapper1.in(RegionAdminDivisionRelate::getGridId, gridIds);
        return regionAdminDivisionRelateMapper.selectList(queryWrapper1).stream().map(RegionAdminDivisionRelate::getCode).distinct().collect(Collectors.toList());
    }

    /**
     * @return
     */
    @Override
    public List<RegionDataVO> getRegionDataList(RegionDataSelectDTO regionDataSelectDTO, List<String> regionList) {

        LambdaQueryWrapper<AdminDivision> queryWrapper1 = new LambdaQueryWrapper<>();
        if (Objects.nonNull(regionDataSelectDTO.getCode())) {
            if (regionDataSelectDTO.isCode()) {
                queryWrapper1.like(AdminDivision::getCode, regionDataSelectDTO.getCode());
            } else {
                queryWrapper1.like(AdminDivision::getLabel, regionDataSelectDTO.getCode());
            }
        }
        if (Objects.nonNull(regionList) && !regionList.isEmpty()){
            queryWrapper1.and(i -> {
                regionList.forEach(region -> {
                    i.or().likeRight(AdminDivision::getCode, region);
                });
            });
        }
        queryWrapper1.eq(AdminDivision::getLevel, regionDataSelectDTO.getLevel());

        List<AdminDivision> adminDivisions = adminDivisionMapper.selectList(queryWrapper1);
        return adminDivisions.stream().map(adminDivision -> {
            RegionDataVO regionDataVO = new RegionDataVO();
            BeanUtils.copyProperties(adminDivision, regionDataVO);
            if (adminDivision.getLevel() == 4) {
                regionDataVO.setRegionType("镇级行政区划");
            } else if (adminDivision.getLevel() == 5) {
                regionDataVO.setRegionType("村级行政区划");
            }
            regionDataVO.setRegionCount(getRegionCount(adminDivision.getCode(), adminDivision.getLevel()));
            if (redisCache.hasKey(regionRetailCountRedisKey + adminDivision.getCode())) {
                regionDataVO.setCustRetailCount(redisCache.getCacheObject(regionRetailCountRedisKey + adminDivision.getCode()));
            } else {
                Long count = myCustomerService.countCustRetailByRegion(adminDivision.getCode());
                redisCache.setCacheObjectToEndDay(regionRetailCountRedisKey + adminDivision.getCode(), count);
                regionDataVO.setCustRetailCount(count);
            }
            if (redisCache.hasKey(regionBusinessCountRedisKey + adminDivision.getCode())) {
                regionDataVO.setCustBusinessCount(redisCache.getCacheObject(regionBusinessCountRedisKey + adminDivision.getCode()));
            } else {
                Long count = myCustomerService.countCustBusinessByRegion(adminDivision.getCode());
                redisCache.setCacheObjectToEndDay(regionBusinessCountRedisKey + adminDivision.getCode(), count);
                regionDataVO.setCustBusinessCount(count);
            }
            if (redisCache.hasKey(regionMerchantCountRedisKey + adminDivision.getCode())) {
                regionDataVO.setCustMerchantCount(redisCache.getCacheObject(regionMerchantCountRedisKey + adminDivision.getCode()));
            } else {
                Long count = myCustomerService.countCustMerchantByRegion(adminDivision.getCode());
                redisCache.setCacheObjectToEndDay(regionMerchantCountRedisKey + adminDivision.getCode(), count);
                regionDataVO.setCustMerchantCount(count);
            }
            RegionDataRemark regionDataRemarkByCode = getRegionDataRemarkByCode(adminDivision.getCode());
            if (Objects.nonNull(regionDataRemarkByCode)) {
                regionDataVO.setRemark(regionDataRemarkByCode.getRemark());
            }
            RegionMapVO pointListByCode = adminDivisionService.getPointListByCode(regionDataVO.getCode());
            if (Objects.nonNull(pointListByCode)) {
                regionDataVO.setPolygonList(pointListByCode.getPolygonList());
            }
            return regionDataVO;
        }).collect(Collectors.toList());
    }

    /**
     * @return
     */
    @Override
    public List<RegionDataVO> getRegionDataListByAdmin(RegionDataSelectDTO regionDataSelectDTO) {

        LambdaQueryWrapper<AdminDivision> queryWrapper1 = new LambdaQueryWrapper<>();
        if (Objects.nonNull(regionDataSelectDTO.getCode())) {
            if (regionDataSelectDTO.isCode()) {
                queryWrapper1.like(AdminDivision::getCode, regionDataSelectDTO.getCode());
            } else {
                queryWrapper1.like(AdminDivision::getLabel, regionDataSelectDTO.getCode());
            }
        }
        queryWrapper1.eq(AdminDivision::getLevel, regionDataSelectDTO.getLevel());

        List<AdminDivision> adminDivisions = adminDivisionMapper.selectList(queryWrapper1);
        return adminDivisions.stream().map(adminDivision -> {
            RegionDataVO regionDataVO = new RegionDataVO();
            BeanUtils.copyProperties(adminDivision, regionDataVO);
            if (adminDivision.getLevel() == 4) {
                regionDataVO.setRegionType("镇级行政区划");
            } else if (adminDivision.getLevel() == 5) {
                regionDataVO.setRegionType("村级行政区划");
            }
            regionDataVO.setRegionCount(getRegionCount(adminDivision.getCode(), adminDivision.getLevel()));
            RegionMapVO pointListByCode = adminDivisionService.getPointListByCode(regionDataVO.getCode());
            if (Objects.nonNull(pointListByCode)){
                regionDataVO.setPolygonList(pointListByCode.getPolygonList());
            }
            return regionDataVO;
        }).collect(Collectors.toList());
    }

    @Override
    public String updateRegionRemark(RegionDataRemarkDTO regionDataRemarkDTO) {
        RegionDataRemark regionDataRemark = getRegionDataRemarkByCode(regionDataRemarkDTO.getCode());
        if (Objects.isNull(regionDataRemark)) {
            regionDataRemark = new RegionDataRemark();
            BeanUtils.copyProperties(regionDataRemarkDTO, regionDataRemark);
            regionDataRemarkMapper.insert(regionDataRemark);
        } else {
            BeanUtils.copyProperties(regionDataRemarkDTO, regionDataRemark);
            regionDataRemarkMapper.updateById(regionDataRemark);
        }

        return "备注更新成功！";
    }

    @Override
    public RegionDataRemark getRegionDataRemarkByCode(String code) {
        Long deptId = SecurityUtils.getDeptId();
        LambdaQueryWrapper<RegionDataRemark> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(RegionDataRemark::getDeptId, deptId)
                .eq(RegionDataRemark::getCode, code);
        return regionDataRemarkMapper.selectOne(queryWrapper);
    }

    @Override
    public GridRegionVO getGridRegionFence(Long gridId) {
        GridRegionVO gridRegionVO = new GridRegionVO();
        // 获取网格信息
        RegionGrid regionGrid = regionGridMapper.selectById(gridId);
        gridRegionVO.setGridId(gridId);
        gridRegionVO.setGridName(regionGrid.getGridName());
        Geometry geometry = gridAreaFenceService.getGeometry("1", gridId);
        // 获取围栏坐标
        List<List<Coordinate[]>> polygonList = new ArrayList<>();
        int geoCount = geometry.getNumGeometries();
        for (int i = 0; i < geoCount; i++) {
            List<Coordinate[]> pointList = new ArrayList<>();
            Polygon polygon = (Polygon) geometry.getGeometryN(i);
            pointList.add(polygon.getExteriorRing().getCoordinates());
            if (polygon.getNumInteriorRing() > 0) {
                for (int j = 0; j < polygon.getNumInteriorRing(); j++) {
                    pointList.add(polygon.getInteriorRingN(j).getCoordinates());
                }
            }
            polygonList.add(pointList);
        }
        gridRegionVO.setPolygonList(polygonList);
        return gridRegionVO;
    }

    @Override
    public List<GridRegionVO> queryGridRegionFence(List<Long> gridIds) {
        if (Objects.isNull(gridIds) || gridIds.isEmpty()) {
            return null;
        }
        return gridIds.stream().map(this::getGridRegionFence).collect(Collectors.toList());
    }

    private Long getRegionCount(String code, Integer level) {
        LambdaQueryWrapper<AdminDivision> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(AdminDivision::getCode, code)
                .eq(AdminDivision::getLevel, level + 1);
        return adminDivisionMapper.selectCount(queryWrapper);

    }


}
