package com.eactive.eai.transformer;

import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.jdbc.Sql;

import com.eactive.eai.transformer.engine.TransformEngine;
import com.eactive.eai.transformer.function.jpa.TransformJPATestConfiguration;
import com.eactive.eai.transformer.message.Message;
import com.eactive.eai.transformer.message.MessageFactory;
import com.eactive.eai.transformer.message.MessageSetDataException;

/**
 * XMLMessage BIGDECIMAL validation 단위테스트
 *
 * 테스트 대상 레이아웃: EAI_UXMLTYPE_REQ1 (XML 타입)
 *   - BIG_VALUE   : TYPE_BIGDECIMAL(2118), length=10, decimal=5  → 정수부 최대 4자리
 *   - BIG15_VALUE : TYPE_BIGDECIMAL(2118), length=15, decimal=0  → 정수부 최대 15자리
 *   - STR_VALUE   : TYPE_STRING(2101),     length=20
 *
 * 검증 흐름
 *   setData(xmlString) → doSetData() → setValue(Element) → doSetValue()
 *   → TYPE_BIGDECIMAL 필드 + validation=true + 자릿수 초과 → InvalidAccessException
 *   → doSetData() catch → MessageSetDataException
 *
 * 시나리오
 *   A)   정상 XML → 예외 없음
 *   B)   정상 XML + validation=true → 예외 없음
 *   C-1) BIG_VALUE 정수부 초과(5자리) + validation=true  → MessageSetDataException
 *   C-2) BIG_VALUE 정수부 초과(5자리) + validation=false → 예외 없음
 *   D-1) BIG15_VALUE 소수점 포함(decimal=0 필드) + validation=true  → MessageSetDataException
 *   D-2) BIG15_VALUE 정수부 초과(16자리) + validation=true → MessageSetDataException
 *   E)   BIG15_VALUE 정상 정수(≤15자리) + validation=true → 예외 없음
 */
@DataJpaTest
@ContextConfiguration(classes = { TransformJPATestConfiguration.class })
@Sql({
    "/com/eactive/eai/transformer/init_tseaitr06.sql",
    "/com/eactive/eai/transformer/init_xml_validation.sql"
})
@DisplayName("XMLMessage BIGDECIMAL Validation 테스트")
class XMLMessageValidationTest {

    @Autowired
    TransformEngine engine;

    // BIG_VALUE: length=10, decimal=5 → 정수부 최대 4자리, 소수부 최대 5자리
    // BIG15_VALUE: length=15, decimal=0 → 정수부 최대 15자리, 소수점 없음
    private static final String VALID_XML =
        "<EAI_UXMLTYPE_REQ1>" +
            "<BIG_VALUE>1234.12345</BIG_VALUE>" +
            "<BIG15_VALUE>123000</BIG15_VALUE>" +
            "<STR_VALUE>HELLO</STR_VALUE>" +
        "</EAI_UXMLTYPE_REQ1>";

    @BeforeEach
    void setUp() {
        try {
            if (!engine.isStarted()) {
                engine.start();
            }
        } catch (Exception e) {
            assumeTrue(false, "TransformEngine 시작 실패: " + e.getMessage());
        }
    }

    @AfterEach
    void tearDown() {
        System.setProperty(SystemKeys.TRANSFROMER_VALIDATION, "false");
        System.setProperty(SystemKeys.TRANSFROMER_SCIENTIFIC_NORMALIZE, "false");
        SystemKeys.reload();
    }

    // ─────────────────────────────────────────────────────────────────
    // A. 정상 XML — validation 설정 무관
    // ─────────────────────────────────────────────────────────────────

    @Test
    @DisplayName("[A] 정상 XML → 예외 없음")
    void testValidXml() {
        Message msg = MessageFactory.getFactory().getMessage("EAI_UXMLTYPE_REQ1");
        assertDoesNotThrow(() -> msg.setData(VALID_XML),
            "정상 XML 파싱은 예외가 발생하지 않아야 합니다");
    }

    @Test
    @DisplayName("[B] 정상 XML + validation=true → 예외 없음")
    void testValidXml_withValidation() {
        enableValidation();
        Message msg = MessageFactory.getFactory().getMessage("EAI_UXMLTYPE_REQ1");
        assertDoesNotThrow(() -> msg.setData(VALID_XML),
            "정상값은 validation=true에서도 예외가 발생하지 않아야 합니다");
    }

    // ─────────────────────────────────────────────────────────────────
    // C. BIG_VALUE 정수부 초과 — validation 설정에 따른 동작 분기
    //    BIG_VALUE: length=10, decimal=5 → 정수부 최대 4자리
    //    "12345.12345" → 정수부 5자리 초과
    // ─────────────────────────────────────────────────────────────────

    @Test
    @DisplayName("[C-1] BIG_VALUE 정수부 초과(5자리) + validation=true → MessageSetDataException")
    void testBigValueIntegerOverflow_withValidation() {
        enableValidation();
        String xml =
            "<EAI_UXMLTYPE_REQ1>" +
                "<BIG_VALUE>12345.12345</BIG_VALUE>" +
                "<BIG15_VALUE>123000</BIG15_VALUE>" +
                "<STR_VALUE>HELLO</STR_VALUE>" +
            "</EAI_UXMLTYPE_REQ1>";
        Message msg = MessageFactory.getFactory().getMessage("EAI_UXMLTYPE_REQ1");
        assertThrows(MessageSetDataException.class, () -> msg.setData(xml),
            "정수부 자릿수 초과 시 validation=true이면 MessageSetDataException이 발생해야 합니다");
    }

    @Test
    @DisplayName("[C-2] BIG_VALUE 정수부 초과(5자리) + validation=false → 예외 없음")
    void testBigValueIntegerOverflow_withoutValidation() {
        // validation=false (기본값)
        String xml =
            "<EAI_UXMLTYPE_REQ1>" +
                "<BIG_VALUE>12345.12345</BIG_VALUE>" +
                "<BIG15_VALUE>123000</BIG15_VALUE>" +
                "<STR_VALUE>HELLO</STR_VALUE>" +
            "</EAI_UXMLTYPE_REQ1>";
        Message msg = MessageFactory.getFactory().getMessage("EAI_UXMLTYPE_REQ1");
        assertDoesNotThrow(() -> msg.setData(xml),
            "validation=false(기본값) 상태에서는 자릿수 초과에도 예외가 발생하지 않아야 합니다");
    }

    // ─────────────────────────────────────────────────────────────────
    // D. BIG15_VALUE (decimal=0 필드) 오류 케이스
    //    D-1) 소수점 포함값 — decimal=0은 정수 전용, 소수점 자체가 오류
    //    D-2) 정수부 초과 — 16자리 > 15자리 제한
    // ─────────────────────────────────────────────────────────────────

    @Test
    @DisplayName("[D-1] BIG15_VALUE decimal=0 필드에 소수점 포함값 + validation=true → MessageSetDataException")
    void testBig15ValueWithDecimalPoint_withValidation() {
        enableValidation();
        String xml =
            "<EAI_UXMLTYPE_REQ1>" +
                "<BIG_VALUE>1234.12345</BIG_VALUE>" +
                "<BIG15_VALUE>123.456</BIG15_VALUE>" +
                "<STR_VALUE>HELLO</STR_VALUE>" +
            "</EAI_UXMLTYPE_REQ1>";
        Message msg = MessageFactory.getFactory().getMessage("EAI_UXMLTYPE_REQ1");
        assertThrows(MessageSetDataException.class, () -> msg.setData(xml),
            "decimal=0 필드에 소수점 포함값 입력 시 validation=true이면 MessageSetDataException이 발생해야 합니다");
    }

    @Test
    @DisplayName("[D-2] BIG15_VALUE 정수부 초과(16자리) + validation=true → MessageSetDataException")
    void testBig15ValueIntegerOverflow_withValidation() {
        enableValidation();
        String xml =
            "<EAI_UXMLTYPE_REQ1>" +
                "<BIG_VALUE>1234.12345</BIG_VALUE>" +
                "<BIG15_VALUE>1234567890123456</BIG15_VALUE>" +
                "<STR_VALUE>HELLO</STR_VALUE>" +
            "</EAI_UXMLTYPE_REQ1>";
        Message msg = MessageFactory.getFactory().getMessage("EAI_UXMLTYPE_REQ1");
        assertThrows(MessageSetDataException.class, () -> msg.setData(xml),
            "정수부 16자리(>15) 초과 시 validation=true이면 MessageSetDataException이 발생해야 합니다");
    }

    // ─────────────────────────────────────────────────────────────────
    // E. BIG15_VALUE 정상 정수 (≤15자리) + validation=true → 예외 없음
    // ─────────────────────────────────────────────────────────────────

    @Test
    @DisplayName("[E] BIG15_VALUE 정상 정수(≤15자리) + validation=true → 예외 없음")
    void testBig15ValueValidInteger_withValidation() {
        enableValidation();
        Message msg = MessageFactory.getFactory().getMessage("EAI_UXMLTYPE_REQ1");
        assertDoesNotThrow(() -> msg.setData(VALID_XML),
            "15자리 이내 정수 입력 시 validation=true에서도 예외가 발생하지 않아야 합니다");
    }

    // ─────────────────────────────────────────────────────────────────
    // F. 빈 요소 / 요소 없음 — 경계 케이스
    //    F-1) 빈 요소(<BIG_VALUE/>) + validation=true  → 예외 없음
    //         dom4j는 빈 요소의 getData()를 null로 반환
    //         → null instanceof String = false → 검증 건너뜀 → 요소 없음과 동일 동작
    //    F-2) 빈 요소(<BIG_VALUE/>) + validation=false → 예외 없음
    //    F-3) 요소 없음(BIG_VALUE 미포함 XML) + validation=true → 예외 없음
    //         XML에 요소가 없으면 doSetValue() 순회 대상이 없어 검증 자체가 실행되지 않음
    // ─────────────────────────────────────────────────────────────────

    @Test
    @DisplayName("[F-1] BIG_VALUE 빈 요소(<BIG_VALUE/>) + validation=true → 예외 없음 (dom4j null 반환)")
    void testBigValueEmptyElement_withValidation() {
        enableValidation();
        // dom4j는 빈 요소의 getData()를 null로 반환 → null instanceof String = false → 검증 건너뜀
        String xml =
            "<EAI_UXMLTYPE_REQ1>" +
                "<BIG_VALUE></BIG_VALUE>" +
                "<BIG15_VALUE>123000</BIG15_VALUE>" +
                "<STR_VALUE>HELLO</STR_VALUE>" +
            "</EAI_UXMLTYPE_REQ1>";
        Message msg = MessageFactory.getFactory().getMessage("EAI_UXMLTYPE_REQ1");
        assertDoesNotThrow(() -> msg.setData(xml),
            "dom4j 빈 요소는 null로 처리되어 검증 대상이 아니므로 예외가 발생하지 않아야 합니다");
    }

    @Test
    @DisplayName("[F-2] BIG_VALUE 빈 문자열 + validation=false → 예외 없음")
    void testBigValueEmptyString_withoutValidation() {
        // validation=false (기본값)
        String xml =
            "<EAI_UXMLTYPE_REQ1>" +
                "<BIG_VALUE></BIG_VALUE>" +
                "<BIG15_VALUE>123000</BIG15_VALUE>" +
                "<STR_VALUE>HELLO</STR_VALUE>" +
            "</EAI_UXMLTYPE_REQ1>";
        Message msg = MessageFactory.getFactory().getMessage("EAI_UXMLTYPE_REQ1");
        assertDoesNotThrow(() -> msg.setData(xml),
            "validation=false(기본값) 상태에서는 빈 문자열도 예외가 발생하지 않아야 합니다");
    }

    @Test
    @DisplayName("[F-3] BIG_VALUE 요소 없음 + validation=true → 예외 없음")
    void testBigValueMissingElement_withValidation() {
        enableValidation();
        // BIG_VALUE 요소 자체를 XML에서 제외
        String xml =
            "<EAI_UXMLTYPE_REQ1>" +
                "<BIG15_VALUE>123000</BIG15_VALUE>" +
                "<STR_VALUE>HELLO</STR_VALUE>" +
            "</EAI_UXMLTYPE_REQ1>";
        Message msg = MessageFactory.getFactory().getMessage("EAI_UXMLTYPE_REQ1");
        assertDoesNotThrow(() -> msg.setData(xml),
            "XML에 요소가 없으면 검증 대상이 아니므로 예외가 발생하지 않아야 합니다");
    }

    // ─────────────────────────────────────────────────────────────────
    // 유틸 메서드
    // ─────────────────────────────────────────────────────────────────

    private void enableValidation() {
        System.setProperty(SystemKeys.TRANSFROMER_VALIDATION, "true");
        SystemKeys.reload();
    }
}
