/*
 * Copyright (c) 2024 codvision.com All Rights Reserved.
 */

package com.codvision.basic.service.impl;

import cn.hutool.core.util.ReUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.codvision.authcore.bean.SysUserBean;
import com.codvision.authcore.util.AuthUtil;
import com.codvision.basic.entity.Address;
import com.codvision.basic.entity.PersonAddressRelation;
import com.codvision.basic.entity.inspection.InspectionTarget;
import com.codvision.basic.entity.inspection.InspectionTask;
import com.codvision.basic.entity.vo.AddressVO;
import com.codvision.basic.entity.vo.BatchAddressVO;
import com.codvision.basic.mapper.AddressMapper;
import com.codvision.basic.mapper.PersonAddressRelationMapper;
import com.codvision.basic.mapper.inspection.InspectionTargetMapper;
import com.codvision.basic.mapper.inspection.InspectionTaskMapper;
import com.codvision.basic.service.AddressService;
import com.codvision.basic.util.AddressCheckCodeUtil;
import com.codvision.commoncore.exception.BusinessException;
import com.codvision.webcore.bean.QueryPage;
import com.codvision.webcore.util.QueryPageUtil;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;

import static com.codvision.basic.constant.BasicConstant.PATTERN;

/**
 * @author KX
 */
@Service
@RequiredArgsConstructor
public class AddressServiceImpl extends ServiceImpl<AddressMapper, Address> implements AddressService {

    private final PersonAddressRelationMapper relationMapper;
    private final InspectionTargetMapper inspectionTargetMapper;
    private final InspectionTaskMapper inspectionTaskMapper;

    @Override
    @SuppressWarnings("all")
    public IPage<AddressVO> getPageResult(QueryPage<Map<String, Object>> queryPage) {
        SysUserBean currentUser = AuthUtil.getCurrentUser();
        Map<String, Object> paraMap = QueryPageUtil.queryMap(queryPage);
        if (!paraMap.containsKey("oid") || paraMap.get("oid") == null) {
            paraMap.put("oid", currentUser.getActiveOid());
        }

        return getBaseMapper().getPageResult(queryPage.getPage(), paraMap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(Address address) {
        if (StringUtils.isEmpty(address.getGridCode())) {
            throw new BusinessException("所选组织网格编码为空，请联系管理员完善！");
        }

        int count = getBaseMapper().countBuilding(address);
        if ("4".equals(address.getAddressType()) && count > 0) {
            throw new BusinessException("该组织下此小区/园区地址已存在，请勿重复添加");
        }
        if ("1".equals(address.getAddressType()) && count > 0) {
            throw new BusinessException("该组织下此楼幢地址已存在，请勿重复添加！");
        }
        if ("0".equals(address.getAddressType()) && getBaseMapper().countHouse(address) > 0) {
            throw new BusinessException("该组织下此房屋地址已存在，请勿重复添加！");
        }

        insertAddress(address);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAddress(Address address) {
        int count = getBaseMapper().countBuilding(address);
        if ("4".equals(address.getAddressType()) && count > 0) {
            throw new BusinessException("该组织下此小区/园区地址已存在，请勿重复添加");
        }
        if ("1".equals(address.getAddressType()) && count > 0) {
            throw new BusinessException("该组织下此楼幢地址已存在，不可重复添加！");
        }
        if ("0".equals(address.getAddressType()) && getBaseMapper().countHouse(address) > 0) {
            throw new BusinessException("该组织下此房屋地址已存在，不可重复添加！");
        }
        if (address.getAddressType().compareTo("4") > 0 && count > 0) {
            throw new BusinessException("该组织下此建筑地址已存在，不可重复添加！");
        }
        getAddressSlot(address);
        addInspectionTarget(address);
        getBaseMapper().updateById(address);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addList(BatchAddressVO batchAddressVO) {
        for (Address address : batchAddressVO.getBuildAddressList()) {
            insertAddress(address);
        }

        for (Address address : batchAddressVO.getHouseRoomAddressList()) {
            String buildingCode = getBaseMapper().getBuildingCode(address.getParkCode(), address.getBuildingNumber());
            address.setBuildingCode(buildingCode);
            insertAddress(address);
        }
    }

    @Override
    public AddressVO details(int id) {
        return getBaseMapper().details(id);
    }

    @Override
    @SuppressWarnings("all")
    public IPage<AddressVO> getAddressHouseListByCode(QueryPage<Map<String, Object>> queryPage) {
        Map<String, Object> paraMap = QueryPageUtil.queryMap(queryPage);
        if (!paraMap.containsKey("addressCode") || StringUtils.isBlank((String) paraMap.get("addressCode"))) {
            throw new BusinessException("地址编码为空，请检查！");
        }
        return getBaseMapper().getAddressHouseListByCode(queryPage.getPage(), paraMap);
    }

    @Override
    @SuppressWarnings("all")
    public IPage<AddressVO> getAddressBuildingListByCode(QueryPage<Map<String, Object>> queryPage) {
        Map<String, Object> paraMap = QueryPageUtil.queryMap(queryPage);
        if (!paraMap.containsKey("addressCode") || StringUtils.isBlank((String) paraMap.get("addressCode"))) {
            throw new BusinessException("地址编码为空，请检查！");
        }
        return getBaseMapper().getAddressBuildingListByCode(queryPage.getPage(), paraMap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchLogicDel(List<Integer> addressIds) {
        // 删除房屋关联
        for (Integer addressId : addressIds) {
            Address address = getBaseMapper().selectById(addressId);
            if ("4".equals(address.getAddressType())) {
                // 删除小区下户室关联
                List<Integer> addressIdList = getBaseMapper().getAddressIdList(null, address.getParkCode());
                if (CollectionUtils.isNotEmpty(addressIdList)) {
                    relationMapper.deleteBatchIds(addressIdList);
                }

                // 删除小区下楼幢和户室
               getBaseMapper().delete(Wrappers.<Address>lambdaQuery().eq(Address::getParkCode, address.getParkCode()));
            } else if ("1".equals(address.getAddressType())) {
                // 删除楼幢下户室的关联
                List<Integer> addressIdList = getBaseMapper().getAddressIdList(address.getBuildingCode(), null);
                if (CollectionUtils.isNotEmpty(addressIdList)) {
                    relationMapper.deleteBatchIds(addressIdList);
                }

                // 如果是楼幢地址同步删除楼幢下户室
                getBaseMapper().delete(Wrappers.<Address>lambdaQuery().eq(Address::getBuildingCode, address.getBuildingCode()));
            } else {
                relationMapper.delete(Wrappers.<PersonAddressRelation>lambdaQuery().eq(PersonAddressRelation::getAddressId, addressId));
            }
        }
        getBaseMapper().deleteBatchIds(addressIds);
    }

    public void insertAddress(Address address) {
        // 获取最大编码
        String maxAddressCode = getBaseMapper().getMaxAddressCode(address);
        // 获取新编码
        String addressCode = getAddressCode(address, maxAddressCode);
        if ("4".equals(address.getAddressType())) {
            address.setParkCode(addressCode);
        } else if ("1".equals(address.getAddressType())) {
            address.setBuildingCode(addressCode);
        }
        address.setAddressCode(addressCode);
        getAddressSlot(address);
        addInspectionTarget(address);
        getBaseMapper().insert(address);
    }

    /**
     * 获取地址房屋索引
     * @param address 地址信息
     */
    private void getAddressSlot(Address address) {
        if ("0".equals(address.getAddressType())) {
            // 获取单元、楼层、房间号中的数字类型字符串作为索引
            address.setUnitSlot(ReUtil.getGroup0(PATTERN, address.getUnit()));
            address.setFloorSlot(ReUtil.getGroup0(PATTERN, address.getFloor()));
            address.setRoomSlot(ReUtil.getGroup0(PATTERN, address.getRoom()));
        }
    }

    /**
     * 获取下一个地址信息
     *
     * @param address        地址信息
     * @param maxAddressCode 最大地址编码
     * @return String
     */
    private String getAddressCode(Address address, String maxAddressCode) {
        // 小区(室外)、楼幢五位顺序位，户室六位顺序位
        int number;
        // 网格/楼幢编码
        StringBuilder addressCode;
        if ("1".equals(address.getAddressType())) {
            addressCode = new StringBuilder(address.getGridCode());
            if (StringUtils.isEmpty(maxAddressCode)) {
                number = 1;
            } else {
                // 如果在楼幢5位顺序码上加一。
                String str = maxAddressCode.substring(maxAddressCode.length() - 6, maxAddressCode.length() - 1);
                number = Integer.parseInt(str) + 1;
            }
            addressCode.append(String.format("%05d", number));
        } else if("0".equals(address.getAddressType())){
            // 去除楼幢编码最后一位校验位
            addressCode = new StringBuilder(address.getBuildingCode());
            addressCode.deleteCharAt(addressCode.length() -1);
            if (StringUtils.isEmpty(maxAddressCode)) {
                number = 1;
            } else {
                String str = maxAddressCode.substring(maxAddressCode.length() - 7, maxAddressCode.length() - 1);
                number = Integer.parseInt(str) + 1;
            }
            // 楼幢编码为6位顺序码
            addressCode.append(String.format("%06d", number));
        } else {
            /*
                社会治理要素统一地址规范：室外地址编码规范为50001-99999
                小区地址编码顺序位为：40001-49999
             */
            addressCode = new StringBuilder(address.getGridCode());
            if (StringUtils.isEmpty(maxAddressCode)) {
                number = 1;
            } else {
                String str = maxAddressCode.substring(maxAddressCode.length() - 5, maxAddressCode.length() - 1);
                number = Integer.parseInt(str) + 1;
            }
            addressCode.append(address.getAddressType()).append(String.format("%04d", number));
        }
        return AddressCheckCodeUtil.getAddressCode(addressCode.toString());
    }

    /**
     * 断是否新增检查对象
     * @param address 地址信息
     */
    private void addInspectionTarget(Address address) {
        if (StringUtils.isEmpty(address.getAddressTags())) {
            return;
        }
        for (InspectionTask inspectionTask : inspectionTaskMapper.getTaskByCheckTag("ADDRESS", address.getAddressTags())) {
            InspectionTarget exist = inspectionTargetMapper.selectOne(Wrappers.<InspectionTarget>lambdaQuery().eq(InspectionTarget::getTargetCode, address.getAddressCode()).eq(InspectionTarget::getTaskId, inspectionTask.getId()));
            if (exist == null) {
                InspectionTarget inspectionTarget = new InspectionTarget();
                inspectionTarget = updateInspectionTarget(inspectionTarget, address);
                inspectionTarget.setTaskId(inspectionTask.getId());
                inspectionTargetMapper.insert(inspectionTarget);
            } else {
                exist = updateInspectionTarget(exist, address);
                exist.setTaskId(inspectionTask.getId());
                inspectionTargetMapper.updateById(exist);
            }
        }
    }

    private InspectionTarget updateInspectionTarget(InspectionTarget inspectionTarget, Address address) {
        inspectionTarget.setFlagActive(1);
        inspectionTarget.setCategory("ADDRESS");
        inspectionTarget.setDataSource("1");
        inspectionTarget.setTargetName(address.getSourceAddress());
        inspectionTarget.setTargetAddress(address.getSourceAddress());
        inspectionTarget.setTargetCode(address.getAddressCode());
        inspectionTarget.setTargetAlias(address.getSourceAddress());
        inspectionTarget.setOid(address.getOid());
        inspectionTarget.setRemark(address.getRemark());
        inspectionTarget.setTagIdList(address.getAddressTags());
        return inspectionTarget;
    }
}
