package gc.mda.signal_batch.global.util;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import org.junit.jupiter.params.provider.NullAndEmptySource;
import org.junit.jupiter.params.provider.ValueSource;

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

class SignalKindCodeTest {

    @Nested
    @DisplayName("vesselType 단독 매칭")
    class VesselTypeDirect {

        @ParameterizedTest
        @CsvSource({
            "Cargo,     000023",
            "Tanker,    000024",
            "Passenger, 000022",
            "AtoN,      000028",
            "Law Enforcement, 000025",
            "Search and Rescue, 000021",
            "Local Vessel, 000020"
        })
        @DisplayName("vesselType 직접 매칭 시 올바른 코드 반환")
        void resolve_directMatch(String vesselType, String expectedCode) {
            assertEquals(expectedCode, SignalKindCode.resolve(vesselType, null).getCode());
        }
    }

    @Nested
    @DisplayName("vesselType 그룹 매칭")
    class VesselTypeGroup {

        @ParameterizedTest
        @CsvSource({
            "Tug,              000025",
            "Pilot Boat,       000025",
            "Tender,           000025",
            "Anti Pollution,   000025",
            "Medical Transport, 000025",
            "High Speed Craft, 000022",
            "Wing in Ground-effect, 000022"
        })
        @DisplayName("vesselType 그룹 매칭 시 올바른 코드 반환")
        void resolve_groupMatch(String vesselType, String expectedCode) {
            assertEquals(expectedCode, SignalKindCode.resolve(vesselType, null).getCode());
        }
    }

    @Nested
    @DisplayName("Vessel + extraInfo 조합")
    class VesselWithExtraInfo {

        @ParameterizedTest
        @CsvSource({
            "Vessel, Fishing,              000020",
            "Vessel, Military Operations,  000025",
            "Vessel, Towing,               000025",
            "Vessel, Towing (Large),       000025",
            "Vessel, Dredging/Underwater Ops, 000025",
            "Vessel, Diving Operations,    000025",
            "Vessel, Pleasure Craft,       000020",
            "Vessel, Sailing,              000020",
            "Vessel, N/A,                  000020",
            "Vessel, Hazardous Cat A,      000023",
            "Vessel, Hazardous Cat B,      000023",
            "Vessel, Unknown,              000027"
        })
        @DisplayName("Vessel + extraInfo 조합으로 올바른 코드 반환")
        void resolve_vesselWithExtraInfo(String vesselType, String extraInfo, String expectedCode) {
            assertEquals(expectedCode, SignalKindCode.resolve(vesselType, extraInfo).getCode());
        }
    }

    @Nested
    @DisplayName("N/A + extraInfo 조합")
    class NaWithExtraInfo {

        @Test
        @DisplayName("N/A + hazardous cat → CARGO")
        void resolve_naWithHazardous() {
            assertEquals("000023", SignalKindCode.resolve("N/A", "Hazardous Cat X").getCode());
        }

        @Test
        @DisplayName("N/A + 기타 → DEFAULT")
        void resolve_naWithOther() {
            assertEquals("000027", SignalKindCode.resolve("N/A", "Other").getCode());
        }
    }

    @Nested
    @DisplayName("Null/Blank 처리")
    class NullBlank {

        @ParameterizedTest
        @NullAndEmptySource
        @ValueSource(strings = {"  ", "\t"})
        @DisplayName("vesselType가 null/blank이면 DEFAULT 반환")
        void resolve_nullOrBlankVesselType(String vesselType) {
            assertEquals(SignalKindCode.DEFAULT, SignalKindCode.resolve(vesselType, null));
        }

        @Test
        @DisplayName("vesselType과 extraInfo 모두 null이면 DEFAULT")
        void resolve_bothNull() {
            assertEquals(SignalKindCode.DEFAULT, SignalKindCode.resolve(null, null));
        }
    }

    @Nested
    @DisplayName("Case insensitivity")
    class CaseInsensitive {

        @Test
        @DisplayName("대문자 CARGO도 매칭")
        void resolve_uppercase() {
            assertEquals(SignalKindCode.CARGO, SignalKindCode.resolve("CARGO", null));
        }

        @Test
        @DisplayName("대소문자 혼합 Passenger도 매칭")
        void resolve_mixedCase() {
            assertEquals(SignalKindCode.FERRY, SignalKindCode.resolve("Passenger", null));
        }

        @Test
        @DisplayName("extraInfo도 case insensitive")
        void resolve_extraInfoCaseInsensitive() {
            assertEquals(SignalKindCode.FISHING, SignalKindCode.resolve("VESSEL", "FISHING"));
        }
    }

    @Test
    @DisplayName("알 수 없는 vesselType은 DEFAULT 반환")
    void resolve_unknownType() {
        assertEquals(SignalKindCode.DEFAULT, SignalKindCode.resolve("UnknownType", null));
    }

    @Test
    @DisplayName("Enum 값의 code와 koreanName이 올바른지 확인")
    void enumValues_codeAndName() {
        assertEquals("000020", SignalKindCode.FISHING.getCode());
        assertEquals("어선", SignalKindCode.FISHING.getKoreanName());
        assertEquals("000028", SignalKindCode.BUOY.getCode());
        assertEquals("부이/항로표지", SignalKindCode.BUOY.getKoreanName());
    }
}
