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_INFO_HAS_CHILDREN;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_INFO_NOT_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_INFO_NOT_SAME_LEVEL;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_INFO_PARENT_NOT_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_INFO_TREE_NOT_INDUSTRY;
import static com.yhy.module.core.enums.ErrorCodeConstants.CONFIG_PROJECT_TREE_NOT_EXISTS;

import cn.hutool.core.collection.CollUtil;
import com.yhy.module.core.controller.admin.config.vo.ConfigProjectInfoRespVO;
import com.yhy.module.core.controller.admin.config.vo.ConfigProjectInfoSaveReqVO;
import com.yhy.module.core.controller.admin.config.vo.ConfigProjectInfoSwapSortReqVO;
import com.yhy.module.core.convert.config.ConfigProjectInfoConvert;
import com.yhy.module.core.dal.dataobject.config.ConfigProjectInfoDO;
import com.yhy.module.core.dal.dataobject.config.ConfigProjectTreeDO;
import com.yhy.module.core.dal.mysql.config.ConfigProjectInfoMapper;
import com.yhy.module.core.dal.mysql.config.ConfigProjectTreeMapper;
import com.yhy.module.core.service.config.ConfigProjectInfoService;
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 ConfigProjectInfoServiceImpl implements ConfigProjectInfoService {

    @Resource
    private ConfigProjectInfoMapper configProjectInfoMapper;

    @Resource
    private ConfigProjectTreeMapper configProjectTreeMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createConfigProjectInfo(ConfigProjectInfoSaveReqVO createReqVO) {
        // 1. 校验行业节点存在且类型正确
        validateConfigTreeIsIndustry(createReqVO.getConfigTreeId());
        
        // 2. 校验父节点存在
        if (createReqVO.getParentId() != null) {
            validateParentExists(createReqVO.getParentId());
        }

        // 3. 构建DO
        ConfigProjectInfoDO configProjectInfo = ConfigProjectInfoConvert.INSTANCE.convert(createReqVO);
        
        // 4. 设置排序号
        Integer maxSortOrder = configProjectInfoMapper.selectMaxSortOrderByParentId(
                createReqVO.getConfigTreeId(), createReqVO.getParentId());
        configProjectInfo.setSortOrder(maxSortOrder + 1);
        
        // 5. 设置路径
        configProjectInfo.setPath(buildPath(createReqVO.getParentId()));

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

        return configProjectInfo.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateConfigProjectInfo(ConfigProjectInfoSaveReqVO updateReqVO) {
        // 1. 校验存在
        validateConfigProjectInfoExists(updateReqVO.getId());

        // 2. 更新
        ConfigProjectInfoDO updateObj = ConfigProjectInfoConvert.INSTANCE.convert(updateReqVO);
        configProjectInfoMapper.updateById(updateObj);
    }

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

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

    @Override
    public ConfigProjectInfoRespVO getConfigProjectInfo(Long id) {
        ConfigProjectInfoDO configProjectInfo = configProjectInfoMapper.selectById(id);
        return ConfigProjectInfoConvert.INSTANCE.convert(configProjectInfo);
    }

    @Override
    public List<ConfigProjectInfoRespVO> getConfigProjectInfoTree(Long configTreeId) {
        List<ConfigProjectInfoDO> list = configProjectInfoMapper.selectListByConfigTreeId(configTreeId);
        return buildTree(list);
    }

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

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

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

    /**
     * 校验行业节点存在且类型正确
     */
    private void validateConfigTreeIsIndustry(Long configTreeId) {
        ConfigProjectTreeDO treeNode = configProjectTreeMapper.selectById(configTreeId);
        if (treeNode == null) {
            throw exception(CONFIG_PROJECT_TREE_NOT_EXISTS);
        }
        if (!ConfigProjectTreeDO.NODE_TYPE_INDUSTRY.equals(treeNode.getNodeType())) {
            throw exception(CONFIG_PROJECT_INFO_TREE_NOT_INDUSTRY);
        }
    }

    /**
     * 校验父节点存在
     */
    private void validateParentExists(Long parentId) {
        ConfigProjectInfoDO parent = configProjectInfoMapper.selectById(parentId);
        if (parent == null) {
            throw exception(CONFIG_PROJECT_INFO_PARENT_NOT_EXISTS);
        }
    }

    /**
     * 校验节点存在
     */
    private ConfigProjectInfoDO validateConfigProjectInfoExists(Long id) {
        ConfigProjectInfoDO configProjectInfo = configProjectInfoMapper.selectById(id);
        if (configProjectInfo == null) {
            throw exception(CONFIG_PROJECT_INFO_NOT_EXISTS);
        }
        return configProjectInfo;
    }

    /**
     * 构建路径
     */
    private String[] buildPath(Long parentId) {
        if (parentId == null) {
            return new String[]{};
        }
        ConfigProjectInfoDO parent = configProjectInfoMapper.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(ConfigProjectInfoDO 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]));
        configProjectInfoMapper.updateById(node);
    }

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

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

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

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

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