package com.yhy.module.core.service.config.impl;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_CODE_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_HAS_CHILDREN;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_INDUSTRY_PARENT_INVALID;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_INDUSTRY_PARENT_REQUIRED;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_NODE_TYPE_CANNOT_CHANGE;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_NODE_TYPE_INVALID;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_NOT_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_NOT_SAME_LEVEL;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_PARENT_NOT_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_PROVINCE_PARENT_INVALID;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_PROVINCE_PARENT_REQUIRED;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_ROOT_ONLY_ONE;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_ROOT_PARENT_MUST_NULL;

import cn.hutool.core.collection.CollUtil;
import com.yhy.module.core.controller.admin.config.vo.ConfigProjectTreeRespVO;
import com.yhy.module.core.controller.admin.config.vo.ConfigProjectTreeSaveReqVO;
import com.yhy.module.core.controller.admin.config.vo.ConfigProjectTreeSwapSortReqVO;
import com.yhy.module.core.convert.config.ConfigProjectTreeConvert;
import com.yhy.module.core.dal.dataobject.config.ConfigProjectTreeDO;
import com.yhy.module.core.dal.mysql.config.ConfigProjectTreeMapper;
import com.yhy.module.core.service.config.ConfigProjectTreeService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

/**
 * 项目界面配置树 Service 实现类
 *
 * @author yhy
 */
@Service
@Validated
@Slf4j
public class ConfigProjectTreeServiceImpl implements ConfigProjectTreeService {

    @Resource
    private ConfigProjectTreeMapper configProjectTreeMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createConfigProjectTree(ConfigProjectTreeSaveReqVO createReqVO) {
        // 1. 校验节点类型和父节点
        validateNodeTypeAndParent(createReqVO.getNodeType(), createReqVO.getParentId(), null);
        
        // 2. 校验编码唯一性
        validateCodeUnique(createReqVO.getCode(), null);

        // 3. 构建DO
        ConfigProjectTreeDO configProjectTree = ConfigProjectTreeConvert.INSTANCE.convert(createReqVO);
        
        // 4. 设置排序号
        Integer maxSortOrder = configProjectTreeMapper.selectMaxSortOrderByParentId(createReqVO.getParentId());
        configProjectTree.setSortOrder(maxSortOrder + 1);
        
        // 5. 设置路径
        configProjectTree.setPath(buildPath(createReqVO.getParentId()));

        // 6. 插入数据库
        configProjectTreeMapper.insert(configProjectTree);
        
        // 7. 更新路径（包含自身ID）
        updatePathWithSelfId(configProjectTree);

        return configProjectTree.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateConfigProjectTree(ConfigProjectTreeSaveReqVO updateReqVO) {
        // 1. 校验存在
        ConfigProjectTreeDO existNode = validateConfigProjectTreeExists(updateReqVO.getId());
        
        // 2. 校验编码唯一性
        validateCodeUnique(updateReqVO.getCode(), updateReqVO.getId());
        
        // 3. 不允许修改节点类型
        if (!existNode.getNodeType().equals(updateReqVO.getNodeType())) {
            throw exception(CONFIG_PROJECT_TREE_NODE_TYPE_CANNOT_CHANGE);
        }

        // 4. 更新
        ConfigProjectTreeDO updateObj = ConfigProjectTreeConvert.INSTANCE.convert(updateReqVO);
        configProjectTreeMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteConfigProjectTree(Long id) {
        // 1. 校验存在
        validateConfigProjectTreeExists(id);
        
        // 2. 校验是否有子节点
        List<ConfigProjectTreeDO> children = configProjectTreeMapper.selectListByParentId(id);
        if (CollUtil.isNotEmpty(children)) {
            throw exception(CONFIG_PROJECT_TREE_HAS_CHILDREN);
        }

        // 3. 删除
        configProjectTreeMapper.deleteById(id);
    }

    @Override
    public ConfigProjectTreeRespVO getConfigProjectTree(Long id) {
        ConfigProjectTreeDO configProjectTree = configProjectTreeMapper.selectById(id);
        return ConfigProjectTreeConvert.INSTANCE.convert(configProjectTree);
    }

    @Override
    public List<ConfigProjectTreeRespVO> getConfigProjectTreeList() {
        List<ConfigProjectTreeDO> list = configProjectTreeMapper.selectAllOrderBySortOrder();
        return buildTree(list);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(ConfigProjectTreeSwapSortReqVO swapReqVO) {
        // 1. 校验两个节点存在
        ConfigProjectTreeDO node1 = validateConfigProjectTreeExists(swapReqVO.getNodeId1());
        ConfigProjectTreeDO node2 = validateConfigProjectTreeExists(swapReqVO.getNodeId2());
        
        // 2. 校验是否同级
        if (!Objects.equals(node1.getParentId(), node2.getParentId())) {
            throw exception(CONFIG_PROJECT_TREE_NOT_SAME_LEVEL);
        }

        // 3. 交换排序号
        Integer tempSortOrder = node1.getSortOrder();
        node1.setSortOrder(node2.getSortOrder());
        node2.setSortOrder(tempSortOrder);

        configProjectTreeMapper.updateById(node1);
        configProjectTreeMapper.updateById(node2);
    }

    @Override
    public List<ConfigProjectTreeRespVO> getIndustryOptions() {
        // 获取所有省市节点和行业节点
        List<ConfigProjectTreeDO> allNodes = configProjectTreeMapper.selectAllOrderBySortOrder();
        
        // 过滤出省市节点
        List<ConfigProjectTreeDO> provinceNodes = allNodes.stream()
                .filter(node -> ConfigProjectTreeDO.NODE_TYPE_PROVINCE.equals(node.getNodeType()))
                .collect(Collectors.toList());
        
        // 构建省市 -> 行业的两级结构
        List<ConfigProjectTreeRespVO> result = new ArrayList<>();
        for (ConfigProjectTreeDO province : provinceNodes) {
            ConfigProjectTreeRespVO provinceVO = ConfigProjectTreeConvert.INSTANCE.convert(province);
            
            // 获取该省市下的行业节点
            List<ConfigProjectTreeRespVO> industries = allNodes.stream()
                    .filter(node -> ConfigProjectTreeDO.NODE_TYPE_INDUSTRY.equals(node.getNodeType())
                            && Objects.equals(node.getParentId(), province.getId()))
                    .map(ConfigProjectTreeConvert.INSTANCE::convert)
                    .collect(Collectors.toList());
            
            provinceVO.setChildren(industries);
            result.add(provinceVO);
        }
        
        return result;
    }

    /**
     * 校验节点类型和父节点
     */
    private void validateNodeTypeAndParent(String nodeType, Long parentId, Long selfId) {
        if (ConfigProjectTreeDO.NODE_TYPE_ROOT.equals(nodeType)) {
            // 根节点：父节点必须为空，且只能有一个根节点
            if (parentId != null) {
                throw exception(CONFIG_PROJECT_TREE_ROOT_PARENT_MUST_NULL);
            }
            List<ConfigProjectTreeDO> rootNodes = configProjectTreeMapper.selectListByNodeType(ConfigProjectTreeDO.NODE_TYPE_ROOT);
            if (CollUtil.isNotEmpty(rootNodes) && (selfId == null || !rootNodes.get(0).getId().equals(selfId))) {
                throw exception(CONFIG_PROJECT_TREE_ROOT_ONLY_ONE);
            }
        } else if (ConfigProjectTreeDO.NODE_TYPE_PROVINCE.equals(nodeType)) {
            // 省市节点：父节点必须是根节点或省市节点
            if (parentId == null) {
                throw exception(CONFIG_PROJECT_TREE_PROVINCE_PARENT_REQUIRED);
            }
            ConfigProjectTreeDO parent = configProjectTreeMapper.selectById(parentId);
            if (parent == null) {
                throw exception(CONFIG_PROJECT_TREE_PARENT_NOT_EXISTS);
            }
            if (!ConfigProjectTreeDO.NODE_TYPE_ROOT.equals(parent.getNodeType()) 
                    && !ConfigProjectTreeDO.NODE_TYPE_PROVINCE.equals(parent.getNodeType())) {
                throw exception(CONFIG_PROJECT_TREE_PROVINCE_PARENT_INVALID);
            }
        } else if (ConfigProjectTreeDO.NODE_TYPE_INDUSTRY.equals(nodeType)) {
            // 行业节点：父节点必须是省市节点
            if (parentId == null) {
                throw exception(CONFIG_PROJECT_TREE_INDUSTRY_PARENT_REQUIRED);
            }
            ConfigProjectTreeDO parent = configProjectTreeMapper.selectById(parentId);
            if (parent == null) {
                throw exception(CONFIG_PROJECT_TREE_PARENT_NOT_EXISTS);
            }
            if (!ConfigProjectTreeDO.NODE_TYPE_PROVINCE.equals(parent.getNodeType())) {
                throw exception(CONFIG_PROJECT_TREE_INDUSTRY_PARENT_INVALID);
            }
        } else {
            throw exception(CONFIG_PROJECT_TREE_NODE_TYPE_INVALID);
        }
    }

    /**
     * 校验编码唯一性
     */
    private void validateCodeUnique(String code, Long selfId) {
        ConfigProjectTreeDO existNode = configProjectTreeMapper.selectByCode(code);
        if (existNode != null && !existNode.getId().equals(selfId)) {
            throw exception(CONFIG_PROJECT_TREE_CODE_EXISTS);
        }
    }

    /**
     * 校验节点存在
     */
    private ConfigProjectTreeDO validateConfigProjectTreeExists(Long id) {
        ConfigProjectTreeDO configProjectTree = configProjectTreeMapper.selectById(id);
        if (configProjectTree == null) {
            throw exception(CONFIG_PROJECT_TREE_NOT_EXISTS);
        }
        return configProjectTree;
    }

    /**
     * 构建路径
     */
    private String[] buildPath(Long parentId) {
        if (parentId == null) {
            return new String[]{};
        }
        ConfigProjectTreeDO parent = configProjectTreeMapper.selectById(parentId);
        if (parent == null || parent.getPath() == null) {
            return new String[]{String.valueOf(parentId)};
        }
        List<String> pathList = new ArrayList<>(Arrays.asList(parent.getPath()));
        pathList.add(String.valueOf(parentId));
        return pathList.toArray(new String[0]);
    }

    /**
     * 更新路径（包含自身ID）
     */
    private void updatePathWithSelfId(ConfigProjectTreeDO node) {
        List<String> pathList = node.getPath() != null ? new ArrayList<>(Arrays.asList(node.getPath())) : new ArrayList<>();
        pathList.add(String.valueOf(node.getId()));
        node.setPath(pathList.toArray(new String[0]));
        configProjectTreeMapper.updateById(node);
    }

    /**
     * 构建树形结构
     */
    private List<ConfigProjectTreeRespVO> buildTree(List<ConfigProjectTreeDO> list) {
        if (CollUtil.isEmpty(list)) {
            return Collections.emptyList();
        }

        // 转换为VO
        List<ConfigProjectTreeRespVO> voList = list.stream()
                .map(ConfigProjectTreeConvert.INSTANCE::convert)
                .collect(Collectors.toList());

        // 构建父子关系
        Map<Long, List<ConfigProjectTreeRespVO>> parentIdMap = voList.stream()
                .filter(vo -> vo.getParentId() != null)
                .collect(Collectors.groupingBy(ConfigProjectTreeRespVO::getParentId));

        voList.forEach(vo -> vo.setChildren(parentIdMap.get(vo.getId())));

        // 返回根节点
        return voList.stream()
                .filter(vo -> vo.getParentId() == null)
                .collect(Collectors.toList());
    }
}
