package com.kt.event.participation.test.integration;

import com.kt.event.participation.domain.draw.DrawLog;
import com.kt.event.participation.domain.draw.DrawLogRepository;
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 java.time.LocalDateTime;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

/**
 * DrawLogRepository 통합 테스트
 *
 * @author Digital Garage Team
 * @since 2025-01-24
 */
@DataJpaTest
@DisplayName("DrawLogRepository 통합 테스트")
class DrawLogRepositoryIntegrationTest {

    @Autowired
    private DrawLogRepository drawLogRepository;

    // 테스트 데이터 상수
    private static final String VALID_EVENT_ID = "evt_20250124_001";
    private static final Integer TOTAL_PARTICIPANTS = 100;
    private static final Integer WINNER_COUNT = 10;
    private static final String ALGORITHM = "WEIGHTED_RANDOM";
    private static final String DRAWN_BY = "SYSTEM";

    @BeforeEach
    void setUp() {
        drawLogRepository.deleteAll();
    }

    @Test
    @DisplayName("추첨 로그를 저장하면 정상적으로 조회할 수 있다")
    void givenDrawLog_whenSave_thenCanRetrieve() {
        // Given
        DrawLog drawLog = createDrawLog(VALID_EVENT_ID, true);

        // When
        DrawLog saved = drawLogRepository.save(drawLog);

        // Then
        assertThat(saved.getId()).isNotNull();
        assertThat(saved.getEventId()).isEqualTo(VALID_EVENT_ID);
        assertThat(saved.getTotalParticipants()).isEqualTo(TOTAL_PARTICIPANTS);
        assertThat(saved.getWinnerCount()).isEqualTo(WINNER_COUNT);
    }

    @Test
    @DisplayName("이벤트 ID로 추첨 로그를 조회할 수 있다")
    void givenSavedDrawLog_whenFindByEventId_thenReturnDrawLog() {
        // Given
        DrawLog drawLog = createDrawLog(VALID_EVENT_ID, true);
        drawLogRepository.save(drawLog);

        // When
        Optional<DrawLog> found = drawLogRepository.findByEventId(VALID_EVENT_ID);

        // Then
        assertThat(found).isPresent();
        assertThat(found.get().getEventId()).isEqualTo(VALID_EVENT_ID);
        assertThat(found.get().getApplyStoreVisitBonus()).isTrue();
    }

    @Test
    @DisplayName("존재하지 않는 이벤트 ID로 조회하면 Empty가 반환된다")
    void givenNoDrawLog_whenFindByEventId_thenReturnEmpty() {
        // Given
        String nonExistentEventId = "evt_99999999_999";

        // When
        Optional<DrawLog> found = drawLogRepository.findByEventId(nonExistentEventId);

        // Then
        assertThat(found).isEmpty();
    }

    @Test
    @DisplayName("이벤트 ID로 추첨 여부를 확인할 수 있다")
    void givenSavedDrawLog_whenExistsByEventId_thenReturnTrue() {
        // Given
        DrawLog drawLog = createDrawLog(VALID_EVENT_ID, false);
        drawLogRepository.save(drawLog);

        // When
        boolean exists = drawLogRepository.existsByEventId(VALID_EVENT_ID);

        // Then
        assertThat(exists).isTrue();
    }

    @Test
    @DisplayName("추첨이 없는 이벤트 ID로 확인하면 false가 반환된다")
    void givenNoDrawLog_whenExistsByEventId_thenReturnFalse() {
        // Given
        String nonExistentEventId = "evt_99999999_999";

        // When
        boolean exists = drawLogRepository.existsByEventId(nonExistentEventId);

        // Then
        assertThat(exists).isFalse();
    }

    @Test
    @DisplayName("매장 방문 보너스 미적용 추첨 로그를 저장할 수 있다")
    void givenDrawLogWithoutBonus_whenSave_thenCanRetrieve() {
        // Given
        DrawLog drawLog = createDrawLog(VALID_EVENT_ID, false);

        // When
        DrawLog saved = drawLogRepository.save(drawLog);

        // Then
        assertThat(saved.getApplyStoreVisitBonus()).isFalse();
    }

    @Test
    @DisplayName("추첨 로그의 모든 필드가 정상적으로 저장된다")
    void givenCompleteDrawLog_whenSave_thenAllFieldsPersisted() {
        // Given
        LocalDateTime now = LocalDateTime.now();
        DrawLog drawLog = DrawLog.builder()
                .eventId(VALID_EVENT_ID)
                .totalParticipants(TOTAL_PARTICIPANTS)
                .winnerCount(WINNER_COUNT)
                .applyStoreVisitBonus(true)
                .algorithm(ALGORITHM)
                .drawnAt(now)
                .drawnBy(DRAWN_BY)
                .build();

        // When
        DrawLog saved = drawLogRepository.save(drawLog);

        // Then
        assertThat(saved.getId()).isNotNull();
        assertThat(saved.getEventId()).isEqualTo(VALID_EVENT_ID);
        assertThat(saved.getTotalParticipants()).isEqualTo(TOTAL_PARTICIPANTS);
        assertThat(saved.getWinnerCount()).isEqualTo(WINNER_COUNT);
        assertThat(saved.getApplyStoreVisitBonus()).isTrue();
        assertThat(saved.getAlgorithm()).isEqualTo(ALGORITHM);
        assertThat(saved.getDrawnAt()).isEqualToIgnoringNanos(now);
        assertThat(saved.getDrawnBy()).isEqualTo(DRAWN_BY);
    }

    // 헬퍼 메서드
    private DrawLog createDrawLog(String eventId, boolean applyBonus) {
        return DrawLog.builder()
                .eventId(eventId)
                .totalParticipants(TOTAL_PARTICIPANTS)
                .winnerCount(WINNER_COUNT)
                .applyStoreVisitBonus(applyBonus)
                .algorithm(ALGORITHM)
                .drawnAt(LocalDateTime.now())
                .drawnBy(DRAWN_BY)
                .build();
    }
}
