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

import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception0;
import static com.yhy.module.core.enums.ErrorCodeConstants.RESOURCE_CATEGORY_CODE_DUPLICATE;
import static com.yhy.module.core.enums.ErrorCodeConstants.RESOURCE_CATEGORY_NOT_EXISTS;

import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yhy.module.core.controller.admin.resource.vo.ResourceCategorySaveReqVO;
import com.yhy.module.core.dal.dataobject.resource.ResourceCategoryDO;
import com.yhy.module.core.dal.dataobject.resource.ResourceCategoryTreeMappingDO;
import com.yhy.module.core.dal.dataobject.resource.ResourceItemDO;
import com.yhy.module.core.dal.mysql.resource.ResourceCategoryMapper;
import com.yhy.module.core.dal.mysql.resource.ResourceCategoryTreeMappingMapper;
import com.yhy.module.core.dal.mysql.resource.ResourceItemMapper;
import com.yhy.module.core.service.resource.ResourceCategoryService;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ResourceCategoryServiceImpl implements ResourceCategoryService {

    @Resource
    private ResourceCategoryMapper categoryMapper;
    
    @Resource
    private ResourceCategoryTreeMappingMapper categoryTreeMappingMapper;
    
    @Resource
    private ResourceItemMapper resourceItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(ResourceCategorySaveReqVO reqVO) {
        Long tenantId = TenantContextHolder.getTenantId();
        
        // 检查代码唯一性
        validateCategoryCodeDuplicate(reqVO.getCode(), null, tenantId);

        ResourceCategoryDO category = BeanUtils.toBean(reqVO, ResourceCategoryDO.class);
        category.setTenantId(tenantId);
        categoryMapper.insert(category);
        return category.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ResourceCategorySaveReqVO reqVO) {
        // 校验类别存在
        validateCategoryExists(reqVO.getId());
        
        Long tenantId = TenantContextHolder.getTenantId();
        
        // 检查代码唯一性（排除自己）
        validateCategoryCodeDuplicate(reqVO.getCode(), reqVO.getId(), tenantId);

        ResourceCategoryDO category = BeanUtils.toBean(reqVO, ResourceCategoryDO.class);
        category.setTenantId(tenantId);
        categoryMapper.updateById(category);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        // 校验类别存在
        validateCategoryExists(id);
        
        // 检查是否被机类树映射引用
        validateCategoryNotUsedInMapping(id);
        
        // 检查是否有工料机项引用此类别
        validateCategoryNotUsedInResourceItem(id);
        
        categoryMapper.deleteById(id);
    }
    
    /**
     * 校验类别是否存在
     */
    private void validateCategoryExists(Long id) {
        if (categoryMapper.selectById(id) == null) {
            throw exception(RESOURCE_CATEGORY_NOT_EXISTS);
        }
    }
    
    /**
     * 校验类别是否被机类树映射引用
     */
    private void validateCategoryNotUsedInMapping(Long categoryId) {
        Long count = categoryTreeMappingMapper.selectCount(
                new LambdaQueryWrapper<ResourceCategoryTreeMappingDO>()
                        .eq(ResourceCategoryTreeMappingDO::getCategoryId, categoryId)
        );
        if (count > 0) {
            throw exception0(BAD_REQUEST.getCode(), "该类别已被工料机专业引用，无法删除");
        }
    }
    
    /**
     * 校验类别是否被工料机项引用
     */
    private void validateCategoryNotUsedInResourceItem(Long categoryId) {
        Long count = resourceItemMapper.selectCount(
                new LambdaQueryWrapper<ResourceItemDO>()
                        .eq(ResourceItemDO::getCategoryId, categoryId)
        );
        if (count > 0) {
            throw exception0(BAD_REQUEST.getCode(), "该类别已被工料机项引用，无法删除");
        }
    }
    
    /**
     * 校验类别代码是否重复
     */
    private void validateCategoryCodeDuplicate(String code, Long excludeId, Long tenantId) {
        ResourceCategoryDO category = categoryMapper.selectOne(new LambdaQueryWrapper<ResourceCategoryDO>()
                .eq(ResourceCategoryDO::getTenantId, tenantId)
                .eq(ResourceCategoryDO::getCode, code));
        if (category == null) {
            return;
        }
        // 如果 excludeId 为空，说明是新增，直接抛异常
        if (excludeId == null) {
            throw exception(RESOURCE_CATEGORY_CODE_DUPLICATE, code);
        }
        // 如果 ID 不同，说明代码重复
        if (!category.getId().equals(excludeId)) {
            throw exception(RESOURCE_CATEGORY_CODE_DUPLICATE, code);
        }
    }

    @Override
    public ResourceCategoryDO get(Long id) {
        return categoryMapper.selectById(id);
    }

    @Override
    public List<ResourceCategoryDO> list() {
        return categoryMapper.selectList(new LambdaQueryWrapper<ResourceCategoryDO>()
                .eq(ResourceCategoryDO::getTenantId, TenantContextHolder.getTenantId())
                .orderByAsc(ResourceCategoryDO::getSortOrder)
                .orderByAsc(ResourceCategoryDO::getId));
    }
    
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSortOrder(Long nodeId1, Long nodeId2) {
        Long tenantId = TenantContextHolder.getTenantId();
        
        // 1. 查询两个节点（使用行锁）
        ResourceCategoryDO node1 = categoryMapper.selectOne(
                new LambdaQueryWrapper<ResourceCategoryDO>()
                        .eq(ResourceCategoryDO::getId, nodeId1)
                        .eq(ResourceCategoryDO::getTenantId, tenantId)
                        .last("FOR UPDATE")
        );
        ResourceCategoryDO node2 = categoryMapper.selectOne(
                new LambdaQueryWrapper<ResourceCategoryDO>()
                        .eq(ResourceCategoryDO::getId, nodeId2)
                        .eq(ResourceCategoryDO::getTenantId, tenantId)
                        .last("FOR UPDATE")
        );
        
        if (node1 == null || node2 == null) {
            throw exception0(BAD_REQUEST.getCode(), "类别不存在");
        }
        
        // 2. 交换 sort_order
        Integer tempSortOrder = node1.getSortOrder();
        node1.setSortOrder(node2.getSortOrder());
        node2.setSortOrder(tempSortOrder);
        
        // 3. 更新数据库
        categoryMapper.updateById(node1);
        categoryMapper.updateById(node2);
    }
}
