package tech.easyflow.skill.mapper;

import org.apache.ibatis.annotations.Select;
import org.junit.Test;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tech.easyflow.skill.service.impl.SkillCategoryServiceImpl;

import java.lang.reflect.Method;
import java.math.BigInteger;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;

/**
 * {@link SkillCategoryMapper} 分类树并发锁 SQL 契约测试。
 */
public class SkillCategoryMapperLockContractTest {

    /**
     * 验证租户分类树按稳定主键顺序执行排他锁定。
     *
     * @throws Exception 反射读取 Mapper 方法失败
     */
    @Test
    public void tenantTreeMutationShouldLockRowsInStableOrder() throws Exception {
        Method method = SkillCategoryMapper.class.getMethod("selectTenantTreeForUpdate", BigInteger.class);
        String sql = String.join(" ", method.getAnnotation(Select.class).value())
                .replaceAll("\\s+", " ")
                .toUpperCase();

        assertTrue(sql.contains("WHERE TENANT_ID=#{TENANTID}"));
        assertTrue(sql.contains("ORDER BY ID FOR UPDATE"));
        assertTrue(sql.contains("TENANT_ID AS TENANTID"));
        assertTrue(sql.contains("PARENT_ID AS PARENTID"));
        assertTrue(sql.contains("CATEGORY_NAME AS CATEGORYNAME"));
        assertTrue(sql.contains("LEVEL_NO AS LEVELNO"));
        assertTrue(sql.contains("SORT_NO AS SORTNO"));
        assertTrue(sql.contains("CREATED_BY AS CREATEDBY"));
        assertTrue(sql.contains("MODIFIED_BY AS MODIFIEDBY"));
    }

    /**
     * Skill 归类锁必须加入调用方写事务，避免锁在 category_id 写入前提前释放。
     *
     * @throws Exception 反射读取服务方法失败
     */
    @Test
    public void skillAssignmentLockShouldRequireExistingTransaction() throws Exception {
        Method method = SkillCategoryServiceImpl.class.getMethod(
                "lockAndValidateUsableCategory", BigInteger.class);
        Transactional transactional = method.getAnnotation(Transactional.class);

        assertTrue(transactional != null);
        assertEquals(Propagation.MANDATORY, transactional.propagation());
    }
}
