package tech.easyflow.admin.controller.system;

import org.testng.annotations.Test;
import tech.easyflow.ai.service.KnowledgeSharePermissionService;
import tech.easyflow.ai.service.WorkflowApiPermissionService;
import tech.easyflow.common.domain.Result;
import tech.easyflow.system.entity.SysApiKey;
import tech.easyflow.system.service.SysApiKeyResourceMappingService;
import tech.easyflow.system.service.SysApiKeyService;

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

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertNotEquals;

/**
 * {@link SysApiKeyController} 更新访问令牌测试。
 */
public class SysApiKeyControllerTest {

    /**
     * 验证只更新权限时不会执行缺少主表更新字段的 SQL。
     */
    @Test
    public void updateShouldSkipMainTableForPermissionOnlyRequest() {
        BigInteger apiKeyId = BigInteger.valueOf(100);
        SysApiKeyService apiKeyService = mock(SysApiKeyService.class);
        KnowledgeSharePermissionService knowledgePermissionService =
                mock(KnowledgeSharePermissionService.class);
        SysApiKeyController controller = controller(apiKeyService, knowledgePermissionService);
        SysApiKey existing = new SysApiKey();
        existing.setId(apiKeyId);
        when(apiKeyService.getById(apiKeyId)).thenReturn(existing);

        SysApiKey request = new SysApiKey();
        request.setId(apiKeyId);
        request.setKnowledgeReadEnabled(true);
        request.setKnowledgeImportEnabled(false);
        request.setKnowledgeMaintenanceEnabled(false);

        Result<?> result = controller.update(request);

        assertEquals(result.getErrorCode(), 0);
        verify(apiKeyService, never()).updateById(request);
        verify(knowledgePermissionService).replaceApiPermissions(apiKeyId, true, false, false);
    }

    /**
     * 验证基础字段与权限同时更新时，两类数据都被保存。
     */
    @Test
    public void updateShouldPersistMainTableAndPermissionsTogether() {
        BigInteger apiKeyId = BigInteger.valueOf(101);
        SysApiKeyService apiKeyService = mock(SysApiKeyService.class);
        KnowledgeSharePermissionService knowledgePermissionService =
                mock(KnowledgeSharePermissionService.class);
        SysApiKeyController controller = controller(apiKeyService, knowledgePermissionService);
        SysApiKey existing = new SysApiKey();
        existing.setId(apiKeyId);
        when(apiKeyService.getById(apiKeyId)).thenReturn(existing);

        SysApiKey request = new SysApiKey();
        request.setId(apiKeyId);
        request.setStatus(1);
        request.setKnowledgeReadEnabled(true);
        request.setKnowledgeImportEnabled(true);
        request.setKnowledgeMaintenanceEnabled(true);

        Result<?> result = controller.update(request);

        assertEquals(result.getErrorCode(), 0);
        verify(apiKeyService).updateById(request);
        verify(knowledgePermissionService).replaceApiPermissions(apiKeyId, true, true, true);
    }

    /**
     * 验证名称可以单独更新，并在持久化前移除首尾空格。
     */
    @Test
    public void updateShouldPersistTrimmedNameOnly() {
        BigInteger apiKeyId = BigInteger.valueOf(103);
        SysApiKeyService apiKeyService = mock(SysApiKeyService.class);
        KnowledgeSharePermissionService knowledgePermissionService =
                mock(KnowledgeSharePermissionService.class);
        SysApiKeyController controller = controller(apiKeyService, knowledgePermissionService);
        SysApiKey existing = new SysApiKey();
        existing.setId(apiKeyId);
        when(apiKeyService.getById(apiKeyId)).thenReturn(existing);

        SysApiKey request = new SysApiKey();
        request.setId(apiKeyId);
        request.setName("  生产环境调用  ");

        Result<?> result = controller.update(request);

        assertEquals(result.getErrorCode(), 0);
        assertEquals(request.getName(), "生产环境调用");
        verify(apiKeyService).updateById(request);
    }

    /**
     * 验证空白名称会被拒绝，避免覆盖为无意义内容。
     */
    @Test
    public void updateShouldRejectBlankName() {
        SysApiKeyService apiKeyService = mock(SysApiKeyService.class);
        KnowledgeSharePermissionService knowledgePermissionService =
                mock(KnowledgeSharePermissionService.class);
        SysApiKeyController controller = controller(apiKeyService, knowledgePermissionService);
        SysApiKey request = new SysApiKey();
        request.setId(BigInteger.valueOf(104));
        request.setName("   ");

        Result<?> result = controller.update(request);

        assertNotEquals(result.getErrorCode(), 0);
        verifyNoInteractions(apiKeyService, knowledgePermissionService);
    }

    /**
     * 验证新版知识库权限缺少字段时拒绝更新，避免遗漏字段被隐式关闭。
     */
    @Test
    public void updateShouldRejectPartialKnowledgePermissions() {
        SysApiKeyService apiKeyService = mock(SysApiKeyService.class);
        KnowledgeSharePermissionService knowledgePermissionService =
                mock(KnowledgeSharePermissionService.class);
        SysApiKeyController controller = controller(apiKeyService, knowledgePermissionService);
        SysApiKey request = new SysApiKey();
        request.setId(BigInteger.valueOf(102));
        request.setKnowledgeReadEnabled(true);

        Result<?> result = controller.update(request);

        assertNotEquals(result.getErrorCode(), 0);
        verifyNoInteractions(apiKeyService, knowledgePermissionService);
    }

    /**
     * 创建注入模拟依赖的控制器。
     *
     * @param apiKeyService 访问令牌服务
     * @param knowledgePermissionService 知识库权限服务
     * @return 测试控制器
     */
    private SysApiKeyController controller(
            SysApiKeyService apiKeyService,
            KnowledgeSharePermissionService knowledgePermissionService
    ) {
        SysApiKeyController controller = new SysApiKeyController(apiKeyService);
        setField(controller, "sysApiKeyResourceMappingService", mock(SysApiKeyResourceMappingService.class));
        setField(controller, "knowledgeSharePermissionService", knowledgePermissionService);
        setField(controller, "workflowApiPermissionService", mock(WorkflowApiPermissionService.class));
        return controller;
    }

    /**
     * 通过反射注入控制器字段。
     *
     * @param target 目标对象
     * @param fieldName 字段名
     * @param value 字段值
     */
    private void setField(Object target, String fieldName, Object value) {
        Class<?> current = target.getClass();
        while (current != null) {
            try {
                Field field = current.getDeclaredField(fieldName);
                field.setAccessible(true);
                field.set(target, value);
                return;
            } catch (NoSuchFieldException ignored) {
                current = current.getSuperclass();
            } catch (IllegalAccessException e) {
                throw new IllegalStateException("设置测试字段失败: " + fieldName, e);
            }
        }
        throw new IllegalArgumentException("未找到字段: " + fieldName);
    }
}
