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

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.*;
import static com.yhy.module.core.enums.ErrorCodeConstants.*;

import cn.hutool.core.collection.CollUtil;
import com.yhy.module.core.controller.admin.workbench.vo.WbProjectTreeRespVO;
import com.yhy.module.core.controller.admin.workbench.vo.WbProjectTreeSaveReqVO;
import com.yhy.module.core.controller.admin.workbench.vo.WbProjectTreeSwapSortReqVO;
import com.yhy.module.core.convert.workbench.WbProjectConvert;
import com.yhy.module.core.dal.dataobject.config.ConfigProjectTreeDO;
import com.yhy.module.core.dal.dataobject.infoprice.InfoPriceBookDO;
import com.yhy.module.core.dal.dataobject.infoprice.InfoPriceTreeDO;
import com.yhy.module.core.dal.dataobject.workbench.WbProjectTreeDO;
import com.yhy.module.core.dal.mysql.config.ConfigProjectTreeMapper;
import com.yhy.module.core.dal.mysql.infoprice.InfoPriceBookMapper;
import com.yhy.module.core.dal.mysql.infoprice.InfoPriceTreeMapper;
import com.yhy.module.core.dal.mysql.workbench.WbProjectTreeMapper;
import com.yhy.module.core.service.workbench.WbProjectService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
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 WbProjectServiceImpl implements WbProjectService {

    @Resource
    private WbProjectTreeMapper wbProjectTreeMapper;

    @Resource
    private ConfigProjectTreeMapper configProjectTreeMapper;

    @Resource
    private InfoPriceTreeMapper infoPriceTreeMapper;

    @Resource
    private InfoPriceBookMapper infoPriceBookMapper;

    @Resource
    private com.yhy.module.core.dal.mysql.workbench.WbCompileTreeMapper wbCompileTreeMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createNode(WbProjectTreeSaveReqVO createReqVO) {
        // 1. 校验节点类型
        validateNodeType(createReqVO.getNodeType());
        
        // 2. 校验父节点
        if (createReqVO.getParentId() != null) {
            WbProjectTreeDO parent = validateParentExists(createReqVO.getParentId());
            // 只有目录节点才能添加子节点
            if (!WbProjectTreeDO.NODE_TYPE_DIRECTORY.equals(parent.getNodeType())) {
                throw exception(WB_PROJECT_PARENT_NOT_DIRECTORY);
            }
        }
        
        // 3. 如果是项目节点，校验项目编号唯一性
        if (WbProjectTreeDO.NODE_TYPE_PROJECT.equals(createReqVO.getNodeType())) {
            if (createReqVO.getProjectCode() != null) {
                validateProjectCodeUnique(createReqVO.getProjectCode(), null);
            }
        }

        // 4. 构建DO
        WbProjectTreeDO node = WbProjectConvert.INSTANCE.convert(createReqVO);
        
        // 5. 设置排序号（支持上方/下方插入）
        Integer sortOrder = calculateSortOrder(createReqVO);
        node.setSortOrder(sortOrder);
        
        // 6. 设置路径
        node.setPath(buildPath(createReqVO.getParentId()));
        
        // 7. 如果是项目节点，设置默认状态和快照
        if (WbProjectTreeDO.NODE_TYPE_PROJECT.equals(createReqVO.getNodeType())) {
            node.setStatus(WbProjectTreeDO.STATUS_DRAFT);
            
            // 设置信息价路径
            setInfoPricePaths(node, createReqVO);
            
            // 构建快照
            node.setSnapshotJson(buildSnapshot(createReqVO));
        }

        // 8. 插入数据库
        wbProjectTreeMapper.insert(node);
        
        // 9. 更新路径（包含自身ID）
        updatePathWithSelfId(node);

        return node.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateNode(WbProjectTreeSaveReqVO updateReqVO) {
        // 1. 校验存在
        WbProjectTreeDO existNode = validateNodeExists(updateReqVO.getId());
        
        // 2. 不允许修改节点类型
        if (!existNode.getNodeType().equals(updateReqVO.getNodeType())) {
            throw exception(WB_PROJECT_NODE_TYPE_CANNOT_CHANGE);
        }
        
        // 3. 如果是项目节点，校验项目编号唯一性
        if (WbProjectTreeDO.NODE_TYPE_PROJECT.equals(updateReqVO.getNodeType())) {
            if (updateReqVO.getProjectCode() != null) {
                validateProjectCodeUnique(updateReqVO.getProjectCode(), updateReqVO.getId());
            }
        }

        // 4. 更新
        WbProjectTreeDO updateObj = WbProjectConvert.INSTANCE.convert(updateReqVO);
        wbProjectTreeMapper.updateById(updateObj);
        
        // 5. 如果是项目节点且名称有变化，同步更新编制树的根节点名称
        if (WbProjectTreeDO.NODE_TYPE_PROJECT.equals(updateReqVO.getNodeType()) 
                && updateReqVO.getName() != null 
                && !updateReqVO.getName().equals(existNode.getName())) {
            syncCompileTreeRootName(updateReqVO.getId(), updateReqVO.getName());
        }
    }
    
    /**
     * 同步编制树根节点名称
     */
    private void syncCompileTreeRootName(Long projectId, String newName) {
        com.yhy.module.core.dal.dataobject.workbench.WbCompileTreeDO root = 
                wbCompileTreeMapper.selectRootByProjectId(projectId);
        if (root != null) {
            root.setName(newName);
            wbCompileTreeMapper.updateById(root);
        }
    }

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

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

    @Override
    public WbProjectTreeRespVO getNode(Long id) {
        WbProjectTreeDO node = wbProjectTreeMapper.selectById(id);
        if (node == null) {
            return null;
        }
        
        WbProjectTreeRespVO respVO = WbProjectConvert.INSTANCE.convert(node);
        
        // 如果是项目节点，填充关联名称
        if (WbProjectTreeDO.NODE_TYPE_PROJECT.equals(node.getNodeType())) {
            fillRelatedNames(respVO, node);
        }
        
        return respVO;
    }

    @Override
    public List<WbProjectTreeRespVO> getTree() {
        List<WbProjectTreeDO> list = wbProjectTreeMapper.selectAllOrderBySortOrder();
        return buildTree(list);
    }

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

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

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void archiveProject(Long id) {
        // 1. 校验存在且是项目节点
        WbProjectTreeDO node = validateNodeExists(id);
        if (!WbProjectTreeDO.NODE_TYPE_PROJECT.equals(node.getNodeType())) {
            throw exception(WB_PROJECT_NOT_PROJECT_NODE);
        }
        
        // 2. 更新状态为已归档
        node.setStatus(WbProjectTreeDO.STATUS_ARCHIVED);
        wbProjectTreeMapper.updateById(node);
    }

    /**
     * 校验节点类型
     */
    private void validateNodeType(String nodeType) {
        if (!WbProjectTreeDO.NODE_TYPE_DIRECTORY.equals(nodeType) 
                && !WbProjectTreeDO.NODE_TYPE_PROJECT.equals(nodeType)) {
            throw exception(WB_PROJECT_NODE_TYPE_INVALID);
        }
    }

    /**
     * 校验父节点存在
     */
    private WbProjectTreeDO validateParentExists(Long parentId) {
        WbProjectTreeDO parent = wbProjectTreeMapper.selectById(parentId);
        if (parent == null) {
            throw exception(WB_PROJECT_PARENT_NOT_EXISTS);
        }
        return parent;
    }

    /**
     * 校验项目编号唯一性
     */
    private void validateProjectCodeUnique(String projectCode, Long selfId) {
        WbProjectTreeDO existNode = wbProjectTreeMapper.selectByProjectCode(projectCode);
        if (existNode != null && !existNode.getId().equals(selfId)) {
            throw exception(WB_PROJECT_CODE_EXISTS);
        }
    }

    /**
     * 校验节点存在
     */
    private WbProjectTreeDO validateNodeExists(Long id) {
        WbProjectTreeDO node = wbProjectTreeMapper.selectById(id);
        if (node == null) {
            throw exception(WB_PROJECT_NOT_EXISTS);
        }
        return node;
    }

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

    /**
     * 设置信息价路径
     */
    private void setInfoPricePaths(WbProjectTreeDO node, WbProjectTreeSaveReqVO reqVO) {
        if (reqVO.getInfoPriceProfessionId() != null) {
            InfoPriceTreeDO professionNode = infoPriceTreeMapper.selectById(reqVO.getInfoPriceProfessionId());
            if (professionNode != null && professionNode.getPath() != null) {
                node.setInfoPriceProfessionPath(convertPathToLongArray(professionNode.getPath()));
            }
        }
        if (reqVO.getInfoPriceRegionId() != null) {
            InfoPriceTreeDO regionNode = infoPriceTreeMapper.selectById(reqVO.getInfoPriceRegionId());
            if (regionNode != null && regionNode.getPath() != null) {
                node.setInfoPriceRegionPath(convertPathToLongArray(regionNode.getPath()));
            }
        }
    }

    /**
     * 计算排序号（支持上方/下方插入）
     * @param reqVO 创建请求
     * @return 排序号
     */
    private Integer calculateSortOrder(WbProjectTreeSaveReqVO reqVO) {
        String insertPosition = reqVO.getInsertPosition();
        Long referenceNodeId = reqVO.getReferenceNodeId();
        
        // 默认尾部插入
        if (insertPosition == null || WbProjectTreeSaveReqVO.INSERT_POSITION_END.equals(insertPosition) 
                || referenceNodeId == null) {
            Integer maxSortOrder = wbProjectTreeMapper.selectMaxSortOrderByParentId(reqVO.getParentId());
            return maxSortOrder + 1;
        }
        
        // 获取参考节点
        WbProjectTreeDO referenceNode = wbProjectTreeMapper.selectById(referenceNodeId);
        if (referenceNode == null) {
            Integer maxSortOrder = wbProjectTreeMapper.selectMaxSortOrderByParentId(reqVO.getParentId());
            return maxSortOrder + 1;
        }
        
        Integer targetSortOrder;
        if (WbProjectTreeSaveReqVO.INSERT_POSITION_ABOVE.equals(insertPosition)) {
            // 上方插入：使用参考节点的排序号
            targetSortOrder = referenceNode.getSortOrder();
        } else {
            // 下方插入：使用参考节点排序号 + 1
            targetSortOrder = referenceNode.getSortOrder() + 1;
        }
        
        // 将目标位置及之后的节点排序号都加1
        List<WbProjectTreeDO> nodesToShift = wbProjectTreeMapper.selectListByParentIdAndSortOrderGe(
                referenceNode.getParentId(), targetSortOrder);
        for (WbProjectTreeDO nodeToShift : nodesToShift) {
            nodeToShift.setSortOrder(nodeToShift.getSortOrder() + 1);
            wbProjectTreeMapper.updateById(nodeToShift);
        }
        
        return targetSortOrder;
    }

    /**
     * 构建快照数据
     */
    private Map<String, Object> buildSnapshot(WbProjectTreeSaveReqVO reqVO) {
        Map<String, Object> snapshot = new HashMap<>();
        snapshot.put("snapshotTime", System.currentTimeMillis());
        
        if (reqVO.getIndustryProvinceId() != null) {
            ConfigProjectTreeDO provinceNode = configProjectTreeMapper.selectById(reqVO.getIndustryProvinceId());
            if (provinceNode != null) {
                snapshot.put("industryProvinceName", provinceNode.getName());
                snapshot.put("industryProvinceCode", provinceNode.getCode());
            }
        }
        if (reqVO.getIndustryId() != null) {
            ConfigProjectTreeDO industryNode = configProjectTreeMapper.selectById(reqVO.getIndustryId());
            if (industryNode != null) {
                snapshot.put("industryName", industryNode.getName());
                snapshot.put("industryCode", industryNode.getCode());
            }
        }
        if (reqVO.getInfoPriceBookId() != null) {
            InfoPriceBookDO book = infoPriceBookMapper.selectById(reqVO.getInfoPriceBookId());
            if (book != null) {
                snapshot.put("infoPriceBookName", book.getName());
                snapshot.put("infoPriceBookVersion", book.getCatalogVersion());
            }
        }
        // 存储信息价专业字典值
        if (reqVO.getInfoPriceProfessionType() != null) {
            snapshot.put("infoPriceProfessionType", reqVO.getInfoPriceProfessionType());
        }
        
        return snapshot;
    }

    /**
     * 填充关联名称
     */
    private void fillRelatedNames(WbProjectTreeRespVO respVO, WbProjectTreeDO node) {
        if (node.getIndustryProvinceId() != null) {
            ConfigProjectTreeDO provinceNode = configProjectTreeMapper.selectById(node.getIndustryProvinceId());
            if (provinceNode != null) {
                respVO.setIndustryProvinceName(provinceNode.getName());
            }
        }
        if (node.getIndustryId() != null) {
            ConfigProjectTreeDO industryNode = configProjectTreeMapper.selectById(node.getIndustryId());
            if (industryNode != null) {
                respVO.setIndustryName(industryNode.getName());
            }
        }
        if (node.getInfoPriceProfessionId() != null) {
            InfoPriceTreeDO professionNode = infoPriceTreeMapper.selectById(node.getInfoPriceProfessionId());
            if (professionNode != null) {
                respVO.setInfoPriceProfessionName(professionNode.getName());
            }
        }
        // 如果没有infoPriceProfessionId，尝试从快照读取专业类型
        if (respVO.getInfoPriceProfessionName() == null && node.getSnapshotJson() != null) {
            Object professionType = node.getSnapshotJson().get("infoPriceProfessionType");
            if (professionType != null) {
                // 返回字典值，前端通过字典转换为中文名称
                respVO.setInfoPriceProfessionName(String.valueOf(professionType));
            }
        }
        if (node.getInfoPriceRegionId() != null) {
            InfoPriceTreeDO regionNode = infoPriceTreeMapper.selectById(node.getInfoPriceRegionId());
            if (regionNode != null) {
                respVO.setInfoPriceRegionName(regionNode.getName());
            }
        }
        if (node.getInfoPriceBookId() != null) {
            InfoPriceBookDO book = infoPriceBookMapper.selectById(node.getInfoPriceBookId());
            if (book != null) {
                respVO.setInfoPriceBookName(book.getName());
            }
        }
    }

    /**
     * 将String[]路径转换为Long[]
     */
    private Long[] convertPathToLongArray(String[] path) {
        if (path == null) {
            return null;
        }
        Long[] result = new Long[path.length];
        for (int i = 0; i < path.length; i++) {
            result[i] = Long.parseLong(path[i]);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveToHistoryLibrary(Long projectId) {
        // 1. 校验项目存在且为项目节点
        WbProjectTreeDO project = validateNodeExists(projectId);
        if (!WbProjectTreeDO.NODE_TYPE_PROJECT.equals(project.getNodeType())) {
            throw exception(WB_PROJECT_NOT_PROJECT_NODE);
        }
        // 2. 更新为已保存至历史库
        project.setInHistoryLibrary(true);
        wbProjectTreeMapper.updateById(project);
        log.info("[saveToHistoryLibrary] 项目已保存至历史库, projectId={}", projectId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeFromHistoryLibrary(Long projectId) {
        // 1. 校验项目存在且为项目节点
        WbProjectTreeDO project = validateNodeExists(projectId);
        if (!WbProjectTreeDO.NODE_TYPE_PROJECT.equals(project.getNodeType())) {
            throw exception(WB_PROJECT_NOT_PROJECT_NODE);
        }
        // 2. 更新为从历史库撤销
        project.setInHistoryLibrary(false);
        wbProjectTreeMapper.updateById(project);
        log.info("[removeFromHistoryLibrary] 项目已从历史库撤销, projectId={}", projectId);
    }

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

        // 转换为VO并填充关联名称
        List<WbProjectTreeRespVO> voList = list.stream()
                .map(node -> {
                    WbProjectTreeRespVO vo = WbProjectConvert.INSTANCE.convert(node);
                    // 如果是项目节点，填充关联名称
                    if (WbProjectTreeDO.NODE_TYPE_PROJECT.equals(node.getNodeType())) {
                        fillRelatedNames(vo, node);
                    }
                    return vo;
                })
                .collect(Collectors.toList());

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

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

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