package com.eactive.eai.manage.tools;

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

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.support.GenericApplicationContext;

import com.eactive.eai.agent.encryption.EncryptionManager;
import com.eactive.eai.common.util.ApplicationContextProvider;

/**
 * ToolsService의 EncryptionManager 연동(encryptionManagerEncrypt/Decrypt/Status) 단위 테스트.
 *
 * <p>EncryptionManager.getInstance()는 ApplicationContextProvider를 통해 실제 Spring
 * ApplicationContext에서 빈을 조회하므로, base64/hex/damo 단독 테스트(ToolsServiceTest)와 분리해
 * 최소한의 GenericApplicationContext를 구성한다.
 *
 * <p>damo-manager.jar가 네이티브 DAMO 라이브러리 없이 로드되면 FAKE MODE(encrypt→Base64,
 * decrypt→Base64 디코딩)로 동작하므로(EncryptionManagerTest 참고) DAMO 모드에서도 라운드트립
 * 검증이 가능하다.
 */
class ToolsServiceEncryptionManagerTest {

    private static GenericApplicationContext ctx;
    private static EncryptionManager manager;

    private final ToolsService service = new ToolsService();

    @BeforeAll
    static void setUpClass() throws Exception {
        Constructor<EncryptionManager> ctor = EncryptionManager.class.getDeclaredConstructor();
        ctor.setAccessible(true);
        manager = ctor.newInstance();

        ctx = new GenericApplicationContext();
        ctx.getBeanFactory().registerSingleton("encryptionManager", manager);
        ctx.registerBeanDefinition("applicationContextProvider",
                BeanDefinitionBuilder.genericBeanDefinition(ApplicationContextProvider.class)
                        .getBeanDefinition());
        ctx.refresh();
    }

    @AfterAll
    static void tearDownClass() {
        if (ctx != null) ctx.close();
    }

    private void setField(String name, Object value) throws Exception {
        Field f = EncryptionManager.class.getDeclaredField(name);
        f.setAccessible(true);
        f.set(manager, value);
    }

    // =========================================================================
    // 1. encryptionManagerEncrypt / Decrypt
    // =========================================================================

    @Test
    @DisplayName("1-1. encryptYN=Y, DAMO — encrypt/decrypt 라운드트립")
    void testEncryptDecrypt_damoEnabled_roundTrip() throws Exception {
        setField("encryptYN", "Y");
        setField("dbEncryptSolutionName", "DAMO");

        // DamoManager의 실제 동작(FAKE MODE로 Base64 변환 / 네이티브 라이브러리 미초기화 시 원문 그대로
        // bypass)은 실행 환경에 따라 달라질 수 있어 encrypt 결과가 원문과 달라야 한다는 보장은 없다.
        // 이 테스트는 encryptDBData → decryptDBData 라운드트립이 원문을 복원하는지만 검증한다.
        String plain = "홍길동";
        String encrypted = service.encryptionManagerEncrypt(plain);
        assertEquals(plain, service.encryptionManagerDecrypt(encrypted));
    }

    @Test
    @DisplayName("1-2. encryptYN=N — encrypt는 원문을 그대로 반환 (설정 비활성)")
    void testEncrypt_disabled_returnsPlain() throws Exception {
        setField("encryptYN", "N");
        setField("dbEncryptSolutionName", "DAMO");

        assertEquals("홍길동", service.encryptionManagerEncrypt("홍길동"));
    }

    // =========================================================================
    // 2. encryptionManagerStatus
    // =========================================================================

    @Test
    @DisplayName("2-1. encryptionManagerStatus() — 활성화 상태의 현재 필드값 반영")
    void testStatus_enabled_reflectsCurrentFields() throws Exception {
        setField("encryptYN", "Y");
        setField("dbEncryptSolutionName", "DAMO");

        EncryptionManagerStatusDTO status = service.encryptionManagerStatus();

        assertEquals("Y", status.getEncryptYN());
        assertEquals("DAMO", status.getDbEncryptSolutionName());
        assertTrue(status.isEncryptEnabled());
    }

    @Test
    @DisplayName("2-2. encryptionManagerStatus() — encryptYN=N이면 encryptEnabled=false")
    void testStatus_disabled_encryptEnabledFalse() throws Exception {
        setField("encryptYN", "N");

        assertFalse(service.encryptionManagerStatus().isEncryptEnabled());
    }
}
