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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import com.yhy.module.core.controller.admin.boq.vo.BoqCatalogItemBindQuotaReqVO;
import com.yhy.module.core.controller.admin.boq.vo.BoqCatalogItemRespVO;
import com.yhy.module.core.controller.admin.boq.vo.BoqCatalogItemSaveReqVO;
import com.yhy.module.core.controller.admin.boq.vo.BoqCatalogItemSwapSortReqVO;
import com.yhy.module.core.dal.dataobject.boq.BoqCatalogItemDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaCatalogItemDO;
import com.yhy.module.core.dal.mysql.boq.BoqCatalogItemMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaCatalogItemMapper;
import com.yhy.module.core.enums.ErrorCodeConstants;
import com.yhy.module.core.service.boq.BoqCatalogItemService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

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

/**
 * 清单配置目录树 Service 实现类
 *
 * @author yhy
 */
@Service
@Validated
@Slf4j
public class BoqCatalogItemServiceImpl implements BoqCatalogItemService {

    @Resource
    private BoqCatalogItemMapper boqCatalogItemMapper;

    @Resource
    private QuotaCatalogItemMapper quotaCatalogItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createBoqCatalogItem(BoqCatalogItemSaveReqVO createReqVO) {
        // 1. 校验编码唯一性
        validateCodeUnique(null, createReqVO.getCode());

        // 2. 校验节点类型
        validateNodeType(createReqVO.getNodeType());

        // 3. 构建DO对象
        BoqCatalogItemDO boqCatalogItem = buildBoqCatalogItemDO(createReqVO);

        // 4. 计算路径和层级
        calculatePathAndLevel(boqCatalogItem, createReqVO.getParentId());

        // 5. 设置排序
        if (boqCatalogItem.getSortOrder() == null) {
            boqCatalogItem.setSortOrder(getNextSortOrder(createReqVO.getParentId()));
        }

        // 6. 插入数据库
        boqCatalogItemMapper.insert(boqCatalogItem);

        return boqCatalogItem.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBoqCatalogItem(BoqCatalogItemSaveReqVO updateReqVO) {
        // 1. 校验节点存在
        BoqCatalogItemDO existingItem = validateBoqCatalogItemExists(updateReqVO.getId());

        // 2. 校验编码唯一性
        validateCodeUnique(updateReqVO.getId(), updateReqVO.getCode());

        // 3. 校验节点类型
        validateNodeType(updateReqVO.getNodeType());

        // 4. 校验是否已绑定（已绑定的专业节点不允许修改）
        if (Boolean.TRUE.equals(existingItem.getSpecialtyLocked())) {
            throw exception(BOQ_CATALOG_ITEM_SPECIALTY_LOCKED);
        }

        // 5. 构建更新对象
        BoqCatalogItemDO updateObj = BoqCatalogItemDO.builder()
                .id(updateReqVO.getId())
                .code(updateReqVO.getCode())
                .name(updateReqVO.getName())
                .nodeType(updateReqVO.getNodeType())
                .sortOrder(updateReqVO.getSortOrder())
                .attributes(updateReqVO.getAttributes())
                .build();

        // 6. 更新数据库
        boqCatalogItemMapper.updateById(updateObj);
    }

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

        // 2. 校验是否已绑定
        if (Boolean.TRUE.equals(item.getSpecialtyLocked())) {
            throw exception(BOQ_CATALOG_ITEM_SPECIALTY_LOCKED);
        }

        // 3. 校验是否有子节点
        List<BoqCatalogItemDO> children = boqCatalogItemMapper.selectListByParentId(id);
        if (CollUtil.isNotEmpty(children)) {
            throw exception(BOQ_CATALOG_ITEM_HAS_CHILDREN);
        }

        // 4. 删除节点
        boqCatalogItemMapper.deleteById(id);
    }

    @Override
    public BoqCatalogItemRespVO getBoqCatalogItem(Long id) {
        BoqCatalogItemDO item = boqCatalogItemMapper.selectById(id);
        if (item == null) {
            return null;
        }
        return convertToRespVO(item);
    }

    @Override
    public List<BoqCatalogItemRespVO> getBoqCatalogItemTree() {
        // 1. 查询所有节点
        List<BoqCatalogItemDO> allItems = boqCatalogItemMapper.selectList();

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

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindQuotaCatalogItem(BoqCatalogItemBindQuotaReqVO bindReqVO) {
        // 1. 校验清单专业节点存在
        BoqCatalogItemDO boqItem = validateBoqCatalogItemExists(bindReqVO.getBoqCatalogItemId());

        // 2. 校验节点类型必须是specialty
        if (!BoqCatalogItemDO.NODE_TYPE_SPECIALTY.equals(boqItem.getNodeType())) {
            throw exception(BOQ_CATALOG_ITEM_NOT_SPECIALTY);
        }

        // 3. 校验是否已绑定
        if (Boolean.TRUE.equals(boqItem.getSpecialtyLocked())) {
            throw exception(BOQ_CATALOG_ITEM_ALREADY_BOUND);
        }

        // 4. 校验定额基价节点存在且为第一层
        QuotaCatalogItemDO quotaItem = quotaCatalogItemMapper.selectById(bindReqVO.getQuotaCatalogItemId());
        if (quotaItem == null) {
            throw exception(QUOTA_CATALOG_ITEM_NOT_EXISTS);
        }
        // 通过 path 数组长度判断层级（第一层的 path 长度为 1）
        if (quotaItem.getPath() == null || quotaItem.getPath().length != 1) {
            throw exception(BOQ_CATALOG_ITEM_QUOTA_NOT_FIRST_LEVEL);
        }

        // 5. 更新绑定信息
        BoqCatalogItemDO updateObj = BoqCatalogItemDO.builder()
                .id(bindReqVO.getBoqCatalogItemId())
                .quotaCatalogItemId(bindReqVO.getQuotaCatalogItemId())
                .specialtyLocked(true)
                .build();
        boqCatalogItemMapper.updateById(updateObj);

        log.info("[bindQuotaCatalogItem] 清单专业节点[{}]绑定定额基价节点[{}]成功",
                bindReqVO.getBoqCatalogItemId(), bindReqVO.getQuotaCatalogItemId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(BoqCatalogItemSwapSortReqVO swapReqVO) {
        // 1. 查询两个节点（加锁）
        BoqCatalogItemDO node1 = boqCatalogItemMapper.selectById(swapReqVO.getNodeId1());
        BoqCatalogItemDO node2 = boqCatalogItemMapper.selectById(swapReqVO.getNodeId2());

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

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

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

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

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

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

    /**
     * 校验编码唯一性
     */
    private void validateCodeUnique(Long id, String code) {
        BoqCatalogItemDO existing = boqCatalogItemMapper.selectByCode(code);
        if (existing != null && !existing.getId().equals(id)) {
            throw exception(BOQ_CATALOG_ITEM_CODE_DUPLICATE);
        }
    }

    /**
     * 校验节点类型
     */
    private void validateNodeType(String nodeType) {
        if (!BoqCatalogItemDO.NODE_TYPE_PROVINCE.equals(nodeType)
                && !BoqCatalogItemDO.NODE_TYPE_SPECIALTY.equals(nodeType)) {
            throw exception(BOQ_CATALOG_ITEM_INVALID_NODE_TYPE);
        }
    }

    /**
     * 校验节点存在
     */
    private BoqCatalogItemDO validateBoqCatalogItemExists(Long id) {
        BoqCatalogItemDO item = boqCatalogItemMapper.selectById(id);
        if (item == null) {
            throw exception(BOQ_CATALOG_ITEM_NOT_EXISTS);
        }
        return item;
    }

    /**
     * 构建DO对象
     */
    private BoqCatalogItemDO buildBoqCatalogItemDO(BoqCatalogItemSaveReqVO reqVO) {
        return BoqCatalogItemDO.builder()
                .id(reqVO.getId())
                .parentId(reqVO.getParentId())
                .code(reqVO.getCode())
                .name(reqVO.getName())
                .nodeType(reqVO.getNodeType())
                .sortOrder(reqVO.getSortOrder())
                .specialtyLocked(false)
                .attributes(reqVO.getAttributes())
                .build();
    }

    /**
     * 计算路径和层级
     */
    private void calculatePathAndLevel(BoqCatalogItemDO item, Long parentId) {
        if (parentId == null) {
            // 根节点
            item.setPath(new String[]{item.getId().toString()});
            item.setLevel(1);
        } else {
            // 子节点
            BoqCatalogItemDO parent = boqCatalogItemMapper.selectById(parentId);
            if (parent == null) {
                throw exception(BOQ_CATALOG_ITEM_PARENT_NOT_EXISTS);
            }

            // 拼接路径
            String[] parentPath = parent.getPath();
            String[] newPath = ArrayUtil.append(parentPath, item.getId().toString());
            item.setPath(newPath);
            item.setLevel(parent.getLevel() + 1);
        }
    }

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

    /**
     * 转换为RespVO
     */
    private BoqCatalogItemRespVO convertToRespVO(BoqCatalogItemDO item) {
        BoqCatalogItemRespVO vo = new BoqCatalogItemRespVO();
        vo.setId(item.getId());
        vo.setParentId(item.getParentId());
        vo.setCode(item.getCode());
        vo.setName(item.getName());
        vo.setNodeType(item.getNodeType());
        vo.setSortOrder(item.getSortOrder());
        vo.setQuotaCatalogItemId(item.getQuotaCatalogItemId());
        vo.setSpecialtyLocked(item.getSpecialtyLocked());
        vo.setPath(item.getPath());
        vo.setLevel(item.getLevel());
        vo.setAttributes(item.getAttributes());
        vo.setCreateTime(item.getCreateTime());
        vo.setUpdateTime(item.getUpdateTime());
        return vo;
    }

    /**
     * 构建树形结构
     */
    private List<BoqCatalogItemRespVO> buildTree(List<BoqCatalogItemRespVO> allNodes, Long parentId) {
        List<BoqCatalogItemRespVO> result = new ArrayList<>();
        for (BoqCatalogItemRespVO 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(BoqCatalogItemDO node1, BoqCatalogItemDO node2) {
        // 父节点相同即为同级
        if (node1.getParentId() == null && node2.getParentId() == null) {
            return true;
        }
        if (node1.getParentId() == null || node2.getParentId() == null) {
            return false;
        }
        return node1.getParentId().equals(node2.getParentId());
    }
}
