package dev.awesomedev.mirim.service;

import dev.awesomedev.mirim.domain.Assignment;
import dev.awesomedev.mirim.domain.Submission;
import dev.awesomedev.mirim.domain.User;
import dev.awesomedev.mirim.repository.AssignmentRepository;
import dev.awesomedev.mirim.repository.SubmissionRepository;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.ResponseStatusException;

import java.util.List;
import java.util.Optional;

/**
 * 이 파일이 하는 일:
 * 과제 제출물(Submission)을 다루는 서비스다.
 * 제출/재제출, 내 제출물 조회, 멘토 피드백 등록을 담당한다.
 */
@Service
public class SubmissionService {

    private final SubmissionRepository submissionRepository;
    private final AssignmentRepository assignmentRepository;
    private final TelegramNotifier telegramNotifier;

    public SubmissionService(SubmissionRepository submissionRepository,
                             AssignmentRepository assignmentRepository,
                             TelegramNotifier telegramNotifier) {
        this.submissionRepository = submissionRepository;
        this.assignmentRepository = assignmentRepository;
        this.telegramNotifier = telegramNotifier;
    }

    /**
     * 과제를 제출한다. 같은 과제를 이미 제출했다면 새 행을 만들지 않고 기존 제출물을 갱신한다.
     *
     * 학습 포인트: "제출물은 과제당 1개" 규칙을 INSERT 전에 SELECT로 확인해서 지킨다.
     * 재제출하면 상태가 다시 SUBMITTED로 돌아가 멘토가 다시 리뷰해야 함을 알 수 있다.
     */
    @Transactional
    public Submission submitOrUpdate(User user, Long assignmentId, String content, String link) {
        if (content == null || content.isBlank()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "제출 내용(content)은 비울 수 없습니다.");
        }
        Assignment assignment = assignmentRepository.findById(assignmentId)
                .orElseThrow(() -> new ResponseStatusException(
                        HttpStatus.NOT_FOUND, "과제를 찾을 수 없습니다: " + assignmentId));

        Optional<Submission> existing = submissionRepository.findByAssignmentAndUser(assignment, user);
        Submission submission;
        boolean isResubmit = existing.isPresent();
        if (isResubmit) {
            submission = existing.get();
            submission.resubmit(content, link);
            // 학습 포인트: 트랜잭션 안에서 엔티티를 바꾸면 JPA가 커밋 시 자동으로 UPDATE 한다(더티 체킹).
        } else {
            submission = submissionRepository.save(new Submission(assignment, user, content, link));
        }

        // 멘토에게 텔레그램 알림 (실패해도 제출은 성공)
        telegramNotifier.send("📝 과제 " + (isResubmit ? "재제출" : "제출") + "\n"
                + user.getName() + " — " + assignment.getTitle());

        return submission;
    }

    /** 내 제출물을 최신순으로 조회한다. */
    @Transactional(readOnly = true)
    public List<Submission> mySubmissions(User user) {
        return submissionRepository.findByUserOrderBySubmittedAtDesc(user);
    }

    /** 전체 제출물을 최신순으로 조회한다 (멘토용). */
    @Transactional(readOnly = true)
    public List<Submission> allSubmissions() {
        return submissionRepository.findAllByOrderBySubmittedAtDesc();
    }

    /** 멘토가 제출물에 피드백을 남긴다. 상태는 REVIEWED로 바뀐다. */
    @Transactional
    public Submission giveFeedback(Long submissionId, String feedback) {
        if (feedback == null || feedback.isBlank()) {
            throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "피드백 내용은 비울 수 없습니다.");
        }
        Submission submission = submissionRepository.findById(submissionId)
                .orElseThrow(() -> new ResponseStatusException(
                        HttpStatus.NOT_FOUND, "제출물을 찾을 수 없습니다: " + submissionId));
        submission.review(feedback);
        return submission;
    }
}
