package com.eactive.eai.transformer;

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

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import com.eactive.eai.transformer.engine.Parser;
import com.eactive.eai.transformer.function.generic.ConcatN;

/**
 * ParserTest 스타일로 Parser 를 통해 concatN 함수를 검증한다.
 *
 * - 표현식은 parse() 한 번 → 변수값만 교체하며 반복 평가 (JEP 재사용 패턴)
 * - 변수 : parser.addVariable() 로 바인딩
 * - 상수 : 표현식 안에 "문자열" 리터럴로 직접 기입
 */
@DisplayName("ConcatN - Parser 변수/상수 혼합 테스트")
class ConcatNParserTest {

    private Parser parser;

    @BeforeEach
    void setUp() {
        parser = new Parser();
        // DB 등록 전 테스트이므로 직접 등록
        parser.getJep().addFunction("concatn", new ConcatN());
    }

    // ─────────────────────────────────────────────────────────────────
    // 1. 변수만 사용
    // ─────────────────────────────────────────────────────────────────

    @Test
    @DisplayName("변수 2개 — parse 1회, 값 교체 반복 평가")
    void testTwoVariables() throws Exception {
        parser.parse("concatn(a, b)");

        parser.addVariable("a", "Hello");
        parser.addVariable("b", "World");
        assertEquals("HelloWorld", parser.getValueAsObject());

        parser.addVariable("a", "foo");
        parser.addVariable("b", "bar");
        assertEquals("foobar", parser.getValueAsObject());
    }

    @Test
    @DisplayName("변수 3개")
    void testThreeVariables() throws Exception {
        parser.parse("concatn(v1, v2, v3)");

        parser.addVariable("v1", "AAA");
        parser.addVariable("v2", "BBB");
        parser.addVariable("v3", "CCC");
        assertEquals("AAABBBCCC", parser.getValueAsObject());
    }

    @Test
    @DisplayName("변수 5개")
    void testFiveVariables() throws Exception {
        parser.parse("concatn(y, m, d, h, mi)");

        parser.addVariable("y",  "2024");
        parser.addVariable("m",  "05");
        parser.addVariable("d",  "08");
        parser.addVariable("h",  "14");
        parser.addVariable("mi", "30");
        assertEquals("20240508" + "14" + "30", parser.getValueAsObject());
    }

    // ─────────────────────────────────────────────────────────────────
    // 2. 변수 + 상수(리터럴) 혼합
    // ─────────────────────────────────────────────────────────────────

    @Test
    @DisplayName("날짜 구분자 '-' 상수 삽입 — 변수 교체 반복")
    void testDateWithSeparator() throws Exception {
        parser.parse("concatn(year, \"-\", month, \"-\", day)");

        parser.addVariable("year",  "2024");
        parser.addVariable("month", "01");
        parser.addVariable("day",   "15");
        assertEquals("2024-01-15", parser.getValueAsObject());

        parser.addVariable("year",  "2025");
        parser.addVariable("month", "12");
        parser.addVariable("day",   "31");
        assertEquals("2025-12-31", parser.getValueAsObject());
    }

    @Test
    @DisplayName("접두·접미 상수로 감싸기")
    void testWrapWithConstants() throws Exception {
        parser.parse("concatn(\"[\", code, \"-\", seq, \"]\")");

        parser.addVariable("code", "KOR");
        parser.addVariable("seq",  "001");
        assertEquals("[KOR-001]", parser.getValueAsObject());

        parser.addVariable("code", "USA");
        parser.addVariable("seq",  "999");
        assertEquals("[USA-999]", parser.getValueAsObject());
    }

    @Test
    @DisplayName("앞에 상수 접두어 + 변수 1개")
    void testConstantPrefix() throws Exception {
        parser.parse("concatn(\"REQ-\", txId)");

        parser.addVariable("txId", "20240508001");
        assertEquals("REQ-20240508001", parser.getValueAsObject());

        parser.addVariable("txId", "20240508002");
        assertEquals("REQ-20240508002", parser.getValueAsObject());
    }

    @Test
    @DisplayName("변수 사이에 공백 상수 삽입")
    void testSpaceSeparator() throws Exception {
        parser.parse("concatn(firstName, \" \", lastName)");

        parser.addVariable("firstName", "Gil-dong");
        parser.addVariable("lastName",  "Hong");
        assertEquals("Gil-dong Hong", parser.getValueAsObject());
    }

    // ─────────────────────────────────────────────────────────────────
    // 3. 성능 측정 (ParserTest 스타일)
    // ─────────────────────────────────────────────────────────────────

    @Test
    @DisplayName("100만 회 반복 평가 — parse 1회 재사용 성능")
    void testPerformance() throws Exception {
        String expr = "concatn(code, \"-\", seq)";
        parser.parse(expr);

        Object result = null;
        long t = System.currentTimeMillis();
        for (int i = 0; i < 1_000_000; i++) {
            parser.addVariable("code", "KOR");
            parser.addVariable("seq",  String.valueOf(i));
            result = parser.getValueAsObject();
        }
        long elapsed = System.currentTimeMillis() - t;

        System.out.println(String.format("%s = %s  %dms", expr, result, elapsed));

        assertEquals("KOR-999999", result);
    }
}
