package incheon.product.geoview3d.simulation.service.impl;

import incheon.product.geoview3d.simulation.mapper.SimulationMapper;
import incheon.product.geoview3d.simulation.vo.SubwayVO;
import incheon.product.geoview3d.simulation.vo.TilesetClippingVO;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;

/**
 * SimulationServiceImpl 단위 테스트.
 * 시뮬레이션 데이터 조회 및 지하철 데이터 집계를 검증한다.
 */
@ExtendWith(MockitoExtension.class)
class SimulationServiceImplTest {

    @InjectMocks
    private SimulationServiceImpl simulationService;

    @Mock
    private SimulationMapper simulationMapper;

    @Test
    @DisplayName("getSimulationJson은 mapper에 위임한다")
    void getSimulationJson() {
        when(simulationMapper.selectSimulationJson("sim1")).thenReturn("{\"data\":1}");

        String result = simulationService.getSimulationJson("sim1");

        assertThat(result).isEqualTo("{\"data\":1}");
        verify(simulationMapper).selectSimulationJson("sim1");
    }

    @Test
    @DisplayName("getClipping은 mapper에 위임한다")
    void getClipping() {
        TilesetClippingVO expected = new TilesetClippingVO();
        expected.setClipId("clip1");
        when(simulationMapper.selectTilesetClipping("clip1")).thenReturn(expected);

        TilesetClippingVO result = simulationService.getClipping("clip1");

        assertThat(result).isEqualTo(expected);
    }

    @Nested
    @DisplayName("getSubway — 지하철 데이터 집계")
    class GetSubway {

        @Test
        @DisplayName("지하철 노선 조회 후 역사 형태와 역사 목록을 추가 조회한다")
        void aggregatesSubwayData() {
            SubwayVO subway = new SubwayVO();
            subway.setSubwayName("1호선");

            SubwayVO.SubwayStationShpVO shp = new SubwayVO.SubwayStationShpVO();
            shp.setName("부평");

            SubwayVO.SubwayStationVO station = new SubwayVO.SubwayStationVO();
            station.setName("부평역");

            when(simulationMapper.selectSubwayByName("1호선")).thenReturn(subway);
            when(simulationMapper.selectStationShpsBySubwayName("1호선")).thenReturn(List.of(shp));
            when(simulationMapper.selectStationsBySubwayName("1호선")).thenReturn(List.of(station));

            SubwayVO result = simulationService.getSubway("1호선");

            assertThat(result).isNotNull();
            assertThat(result.getStationShapes()).hasSize(1);
            assertThat(result.getStationShapes()[0].getName()).isEqualTo("부평");
            assertThat(result.getStations()).hasSize(1);
            assertThat(result.getStations()[0].getName()).isEqualTo("부평역");
        }

        @Test
        @DisplayName("지하철 노선이 없으면 null을 반환하고 추가 조회를 하지 않는다")
        void nullSubwaySkipsAggregation() {
            when(simulationMapper.selectSubwayByName("없는노선")).thenReturn(null);

            SubwayVO result = simulationService.getSubway("없는노선");

            assertThat(result).isNull();
            verify(simulationMapper, never()).selectStationShpsBySubwayName(anyString());
            verify(simulationMapper, never()).selectStationsBySubwayName(anyString());
        }
    }
}
