package com.yhy.module.core.service.quota.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 cn.hutool.core.util.ArrayUtil;
import com.yhy.module.core.controller.admin.quota.vo.QuotaCatalogTreeRespVO;
import com.yhy.module.core.controller.admin.quota.vo.QuotaCatalogTreeSaveReqVO;
import com.yhy.module.core.dal.dataobject.quota.QuotaCatalogItemDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaCatalogTreeDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaRateFieldDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaRateItemDO;
import com.yhy.module.core.dal.mysql.quota.QuotaCatalogItemMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaCatalogTreeMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaRateFieldMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaRateItemMapper;
import com.yhy.module.core.service.quota.QuotaCatalogTreeService;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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 QuotaCatalogTreeServiceImpl implements QuotaCatalogTreeService {

    @Resource
    private QuotaCatalogTreeMapper quotaCatalogTreeMapper;

    @Resource
    private QuotaRateItemMapper quotaRateItemMapper;

    @Resource
    private QuotaCatalogItemMapper quotaCatalogItemMapper;

    @Resource
    private QuotaRateFieldMapper rateFieldMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createCatalogTree(QuotaCatalogTreeSaveReqVO createReqVO) {
        // 1. 构建DO对象
        QuotaCatalogTreeDO catalogTree = buildCatalogTreeDO(createReqVO);

        // 2. 设置 allowChildren 和 contentType
        if ("directory".equals(createReqVO.getContentType())) {
            catalogTree.setAllowChildren(true);
        } else if ("content".equals(createReqVO.getContentType())) {
            catalogTree.setAllowChildren(false);
        }

        // 3. 验证父节点（如果有）
        if (createReqVO.getParentId() != null) {
            QuotaCatalogTreeDO parent = quotaCatalogTreeMapper.selectById(createReqVO.getParentId());
            if (parent == null) {
                throw exception(QUOTA_CATALOG_TREE_PARENT_NOT_EXISTS);
            }
            // 校验父节点是否允许添加子节点
            if (!parent.getAllowChildren()) {
                throw exception(QUOTA_CATALOG_TREE_PARENT_NOT_ALLOW_CHILDREN);
            }
        }

        // 4. 设置排序
        if (catalogTree.getSortOrder() == null) {
            catalogTree.setSortOrder(getNextSortOrder(createReqVO.getCatalogItemId(), createReqVO.getParentId()));
        }

        // 5. 插入数据库（先插入以获取ID）
        quotaCatalogTreeMapper.insert(catalogTree);

        // 6. 计算路径和层级（插入后才有ID）
        calculatePathAndLevel(catalogTree, createReqVO.getParentId());
        
        // 7. 更新路径和层级
        quotaCatalogTreeMapper.updateById(catalogTree);

        return catalogTree.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateCatalogTree(QuotaCatalogTreeSaveReqVO updateReqVO) {
        // 1. 校验节点存在
        validateCatalogTreeExists(updateReqVO.getId());

        // 2. 构建更新对象
        QuotaCatalogTreeDO updateObj = QuotaCatalogTreeDO.builder()
                .id(updateReqVO.getId())
                .code(updateReqVO.getCode())
                .name(updateReqVO.getName())
                .unit(updateReqVO.getUnit())
                .sortOrder(updateReqVO.getSortOrder())
                .attributes(updateReqVO.getAttributes())
                .remark(updateReqVO.getRemark())
                .build();

        // 3. 更新数据库
        quotaCatalogTreeMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteCatalogTree(Long id) {
        // 1. 校验节点存在
        validateCatalogTreeExists(id);

        // 2. 校验是否有子节点
        List<QuotaCatalogTreeDO> children = quotaCatalogTreeMapper.selectListByParentId(id);
        if (CollUtil.isNotEmpty(children)) {
            throw exception(QUOTA_CATALOG_TREE_HAS_CHILDREN);
        }

        // 3. 删除节点
        quotaCatalogTreeMapper.deleteById(id);
    }

    @Override
    public QuotaCatalogTreeRespVO getCatalogTree(Long id) {
        QuotaCatalogTreeDO item = quotaCatalogTreeMapper.selectById(id);
        if (item == null) {
            return null;
        }
        return convertToRespVO(item);
    }

    @Override
    public List<QuotaCatalogTreeRespVO> getCatalogTreeList(Long catalogItemId, Long parentId) {
        // 查询指定条件的节点
        List<QuotaCatalogTreeDO> items;
        if (parentId != null) {
            items = quotaCatalogTreeMapper.selectListByParentId(parentId);
        } else {
            items = quotaCatalogTreeMapper.selectListByCatalogItemId(catalogItemId);
        }
        
        return items.stream()
                .map(this::convertToRespVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<QuotaCatalogTreeRespVO> getCatalogTreeTree(Long catalogItemId) {
        // 1. 查询所有节点
        List<QuotaCatalogTreeDO> allItems = quotaCatalogTreeMapper.selectListByCatalogItemId(catalogItemId);

        // 2. 转换为VO
        List<QuotaCatalogTreeRespVO> allVOs = allItems.stream()
                .map(this::convertToRespVO)
                .collect(Collectors.toList());

        // 3. 构建树形结构
        return buildTree(allVOs, null);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(Long nodeId1, Long nodeId2) {
        // 1. 查询两个节点（加锁）
        QuotaCatalogTreeDO node1 = quotaCatalogTreeMapper.selectById(nodeId1);
        QuotaCatalogTreeDO node2 = quotaCatalogTreeMapper.selectById(nodeId2);

        if (node1 == null || node2 == null) {
            throw exception(QUOTA_CATALOG_TREE_NOT_EXISTS);
        }

        // 2. 校验是否同级
        if (!isSameLevel(node1, node2)) {
            throw exception(QUOTA_CATALOG_TREE_NOT_SAME_LEVEL);
        }

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

        // 4. 更新数据库
        quotaCatalogTreeMapper.updateById(node1);
        quotaCatalogTreeMapper.updateById(node2);

        log.info("[swapSort] 交换节点[{}]和节点[{}]的排序成功", nodeId1, nodeId2);
    }

    // ==================== 私有方法 ====================

    /**
     * 校验节点存在
     */
    private QuotaCatalogTreeDO validateCatalogTreeExists(Long id) {
        QuotaCatalogTreeDO item = quotaCatalogTreeMapper.selectById(id);
        if (item == null) {
            throw exception(QUOTA_CATALOG_TREE_NOT_EXISTS);
        }
        return item;
    }

    /**
     * 构建DO对象
     */
    private QuotaCatalogTreeDO buildCatalogTreeDO(QuotaCatalogTreeSaveReqVO reqVO) {
        return QuotaCatalogTreeDO.builder()
                .id(reqVO.getId())
                .catalogItemId(reqVO.getCatalogItemId())
                .parentId(reqVO.getParentId())
                .code(reqVO.getCode())
                .name(reqVO.getName())
                .unit(reqVO.getUnit())
                .contentType(reqVO.getContentType())
                .sortOrder(reqVO.getSortOrder())
                .attributes(reqVO.getAttributes())
                .build();
    }

    /**
     * 计算路径和层级
     */
    private void calculatePathAndLevel(QuotaCatalogTreeDO item, Long parentId) {
        if (parentId == null) {
            // 根节点
            item.setPath(new String[]{item.getId().toString()});
            item.setLevel(1);
        } else {
            // 子节点
            QuotaCatalogTreeDO parent = quotaCatalogTreeMapper.selectById(parentId);
            
            // 拼接路径
            String[] parentPath = parent.getPath();
            String[] newPath = ArrayUtil.append(parentPath, item.getId().toString());
            item.setPath(newPath);
            item.setLevel(parent.getLevel() + 1);
        }
    }

    /**
     * 获取下一个排序值
     */
    private Integer getNextSortOrder(Long catalogItemId, Long parentId) {
        List<QuotaCatalogTreeDO> siblings = quotaCatalogTreeMapper.selectSiblings(catalogItemId, parentId);
        if (CollUtil.isEmpty(siblings)) {
            return 1;
        }
        return siblings.stream()
                .mapToInt(QuotaCatalogTreeDO::getSortOrder)
                .max()
                .orElse(0) + 1;
    }

    /**
     * 转换为RespVO
     */
    private QuotaCatalogTreeRespVO convertToRespVO(QuotaCatalogTreeDO item) {
        QuotaCatalogTreeRespVO vo = new QuotaCatalogTreeRespVO();
        vo.setId(item.getId());
        vo.setTenantId(item.getTenantId());
        vo.setCatalogItemId(item.getCatalogItemId());
        vo.setParentId(item.getParentId());
        vo.setCode(item.getCode());
        vo.setName(item.getName());
        vo.setUnit(item.getUnit());
        vo.setContentType(item.getContentType());
        vo.setAllowChildren(item.getAllowChildren());
        vo.setSortOrder(item.getSortOrder());
        vo.setPath(item.getPath());
        vo.setLevel(item.getLevel());
        vo.setAttributes(item.getAttributes());
        vo.setRemark(item.getRemark());
        vo.setCreateTime(item.getCreateTime());
        return vo;
    }

    /**
     * 构建树形结构
     */
    private List<QuotaCatalogTreeRespVO> buildTree(List<QuotaCatalogTreeRespVO> allNodes, Long parentId) {
        List<QuotaCatalogTreeRespVO> result = new ArrayList<>();
        for (QuotaCatalogTreeRespVO node : allNodes) {
            if ((parentId == null && node.getParentId() == null)
                    || (parentId != null && parentId.equals(node.getParentId()))) {
                node.setChildren(buildTree(allNodes, node.getId()));
                result.add(node);
            }
        }
        return result;
    }

    /**
     * 判断是否同级
     */
    private boolean isSameLevel(QuotaCatalogTreeDO node1, QuotaCatalogTreeDO node2) {
        // 父节点相同且定额专业相同即为同级
        if (!node1.getCatalogItemId().equals(node2.getCatalogItemId())) {
            return false;
        }
        if (node1.getParentId() == null && node2.getParentId() == null) {
            return true;
        }
        if (node1.getParentId() == null || node2.getParentId() == null) {
            return false;
        }
        return node1.getParentId().equals(node2.getParentId());
    }

    @Override
    public List<QuotaCatalogTreeRespVO> getCatalogTreeByRateItem(Long rateItemId) {
        // 1. 查询费率项，获取其 catalogItemId（费率模式节点ID）
        QuotaRateItemDO rateItem = quotaRateItemMapper.selectById(rateItemId);
        if (rateItem == null) {
            throw exception(QUOTA_RATE_ITEM_NOT_EXISTS);
        }
        
        // 2. 查询费率模式节点
        QuotaCatalogItemDO rateModeNode = quotaCatalogItemMapper.selectById(rateItem.getCatalogItemId());
        if (rateModeNode == null) {
            throw exception(QUOTA_CATALOG_ITEM_NOT_EXISTS);
        }
        
        // 3. 获取父节点（定额专业节点）
        if (rateModeNode.getParentId() == null) {
            throw exception(QUOTA_CATALOG_ITEM_PARENT_NOT_EXISTS);
        }
        
        QuotaCatalogItemDO specialtyNode = quotaCatalogItemMapper.selectById(rateModeNode.getParentId());
        if (specialtyNode == null || !"specialty".equals(specialtyNode.getNodeType())) {
            throw exception(QUOTA_CATALOG_ITEM_SPECIALTY_NOT_FOUND);
        }
        
        // 4. 查询定额专业节点对应的定额基价树（第二层）
        List<QuotaCatalogTreeDO> catalogTrees = quotaCatalogTreeMapper.selectListByCatalogItemId(specialtyNode.getId());
        
        // 5. 转换为VO
        return catalogTrees.stream()
                .map(this::convertToRespVO)
                .collect(Collectors.toList());
    }

    @Override
    public List<QuotaCatalogTreeRespVO> getCatalogTreeByRateModeNode(Long rateModeNodeId) {
        // 1. 查询费率模式节点
        QuotaCatalogItemDO rateModeNode = quotaCatalogItemMapper.selectById(rateModeNodeId);
        if (rateModeNode == null) {
            throw exception(QUOTA_CATALOG_ITEM_NOT_EXISTS);
        }
        
        // 2. 验证节点类型必须是 rate_mode
        if (!"rate_mode".equals(rateModeNode.getNodeType())) {
            throw exception(QUOTA_CATALOG_ITEM_NOT_EXISTS, "节点类型必须是 rate_mode");
        }
        
        // 3. 获取父节点（定额专业节点）
        if (rateModeNode.getParentId() == null) {
            throw exception(QUOTA_CATALOG_ITEM_PARENT_NOT_EXISTS);
        }
        
        QuotaCatalogItemDO specialtyNode = quotaCatalogItemMapper.selectById(rateModeNode.getParentId());
        if (specialtyNode == null || !"specialty".equals(specialtyNode.getNodeType())) {
            throw exception(QUOTA_CATALOG_ITEM_SPECIALTY_NOT_FOUND);
        }
        
        // 4. 查询定额专业节点对应的定额基价树（第二层）
        List<QuotaCatalogTreeDO> catalogTrees = quotaCatalogTreeMapper.selectListByCatalogItemId(specialtyNode.getId());
        
        // 5. 查询该费率模式节点的所有字段绑定
        List<QuotaRateFieldDO> fieldBindings = rateFieldMapper.selectListByCatalogItemId(rateModeNodeId);
        
        // 6. 构建节点ID到字段索引的映射（哪些节点被哪些字段绑定了）
        Map<Long, List<Integer>> nodeBindingMap = new HashMap<>();
        for (QuotaRateFieldDO field : fieldBindings) {
            if (field.getBindingIds() != null && field.getBindingIds().length > 0) {
                for (Long nodeId : field.getBindingIds()) {
                    nodeBindingMap.computeIfAbsent(nodeId, k -> new ArrayList<>())
                            .add(field.getFieldIndex());
                }
            }
        }
        
        // 7. 转换为VO并添加绑定信息
        List<QuotaCatalogTreeRespVO> allVOs = catalogTrees.stream()
                .map(tree -> {
                    QuotaCatalogTreeRespVO vo = convertToRespVO(tree);
                    // 设置该节点已被哪些字段绑定
                    vo.setBoundFieldIndexes(nodeBindingMap.getOrDefault(tree.getId(), new ArrayList<>()));
                    return vo;
                })
                .collect(Collectors.toList());
        
        // 8. 构建树形结构
        return buildTree(allVOs, null);
    }
}
