package com.eactive.eai.agent.inflow;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;

import com.eactive.eai.agent.command.CommandException;
import com.eactive.eai.common.inflow.InflowControlManager;
import com.eactive.eai.common.inflow.InflowControlUtil;
import com.eactive.eai.common.inflow.dual.ClientDualInflowControlManager;

/**
 * RemoveInflowClientControlCommand 단위 테스트.
 *
 * <p>InflowControlUtil의 cachedInflowControlManager 필드에 mock을 직접 주입하여
 * PropManager/ApplicationContext 없이 동작을 검증한다.
 */
class RemoveInflowClientControlCommandTest {

    private ClientDualInflowControlManager mockDualManager;

    @BeforeEach
    void setUp() {
        mockDualManager = mock(ClientDualInflowControlManager.class);
        ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", null);
    }

    @AfterEach
    void tearDown() {
        ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", null);
    }

    private RemoveInflowClientControlCommand commandWith(Object args) {
        RemoveInflowClientControlCommand cmd = new RemoveInflowClientControlCommand();
        cmd.setArgs(args);
        return cmd;
    }

    // =========================================================================
    // args 타입 검증 실패
    // =========================================================================

    @Test
    void execute_argsIsInteger_throwsCommandException() {
        assertThrows(CommandException.class, commandWith(Integer.valueOf(1))::execute);
    }

    // =========================================================================
    // ClientDualInflowControlManager 비활성
    // =========================================================================

    @Test
    void execute_notClientDualManager_throwsCommandException() {
        InflowControlManager baseMgr = mock(InflowControlManager.class);
        ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", baseMgr);

        assertThrows(CommandException.class, commandWith("CLIENT_A")::execute);
    }

    // =========================================================================
    // 정상 제거
    // =========================================================================

    @Test
    void execute_validClientId_callsRemoveClient() throws CommandException {
        ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", mockDualManager);

        Object result = commandWith("CLIENT_A").execute();

        assertEquals("success", result);
        verify(mockDualManager).removeClient("CLIENT_A");
    }

    @Test
    void execute_differentClientId_callsRemoveClientWithThatId() throws Exception {
        ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", mockDualManager);

        commandWith("CLIENT_B").execute();

        verify(mockDualManager).removeClient("CLIENT_B");
    }

    @Test
    void execute_validClientId_doesNotCallReload() throws Exception {
        ReflectionTestUtils.setField(InflowControlUtil.class, "cachedInflowControlManager", mockDualManager);

        commandWith("CLIENT_A").execute();

        verify(mockDualManager, never()).reloadClient();
        verify(mockDualManager, never()).reloadClient(anyString());
    }
}
