package com.erp.batch;

import org.junit.jupiter.api.Test;

import java.util.*;

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

/**
 * Phase 3 검증 — vexplor_rps L550~617 알고리즘 1:1 이식 결과가 정상 동작하는지.
 *
 * 외부 의존 없는 순수 함수만 검증.
 */
class MappingTransformerTest {

    // ── evaluateConditional ───────────────────────────────────────────────

    @Test
    void evaluateConditional_단순_매칭() {
        MappingTransformer.ConditionalConfig cfg = new MappingTransformer.ConditionalConfig();
        cfg.rules.add(new MappingTransformer.ConditionalRule("1", "Y"));
        cfg.rules.add(new MappingTransformer.ConditionalRule("0", "N"));
        cfg.defaultValue = "?";

        assertEquals("Y", MappingTransformer.evaluateConditional("1", cfg));
        assertEquals("N", MappingTransformer.evaluateConditional("0", cfg));
        assertEquals("?", MappingTransformer.evaluateConditional("9", cfg)); // 매칭 없음 → default
    }

    @Test
    void evaluateConditional_null_cfg_안전() {
        assertNull(MappingTransformer.evaluateConditional("anything", null));
    }

    @Test
    void evaluateConditional_빈_rules_default만() {
        MappingTransformer.ConditionalConfig cfg = new MappingTransformer.ConditionalConfig();
        cfg.defaultValue = "fallback";
        assertEquals("fallback", MappingTransformer.evaluateConditional("anything", cfg));
    }

    // ── parseConditionalConfig (JSONB normalize) ──────────────────────────

    @Test
    void parseConditionalConfig_Map_입력() {
        Map<String, Object> raw = new LinkedHashMap<>();
        raw.put("rules", List.of(Map.of("when", "1", "then", "Y")));
        raw.put("default", "?");

        MappingTransformer.ConditionalConfig cfg = MappingTransformer.parseConditionalConfig(raw);
        assertEquals(1, cfg.rules.size());
        assertEquals("1", cfg.rules.get(0).when);
        assertEquals("Y", cfg.rules.get(0).then);
        assertEquals("?", cfg.defaultValue);
    }

    @Test
    void parseConditionalConfig_String_JSON_입력() {
        String json = "{\"rules\":[{\"when\":\"J01\",\"then\":\"active\"}],\"default\":\"\"}";
        MappingTransformer.ConditionalConfig cfg = MappingTransformer.parseConditionalConfig(json);
        assertEquals(1, cfg.rules.size());
        assertEquals("J01", cfg.rules.get(0).when);
        assertEquals("active", cfg.rules.get(0).then);
        assertEquals("", cfg.defaultValue);
    }

    @Test
    void parseConditionalConfig_null_빈cfg() {
        MappingTransformer.ConditionalConfig cfg = MappingTransformer.parseConditionalConfig(null);
        assertNotNull(cfg);
        assertTrue(cfg.rules.isEmpty());
    }

    @Test
    void parseConditionalConfig_손상된_JSON_빈cfg() {
        MappingTransformer.ConditionalConfig cfg = MappingTransformer.parseConditionalConfig("{not json");
        assertNotNull(cfg);
        assertTrue(cfg.rules.isEmpty());
    }

    // ── getValueByPath (점 표기법) ─────────────────────────────────────────

    @Test
    void getValueByPath_단순_키() {
        Map<String, Object> obj = Map.of("name", "alice");
        assertEquals("alice", MappingTransformer.getValueByPath(obj, "name"));
    }

    @Test
    void getValueByPath_중첩_경로() {
        Map<String, Object> obj = Map.of("response", Map.of("access_token", "xyz"));
        assertEquals("xyz", MappingTransformer.getValueByPath(obj, "response.access_token"));
    }

    @Test
    void getValueByPath_없는_경로_null() {
        Map<String, Object> obj = Map.of("name", "alice");
        assertNull(MappingTransformer.getValueByPath(obj, "missing.path"));
        assertNull(MappingTransformer.getValueByPath(obj, "name.deeper"));
    }

    @Test
    void getValueByPath_null_obj_안전() {
        assertNull(MappingTransformer.getValueByPath(null, "anything"));
    }

    // ── partitionFixed ────────────────────────────────────────────────────

    @Test
    void partitionFixed_분리() {
        List<Map<String, Object>> mappings = List.of(
                Map.of("mapping_type", "direct", "to_column_name", "a"),
                Map.of("mapping_type", "fixed", "to_column_name", "b"),
                Map.of("mapping_type", "conditional", "to_column_name", "c")
        );
        MappingTransformer.Partition p = MappingTransformer.partitionFixed(mappings);
        assertEquals(2, p.nonFixed.size());
        assertEquals(1, p.fixed.size());
        assertEquals("b", p.fixed.get(0).get("to_column_name"));
    }

    // ── transformRow (통합) ───────────────────────────────────────────────

    @Test
    void transformRow_direct_매핑() {
        Map<String, Object> row = Map.of("user_id", "alice", "email", "a@x.com");
        List<Map<String, Object>> nonFixed = List.of(
                Map.of("mapping_type", "direct",
                        "from_column_name", "user_id",
                        "to_column_name", "USER_ID"),
                Map.of("mapping_type", "direct",
                        "from_column_name", "email",
                        "to_column_name", "EMAIL_ADDR")
        );
        Map<String, Object> mapped = MappingTransformer.transformRow(
                row, nonFixed, List.of(), "internal", "COMPANY_1");
        assertEquals("alice", mapped.get("USER_ID"));
        assertEquals("a@x.com", mapped.get("EMAIL_ADDR"));
        assertEquals("COMPANY_1", mapped.get("company_code")); // 자동 주입
    }

    @Test
    void transformRow_conditional_매핑_1을_Y로() {
        Map<String, Object> row = Map.of("active_flag", "1");
        List<Map<String, Object>> nonFixed = List.of(
                new HashMap<>(Map.of(
                        "mapping_type", "conditional",
                        "from_column_name", "active_flag",
                        "to_column_name", "IS_ACTIVE",
                        "mapping_config", Map.of(
                                "rules", List.of(
                                        Map.of("when", "1", "then", "Y"),
                                        Map.of("when", "0", "then", "N")),
                                "default", "?")))
        );
        Map<String, Object> mapped = MappingTransformer.transformRow(
                row, nonFixed, List.of(), "internal", null);
        assertEquals("Y", mapped.get("IS_ACTIVE"));
    }

    @Test
    void transformRow_conditional_매핑_default_폴백() {
        Map<String, Object> row = Map.of("active_flag", "9"); // 어떤 룰에도 매칭 안 됨
        List<Map<String, Object>> nonFixed = List.of(
                new HashMap<>(Map.of(
                        "mapping_type", "conditional",
                        "from_column_name", "active_flag",
                        "to_column_name", "IS_ACTIVE",
                        "mapping_config", Map.of(
                                "rules", List.of(Map.of("when", "1", "then", "Y")),
                                "default", "?")))
        );
        Map<String, Object> mapped = MappingTransformer.transformRow(
                row, nonFixed, List.of(), "internal", null);
        assertEquals("?", mapped.get("IS_ACTIVE"));
    }

    @Test
    void transformRow_fixed_매핑_적용() {
        Map<String, Object> row = Map.of("user_id", "alice");
        List<Map<String, Object>> nonFixed = List.of(
                Map.of("mapping_type", "direct",
                        "from_column_name", "user_id",
                        "to_column_name", "USER_ID")
        );
        List<Map<String, Object>> fixed = List.of(
                Map.of("mapping_type", "fixed",
                        "from_column_name", "BATCH_001",
                        "to_column_name", "SOURCE_BATCH")
        );
        Map<String, Object> mapped = MappingTransformer.transformRow(
                row, nonFixed, fixed, "internal", null);
        assertEquals("alice", mapped.get("USER_ID"));
        assertEquals("BATCH_001", mapped.get("SOURCE_BATCH"));
    }

    @Test
    void transformRow_점_표기법_API_응답() {
        Map<String, Object> row = Map.of(
                "user", Map.of("profile", Map.of("name", "박창현"))
        );
        List<Map<String, Object>> nonFixed = List.of(
                Map.of("mapping_type", "direct",
                        "from_column_name", "user.profile.name",
                        "to_column_name", "USER_NAME")
        );
        Map<String, Object> mapped = MappingTransformer.transformRow(
                row, nonFixed, List.of(), "internal", null);
        assertEquals("박창현", mapped.get("USER_NAME"));
    }

    @Test
    void transformRow_to_가_restapi_면_company_code_자동주입_안함() {
        Map<String, Object> row = Map.of("user_id", "alice");
        List<Map<String, Object>> nonFixed = List.of(
                Map.of("mapping_type", "direct",
                        "from_column_name", "user_id",
                        "to_column_name", "USER_ID")
        );
        Map<String, Object> mapped = MappingTransformer.transformRow(
                row, nonFixed, List.of(), "restapi", "COMPANY_1");
        assertFalse(mapped.containsKey("company_code"));
    }
}
