package dev.awesomedev.mirim.web;

import dev.awesomedev.mirim.domain.CodingSubmission;
import dev.awesomedev.mirim.domain.Submission;
import dev.awesomedev.mirim.repository.UserRepository;
import dev.awesomedev.mirim.service.AuthService;
import dev.awesomedev.mirim.service.CodingService;
import dev.awesomedev.mirim.service.CourseProgressService;
import dev.awesomedev.mirim.service.ProgressService;
import dev.awesomedev.mirim.service.QuizService;
import dev.awesomedev.mirim.service.StudentProfileService;
import dev.awesomedev.mirim.service.SubmissionService;
import dev.awesomedev.mirim.web.dto.ChecklistProgressOverviewResponse;
import dev.awesomedev.mirim.web.dto.FeedbackRequest;
import dev.awesomedev.mirim.web.dto.MentorResetPasswordRequest;
import dev.awesomedev.mirim.web.dto.MentorSubmissionResponse;
import dev.awesomedev.mirim.web.dto.StudentCourseProgressResponse;
import dev.awesomedev.mirim.web.dto.StudentProfileResponse;
import jakarta.validation.Valid;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 이 파일이 하는 일:
 * 멘토 전용 API(전체 제출물 조회, 피드백 등록)를 제공하는 컨트롤러다.
 *
 * 학습 포인트: 이 컨트롤러엔 권한 검사 코드가 없다.
 * SecurityConfig에서 "/api/mentor/** 는 MENTOR 권한 필요"로 선언했기 때문에,
 * 권한이 없는 요청은 컨트롤러에 도달하기 전에 403으로 차단된다.
 * 이렇게 URL 패턴으로 권한을 선언하면, 멘토 API가 늘어나도 검사 코드를
 * 메서드마다 복사할 필요가 없고 "권한 규칙이 어디 있는지"가 한곳에 모인다.
 */
@RestController
@RequestMapping("/api/mentor")
public class MentorController {

    private final SubmissionService submissionService;
    private final CourseProgressService courseProgressService;
    private final ProgressService progressService;
    private final QuizService quizService;
    private final CodingService codingService;
    private final AuthService authService;
    private final StudentProfileService studentProfileService;
    private final UserRepository userRepository;

    public MentorController(SubmissionService submissionService,
                            CourseProgressService courseProgressService,
                            ProgressService progressService,
                            QuizService quizService,
                            CodingService codingService,
                            AuthService authService,
                            StudentProfileService studentProfileService,
                            UserRepository userRepository) {
        this.submissionService = submissionService;
        this.courseProgressService = courseProgressService;
        this.progressService = progressService;
        this.quizService = quizService;
        this.codingService = codingService;
        this.authService = authService;
        this.studentProfileService = studentProfileService;
        this.userRepository = userRepository;
    }

    /** GET /api/mentor/submissions — 전체 제출물 + 학생 이름 + 과제 제목 (최신순) */
    @GetMapping("/submissions")
    public List<MentorSubmissionResponse> allSubmissions() {
        return submissionService.allSubmissions().stream()
                .map(MentorSubmissionResponse::from)
                .toList();
    }

    /**
     * GET /api/mentor/course-progress — 학생별 코스 완료 현황 (이름순).
     * 학습 포인트: 학생이 4~5명이라 학생마다 조회(N+1)해도 충분히 빠르다.
     * 사용자가 수백 명이 되면 한 번에 JOIN으로 가져오도록 개선해야 한다 —
     * "지금 규모에 맞는 단순함"과 "미래의 개선 지점"을 함께 아는 것이 중요하다.
     */
    @GetMapping("/course-progress")
    public List<StudentCourseProgressResponse> studentCourseProgress() {
        return userRepository.findByRoleOrderByNameAsc("STUDENT").stream()
                .map(student -> new StudentCourseProgressResponse(
                        student.getId(),
                        student.getUsername(),
                        student.getName(),
                        student.getTrack(),
                        courseProgressService.completedSlugs(student)))
                .toList();
    }

    /**
     * GET /api/mentor/checklist-progress — 주차별 체크리스트 진도 현황.
     * 주차별 항목 총수(분모)와 학생별 주차 완료 수(분자)를 함께 반환한다.
     */
    @GetMapping("/checklist-progress")
    public ChecklistProgressOverviewResponse checklistProgress() {
        List<ChecklistProgressOverviewResponse.StudentWeekly> students =
                userRepository.findByRoleOrderByNameAsc("STUDENT").stream()
                        .map(student -> new ChecklistProgressOverviewResponse.StudentWeekly(
                                student.getId(),
                                student.getUsername(),
                                student.getName(),
                                student.getTrack(),
                                progressService.doneCountByWeek(student)))
                        .toList();
        return new ChecklistProgressOverviewResponse(progressService.totalCountByWeek(), students);
    }

    /** 학생 한 명의 퀴즈 성적 묶음 */
    public record StudentQuizResults(Long userId, String name, String track,
                                     List<QuizService.ResultSummary> results) {
    }

    /** GET /api/mentor/quiz-results — 학생별 코스 퀴즈 성적(최고점·응시 횟수) */
    @GetMapping("/quiz-results")
    public List<StudentQuizResults> quizResults() {
        return userRepository.findByRoleOrderByNameAsc("STUDENT").stream()
                .map(student -> new StudentQuizResults(
                        student.getId(),
                        student.getName(),
                        student.getTrack(),
                        quizService.summaryFor(student)))
                .toList();
    }

    /** GET /api/mentor/students — 수습생 인적사항 명단 (화면 표시용) */
    @GetMapping("/students")
    public List<StudentProfileResponse> students() {
        return studentProfileService.allProfiles().stream()
                .map(StudentProfileResponse::from)
                .toList();
    }

    /**
     * GET /api/mentor/students/export.csv — 수습생 명단 CSV 다운로드 (경리 담당자용).
     *
     * 학습 포인트: JSON API와 달리 "파일 다운로드"는 응답 헤더가 중요하다.
     *  - Content-Type: text/csv → 브라우저가 화면에 그리지 않고 파일로 인식
     *  - Content-Disposition: attachment; filename=... → "다운로드하라, 이 이름으로"
     * 이 두 헤더가 없으면 브라우저는 CSV를 그냥 화면에 텍스트로 펼쳐 버린다.
     */
    @GetMapping("/students/export.csv")
    public ResponseEntity<Resource> exportCsv() {
        byte[] bytes = studentProfileService.exportCsv().getBytes(StandardCharsets.UTF_8);
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION,
                        "attachment; filename=\"mirim-students.csv\"")
                .contentType(MediaType.parseMediaType("text/csv; charset=UTF-8"))
                .body(new ByteArrayResource(bytes));
    }

    /**
     * POST /api/mentor/users/{id}/reset-password — 멘토가 학생의 비밀번호를 재설정한다.
     *
     * 학습 포인트: 원래 이 기능은 "아이디+이름만 맞으면 누구나" 호출할 수 있는 무인증 API였다.
     * 보안 검토에서 계정 탈취 경로로 확인되어 이 자리로 옮겼다 —
     * /api/mentor/** 는 SecurityConfig가 MENTOR 권한을 요구하므로, 이제 멘토만 호출할 수 있다.
     * 본인 확인은 "옆자리 멘토가 얼굴을 보고 확인"이라는 오프라인 절차가 대신한다.
     */
    @PostMapping("/users/{id}/reset-password")
    public void resetStudentPassword(@PathVariable Long id,
                                     @Valid @RequestBody MentorResetPasswordRequest request) {
        authService.resetPasswordByMentor(id, request.newPassword());
    }

    /** POST /api/mentor/submissions/{id}/feedback — 피드백 등록, 상태는 REVIEWED로 변경 */
    @PostMapping("/submissions/{id}/feedback")
    public MentorSubmissionResponse giveFeedback(@PathVariable Long id,
                                                 @RequestBody FeedbackRequest feedbackRequest) {
        Submission submission = submissionService.giveFeedback(id, feedbackRequest.feedback());
        return MentorSubmissionResponse.from(submission);
    }

    // --- 코딩 문제 ---

    /**
     * 코딩 제출물 한 건 (멘토 화면용).
     * 학생이 짠 코드 원문(code)과 테스트별 채점 결과(resultsJson)를 그대로 담는다 —
     * 멘토가 "무엇을 어떻게 짰고, 어디서 틀렸는지"를 한 화면에서 보게 하기 위해서다.
     */
    public record MentorCodingSubmissionResponse(Long id, Long problemId, String problemTitle,
                                                 String language, String difficulty,
                                                 Long userId, String studentName, String track,
                                                 String code, String status,
                                                 Integer passedCount, Integer totalCount,
                                                 String resultsJson, Integer attempts,
                                                 String submittedAt, String feedback) {
        static MentorCodingSubmissionResponse from(CodingSubmission s) {
            return new MentorCodingSubmissionResponse(
                    s.getId(), s.getProblem().getId(), s.getProblem().getTitle(),
                    s.getProblem().getLanguage(), s.getProblem().getDifficulty(),
                    s.getUser().getId(), s.getUser().getName(), s.getUser().getTrack(),
                    s.getCode(), s.getStatus(), s.getPassedCount(), s.getTotalCount(),
                    s.getResultsJson(), s.getAttempts(),
                    s.getSubmittedAt().toString(), s.getFeedback());
        }
    }

    /** GET /api/mentor/coding-submissions — 전체 코딩 제출물 (최신순) */
    @GetMapping("/coding-submissions")
    public List<MentorCodingSubmissionResponse> codingSubmissions() {
        return codingService.allSubmissions().stream()
                .map(MentorCodingSubmissionResponse::from)
                .toList();
    }

    /** 학생 한 명의 코딩 진도 */
    public record StudentCodingProgress(Long userId, String name, String track,
                                        CodingService.ProgressSummary progress) {
    }

    /** GET /api/mentor/coding-progress — 학생별 코딩 진도(전체/제출/통과) */
    @GetMapping("/coding-progress")
    public List<StudentCodingProgress> codingProgress() {
        return userRepository.findByRoleOrderByNameAsc("STUDENT").stream()
                .map(student -> new StudentCodingProgress(
                        student.getId(), student.getName(), student.getTrack(),
                        codingService.progressOf(student)))
                .toList();
    }

    /** POST /api/mentor/coding-submissions/{id}/feedback — 코드에 피드백 등록 */
    @PostMapping("/coding-submissions/{id}/feedback")
    public MentorCodingSubmissionResponse giveCodingFeedback(@PathVariable Long id,
                                                             @RequestBody FeedbackRequest feedbackRequest) {
        return MentorCodingSubmissionResponse.from(
                codingService.giveFeedback(id, feedbackRequest.feedback()));
    }
}
