package com.eactive.eai.message.manager;

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

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInstance;

import com.eactive.eai.custom.message.GUIDGeneratorDJB;
import com.eactive.eai.custom.message.InterfaceMapperDJB;
import com.eactive.eai.custom.message.StandardMessageCoordinatorDJB;
import com.eactive.eai.message.StandardMessage;
import com.eactive.eai.message.parser.StandardReader;

/**
 * StandardMessageManager.init() 단위테스트
 *
 * Singleton 특성상 getInstance()로 접근, init()을 직접 호출하여 검증.
 * System.property를 미설정 → 클래스패스의 standard-message-config.properties 로드.
 */
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class StandardMessageManagerInitTest {

    private StandardMessageManager manager;

    @BeforeAll
    void setUp() throws Exception {
        // 테스트용 config: layout.file.path에 src/main/resources 상대경로 사용
        // (StandardMessageUtil.generateMessageFromCsvFile은 파일시스템 상대경로로 읽음)
        System.setProperty(StandardMessageManager.STANDARD_MESSAGE_CONFIG,
                "src/test/resources/standard-message-config-test.properties");
        manager = StandardMessageManager.getInstance();
        manager.init();
    }

    // ----------------------------------------------------------------
    // 1. 표준전문 레이아웃 (StandardMessage)
    // ----------------------------------------------------------------

    @Test
    void standardMessage_정상_로드() {
        StandardMessage msg = manager.getStandardMessage();
        assertNotNull(msg, "StandardMessage가 null — CSV 로드 실패");
    }

    @Test
    void standardMessage_HEAD_블록_존재() {
        StandardMessage msg = manager.getStandardMessage();
        assertNotNull(msg.findItem("HEAD"), "HEAD 블록 없음");
    }

    @Test
    void standardMessage_HEAD_guid_40자() {
        StandardMessage msg = manager.getStandardMessage();
        assertEquals(GUIDGeneratorDJB.GUID_LENGTH, msg.findItem("HEAD.guid").getLength(),
                "HEAD.guid 길이는 40자여야 함");
    }

    @Test
    void standardMessage_HEAD_if_id_30자() {
        StandardMessage msg = manager.getStandardMessage();
        assertEquals(30, msg.findItem("HEAD.if_id").getLength(),
                "HEAD.if_id 길이는 30자여야 함");
    }

    @Test
    void standardMessage_DATA_BIZ_DATA_존재() {
        StandardMessage msg = manager.getStandardMessage();
        assertNotNull(msg.findItem("DATA.BIZ_DATA"), "DATA.BIZ_DATA 없음");
    }

    // ----------------------------------------------------------------
    // 2. InterfaceMapper
    // ----------------------------------------------------------------

    @Test
    void mapper_InterfaceMapperDJB_인스턴스() {
        assertNotNull(manager.getMapper(), "mapper가 null");
        assertInstanceOf(InterfaceMapperDJB.class, manager.getMapper(),
                "mapper가 InterfaceMapperDJB가 아님: " + manager.getMapper().getClass().getName());
    }

    @Test
    void mapper_GUID_경로_매핑_정상() {
        StandardMessage msg = manager.getStandardMessage();
        InterfaceMapperDJB mapper = (InterfaceMapperDJB) manager.getMapper();
        String guid = GUIDGeneratorDJB.getGUID("EAI");
        mapper.setGuid(msg, guid);
        assertEquals(guid, mapper.getGuid(msg), "GUID 설정/조회 불일치");
    }

    @Test
    void mapper_ResponseType_S_F_변환() {
        StandardMessage msg = manager.getStandardMessage();
        InterfaceMapperDJB mapper = (InterfaceMapperDJB) manager.getMapper();
        // NR → S
        mapper.setResponseType(msg, com.ext.eai.common.stdmessage.STDMessageKeys.RESPONSE_TYPE_CODE_N);
        assertEquals("S", msg.findItemValue("HEAD.procs_rslt_dvcd"));
        // ER → F
        mapper.setResponseType(msg, com.ext.eai.common.stdmessage.STDMessageKeys.RESPONSE_TYPE_CODE_E);
        assertEquals("F", msg.findItemValue("HEAD.procs_rslt_dvcd"));
    }

    // ----------------------------------------------------------------
    // 3. StandardMessageCoordinator
    // ----------------------------------------------------------------

    @Test
    void coordinator_StandardMessageCoordinatorDJB_인스턴스() {
        assertNotNull(manager.getMessageCoordinator(), "messageCoordinator가 null");
        assertInstanceOf(StandardMessageCoordinatorDJB.class, manager.getMessageCoordinator(),
                "coordinator가 StandardMessageCoordinatorDJB가 아님: "
                        + manager.getMessageCoordinator().getClass().getName());
    }

    // ----------------------------------------------------------------
    // 4. Reader 등록
    // ----------------------------------------------------------------

    @Test
    void reader_JSON_등록() {
        StandardReader reader = manager.getReader("JSON");
        assertNotNull(reader, "JSON reader 미등록");
        assertEquals("com.eactive.eai.message.parser.JsonReader",
                reader.getClass().getName());
    }

    @Test
    void reader_XML_등록() {
        StandardReader reader = manager.getReader("XML");
        assertNotNull(reader, "XML reader 미등록");
        assertEquals("com.eactive.eai.message.parser.XmlReader",
                reader.getClass().getName());
    }

    @Test
    void reader_ASC_등록() {
        StandardReader reader = manager.getReader("ASC");
        assertNotNull(reader, "ASC(Flat) reader 미등록");
        assertEquals("com.eactive.eai.message.parser.FlatReader",
                reader.getClass().getName());
    }

    @Test
    void reader_FLAT_등록() {
        StandardReader reader = manager.getReader("FLAT");
        assertNotNull(reader, "FLAT reader 미등록");
        assertEquals("com.eactive.eai.message.parser.FlatReader",
                reader.getClass().getName());
    }

    // ----------------------------------------------------------------
    // 5. getStandardMessage() 독립 복사본 반환
    // ----------------------------------------------------------------

    @Test
    void getStandardMessage_호출마다_독립_복사본() {
        StandardMessage msg1 = manager.getStandardMessage();
        StandardMessage msg2 = manager.getStandardMessage();
        assertNotSame(msg1, msg2, "getStandardMessage()는 매번 새 인스턴스를 반환해야 함");

        // 한 쪽 수정이 다른 쪽에 영향 없어야 함
        msg1.setData("HEAD.guid", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
        assertNotEquals(
                msg1.findItemValue("HEAD.guid"),
                msg2.findItemValue("HEAD.guid"),
                "복사본이 원본에 영향을 줌 — clone 미작동");
    }

    // ----------------------------------------------------------------
    // 6. reload() — init() 재실행 후 상태 일관성
    // ----------------------------------------------------------------

    @Test
    void reload_후_mapper_정상() throws Exception {
        manager.reload();
        assertNotNull(manager.getMapper(), "reload 후 mapper null");
        assertInstanceOf(InterfaceMapperDJB.class, manager.getMapper());
    }

    @Test
    void reload_후_standardMessage_정상() throws Exception {
        manager.reload();
        StandardMessage msg = manager.getStandardMessage();
        assertNotNull(msg);
        assertNotNull(msg.findItem("HEAD"));
    }
}
