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

import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import com.yhy.module.core.controller.admin.resource.vo.CatalogItemSaveReqVO;
import com.yhy.module.core.controller.admin.resource.vo.ResourceCategorySimpleRespVO;
import com.yhy.module.core.dal.dataobject.resource.ResourceCatalogItemDO;
import com.yhy.module.core.dal.mysql.resource.ResourceCatalogItemMapper;
import com.yhy.module.core.service.resource.ResourceCatalogItemService;
import com.yhy.module.core.service.resource.ResourceCategoryTreeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;

@Service
public class ResourceCatalogItemServiceImpl implements ResourceCatalogItemService {

    @Resource
    private ResourceCatalogItemMapper catalogItemMapper;
    
    @Resource
    private ResourceCategoryTreeService categoryTreeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(CatalogItemSaveReqVO reqVO) {
        // 验证机类树节点是否存在（可选，根据业务需求决定是否需要）
        // ResourceCategoryTreeDO categoryTree = categoryTreeMapper.selectById(reqVO.getCategoryTreeId());
        // if (categoryTree == null) {
        //     throw exception0(BAD_REQUEST.getCode(), "工料机机类树节点不存在");
        // }
        Long tenantId = TenantContextHolder.getTenantId();
        checkCodeUnique(tenantId, reqVO.getCategoryTreeId(), reqVO.getCode(), null);

        ResourceCatalogItemDO item = BeanUtils.toBean(reqVO, ResourceCatalogItemDO.class);
        item.setTenantId(tenantId);
        item.setPath(buildPath(reqVO.getParentPath(), reqVO.getCode()));
        catalogItemMapper.insert(item);
        return item.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(CatalogItemSaveReqVO reqVO) {
        ResourceCatalogItemDO dbItem = catalogItemMapper.selectById(reqVO.getId());
        if (dbItem == null) {
            throw exception0(BAD_REQUEST.getCode(), "条目不存在");
        }
        Long tenantId = TenantContextHolder.getTenantId();
        checkCodeUnique(tenantId, dbItem.getCategoryTreeId(), reqVO.getCode(), dbItem.getId());

        ResourceCatalogItemDO item = BeanUtils.toBean(reqVO, ResourceCatalogItemDO.class);
        item.setTenantId(tenantId);
        // 只有 parentPath + code 变化时才重建 path
        item.setPath(buildPath(reqVO.getParentPath(), reqVO.getCode()));
        catalogItemMapper.updateById(item);
    }

    @Override
    public void delete(Long id) {
        ResourceCatalogItemDO dbItem = catalogItemMapper.selectById(id);
        if (dbItem == null) {
            return;
        }
        // 检查是否有子节点
        Long count = catalogItemMapper.selectCount(new LambdaQueryWrapper<ResourceCatalogItemDO>()
                .eq(ResourceCatalogItemDO::getCategoryTreeId, dbItem.getCategoryTreeId())
                .apply("path[1:array_length(path,1)-1] = #{path}", (Object) dbItem.getPath()));
        if (count != null && count > 0) {
            throw exception0(BAD_REQUEST.getCode(), "存在子节点，不可删除");
        }
        catalogItemMapper.deleteById(id);
    }

    @Override
    public List<ResourceCatalogItemDO> listByCatalog(Long catalogId) {
        return catalogItemMapper.selectList(new LambdaQueryWrapper<ResourceCatalogItemDO>()
                .eq(ResourceCatalogItemDO::getCategoryTreeId, catalogId)
                .eq(ResourceCatalogItemDO::getTenantId, TenantContextHolder.getTenantId())
                .orderByAsc(ResourceCatalogItemDO::getPath));
    }

    private void checkCodeUnique(Long tenantId, Long catalogId, String code, Long excludeId) {
        LambdaQueryWrapper<ResourceCatalogItemDO> wrapper = new LambdaQueryWrapper<ResourceCatalogItemDO>()
                .eq(ResourceCatalogItemDO::getTenantId, tenantId)
                .eq(ResourceCatalogItemDO::getCategoryTreeId, catalogId)
                .eq(ResourceCatalogItemDO::getCode, code);
        if (excludeId != null) {
            wrapper.ne(ResourceCatalogItemDO::getId, excludeId);
        }
        ResourceCatalogItemDO exists = catalogItemMapper.selectOne(wrapper);
        if (exists != null) {
            throw exception0(BAD_REQUEST.getCode(), "条目编码已存在");
        }
    }

    private String[] buildPath(List<String> parentPath, String code) {
        List<String> path = new ArrayList<>();
        if (!CollectionUtils.isEmpty(parentPath)) {
            path.addAll(parentPath);
        }
        path.add(code);
        return ArrayUtils.toArray(path, s -> s);
    }
    
    @Override
    public List<ResourceCategorySimpleRespVO> getAllowedCategories(Long catalogItemId) {
        // 1. 查询目录树节点
        ResourceCatalogItemDO catalogItem = catalogItemMapper.selectById(catalogItemId);
        if (catalogItem == null) {
            throw exception0(BAD_REQUEST.getCode(), "目录树节点不存在");
        }
        
        // 2. 查询该目录树节点所属的机类树节点允许的类别列表
        return categoryTreeService.getCategoriesByTreeNode(catalogItem.getCategoryTreeId());
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSortOrder(Long nodeId1, Long nodeId2) {
        Long tenantId = TenantContextHolder.getTenantId();
        
        // 1. 查询两个节点（使用行锁）
        ResourceCatalogItemDO node1 = catalogItemMapper.selectOne(
                new LambdaQueryWrapper<ResourceCatalogItemDO>()
                        .eq(ResourceCatalogItemDO::getId, nodeId1)
                        .eq(ResourceCatalogItemDO::getTenantId, tenantId)
                        .last("FOR UPDATE")
        );
        ResourceCatalogItemDO node2 = catalogItemMapper.selectOne(
                new LambdaQueryWrapper<ResourceCatalogItemDO>()
                        .eq(ResourceCatalogItemDO::getId, nodeId2)
                        .eq(ResourceCatalogItemDO::getTenantId, tenantId)
                        .last("FOR UPDATE")
        );
        
        if (node1 == null || node2 == null) {
            throw exception0(BAD_REQUEST.getCode(), "目录树节点不存在");
        }
        
        // 2. 验证是否同级（path 长度必须相同，且父路径必须相同）
        if (!isSameLevel(node1.getPath(), node2.getPath())) {
            throw exception0(BAD_REQUEST.getCode(), "只能在同级节点之间调整排序");
        }
        
        // 3. 交换 sort_order
        Integer tempSortOrder = node1.getSortOrder();
        node1.setSortOrder(node2.getSortOrder());
        node2.setSortOrder(tempSortOrder);
        
        // 4. 更新数据库
        catalogItemMapper.updateById(node1);
        catalogItemMapper.updateById(node2);
    }
    
    /**
     * 判断两个节点是否同级（通过 path 数组判断）
     */
    private boolean isSameLevel(String[] path1, String[] path2) {
        if (path1 == null || path2 == null) {
            return false;
        }
        
        // 长度必须相同
        if (path1.length != path2.length) {
            return false;
        }
        
        // 如果是根节点（长度为1），直接返回 true
        if (path1.length == 1) {
            return true;
        }
        
        // 父路径必须相同（除了最后一个元素）
        for (int i = 0; i < path1.length - 1; i++) {
            if (!path1[i].equals(path2[i])) {
                return false;
            }
        }
        
        return true;
    }
}
