package dev.awesomedev.mirim.service;

import dev.awesomedev.mirim.domain.ChecklistItem;
import dev.awesomedev.mirim.domain.Progress;
import dev.awesomedev.mirim.domain.User;
import dev.awesomedev.mirim.repository.ChecklistItemRepository;
import dev.awesomedev.mirim.repository.ProgressRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.web.server.ResponseStatusException;

import java.util.Optional;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

/**
 * 이 파일이 하는 일:
 * ProgressService의 토글 로직을 검증하는 단위 테스트다.
 *
 * 학습 포인트: 단위 테스트는 DB 없이 돌아간다.
 * Mockito로 리포지토리를 "가짜(mock)"로 바꿔치기해서
 * 서비스의 분기 로직(체크/해제/404)만 빠르게 검증한다.
 */
class ProgressServiceTest {

    private ProgressRepository progressRepository;
    private ChecklistItemRepository checklistItemRepository;
    private ProgressService progressService;

    private User student;
    private ChecklistItem item;

    @BeforeEach
    void setUp() {
        progressRepository = mock(ProgressRepository.class);
        checklistItemRepository = mock(ChecklistItemRepository.class);
        progressService = new ProgressService(progressRepository, checklistItemRepository);

        student = new User("student1", "해시값", "수습생1", "STUDENT", "DEV");
        item = new ChecklistItem(1, 1, "개발 환경 설치 완료", 1);
    }

    @Test
    @DisplayName("체크 안 된 항목을 토글하면 체크 기록이 저장되고 true를 반환한다")
    void toggle_checks_when_not_checked() {
        when(checklistItemRepository.findById(10L)).thenReturn(Optional.of(item));
        when(progressRepository.findByUserAndItem(student, item)).thenReturn(Optional.empty());

        boolean checked = progressService.toggle(student, 10L);

        assertTrue(checked);
        verify(progressRepository).save(any(Progress.class)); // 새 체크 기록이 저장됐는지 확인
        verify(progressRepository, never()).delete(any());
    }

    @Test
    @DisplayName("이미 체크된 항목을 토글하면 체크 기록이 삭제되고 false를 반환한다")
    void toggle_unchecks_when_already_checked() {
        Progress existing = new Progress(student, item);
        when(checklistItemRepository.findById(10L)).thenReturn(Optional.of(item));
        when(progressRepository.findByUserAndItem(student, item)).thenReturn(Optional.of(existing));

        boolean checked = progressService.toggle(student, 10L);

        assertFalse(checked);
        verify(progressRepository).delete(existing); // 기존 기록이 삭제됐는지 확인
        verify(progressRepository, never()).save(any());
    }

    @Test
    @DisplayName("존재하지 않는 항목을 토글하면 404 예외가 발생한다")
    void toggle_throws_404_when_item_missing() {
        when(checklistItemRepository.findById(999L)).thenReturn(Optional.empty());

        ResponseStatusException exception = assertThrows(ResponseStatusException.class,
                () -> progressService.toggle(student, 999L));

        assertEquals(404, exception.getStatusCode().value());
    }
}
