package dev.awesomedev.mirim.service;

import dev.awesomedev.mirim.domain.User;
import dev.awesomedev.mirim.repository.CodingSubmissionRepository;
import dev.awesomedev.mirim.repository.CourseProgressRepository;
import dev.awesomedev.mirim.repository.ProgressRepository;
import dev.awesomedev.mirim.repository.QuizResultRepository;
import dev.awesomedev.mirim.repository.StudentProfileRepository;
import dev.awesomedev.mirim.repository.SubmissionRepository;
import dev.awesomedev.mirim.repository.UserRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.InOrder;
import org.springframework.web.server.ResponseStatusException;

import java.util.Optional;

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

/**
 * 이 파일이 하는 일:
 * 학생 파기의 두 핵심 규칙을 검증한다 — (1) 자식 데이터를 먼저, 계정을 나중에 지우는 순서,
 * (2) 멘토 계정 등 STUDENT가 아닌 대상은 파기하지 못하게 막는 것.
 */
class StudentPurgeServiceTest {

    private UserRepository userRepository;
    private StudentProfileRepository studentProfileRepository;
    private SubmissionRepository submissionRepository;
    private CodingSubmissionRepository codingSubmissionRepository;
    private ProgressRepository progressRepository;
    private CourseProgressRepository courseProgressRepository;
    private QuizResultRepository quizResultRepository;
    private StudentPurgeService service;

    @BeforeEach
    void setUp() {
        userRepository = mock(UserRepository.class);
        studentProfileRepository = mock(StudentProfileRepository.class);
        submissionRepository = mock(SubmissionRepository.class);
        codingSubmissionRepository = mock(CodingSubmissionRepository.class);
        progressRepository = mock(ProgressRepository.class);
        courseProgressRepository = mock(CourseProgressRepository.class);
        quizResultRepository = mock(QuizResultRepository.class);
        service = new StudentPurgeService(userRepository, studentProfileRepository,
                submissionRepository, codingSubmissionRepository, progressRepository,
                courseProgressRepository, quizResultRepository, mock(TelegramNotifier.class));
    }

    @Test
    @DisplayName("학생 파기: 자식 데이터를 먼저 지우고 계정을 마지막에 지운다 (외래키 순서)")
    void purge_deletes_children_before_user() {
        User student = new User("s1", "해시", "임학생", "STUDENT", "DEV");
        when(userRepository.findById(1L)).thenReturn(Optional.of(student));

        service.purge(1L);

        // 계정 삭제(userRepository.delete)는 반드시 자식 삭제들 "뒤에" 일어나야 한다.
        InOrder order = inOrder(submissionRepository, studentProfileRepository, userRepository);
        order.verify(submissionRepository).deleteByUser(student);
        order.verify(studentProfileRepository).deleteByUser(student);
        order.verify(userRepository).delete(student); // 마지막
    }

    @Test
    @DisplayName("학생 파기: 대상이 멘토면 403을 던지고 아무것도 지우지 않는다")
    void purge_rejects_non_student() {
        User mentor = new User("mentor1", "해시", "멘토", "MENTOR", "NONE");
        when(userRepository.findById(9L)).thenReturn(Optional.of(mentor));

        ResponseStatusException ex = assertThrows(ResponseStatusException.class,
                () -> service.purge(9L));

        assertEquals(403, ex.getStatusCode().value());
        verify(userRepository, never()).delete(any());
        verify(submissionRepository, never()).deleteByUser(any());
    }

    @Test
    @DisplayName("학생 파기: 없는 사용자면 404")
    void purge_throws_404_when_missing() {
        when(userRepository.findById(99L)).thenReturn(Optional.empty());

        ResponseStatusException ex = assertThrows(ResponseStatusException.class,
                () -> service.purge(99L));

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