package dev.awesomedev.mirim.web;

import dev.awesomedev.mirim.domain.CodingProblem;
import dev.awesomedev.mirim.domain.CodingSubmission;
import dev.awesomedev.mirim.domain.User;
import dev.awesomedev.mirim.service.AuthService;
import dev.awesomedev.mirim.service.CodingService;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

/**
 * 이 파일이 하는 일:
 * 학생용 코딩 문제 API — 문제 목록, 문제 상세(+내 제출물), 코드 제출, 내 진도.
 */
@RestController
@RequestMapping("/api/coding")
public class CodingController {

    private final CodingService codingService;
    private final AuthService authService;

    public CodingController(CodingService codingService, AuthService authService) {
        this.codingService = codingService;
        this.authService = authService;
    }

    /**
     * 목록용 요약 — 문제 설명·테스트케이스는 빼고 필요한 것만 담는다.
     * 학습 포인트: 목록 20건마다 긴 description을 실어 보내면 응답이 쓸데없이 커진다.
     * "화면이 필요로 하는 만큼만 준다"가 DTO를 따로 두는 이유다.
     */
    public record ProblemSummary(Long id, String language, String title, String difficulty,
                                 String topic, String status, Integer passedCount, Integer totalCount) {
    }

    /** GET /api/coding/problems — 문제 목록 + 내 풀이 상태 */
    @GetMapping("/problems")
    public List<ProblemSummary> problems(Authentication authentication) {
        User user = authService.requireUser(authentication);
        Map<Long, CodingSubmission> mine = codingService.mySubmissionsByProblemId(user);
        return codingService.allProblems().stream()
                .map(problem -> {
                    CodingSubmission submission = mine.get(problem.getId());
                    return new ProblemSummary(
                            problem.getId(), problem.getLanguage(), problem.getTitle(),
                            problem.getDifficulty(), problem.getTopic(),
                            submission == null ? "TODO" : submission.getStatus(),
                            submission == null ? null : submission.getPassedCount(),
                            submission == null ? null : submission.getTotalCount());
                })
                .toList();
    }

    /** 문제 상세 — 채점 데이터(testsJson)와 SQL 준비 스크립트(setupSql)는 브라우저가 쓰므로 함께 내려준다 */
    public record ProblemDetail(Long id, String language, String title, String difficulty,
                                String topic, String description, String starterCode,
                                String functionName, String setupSql, String testsJson,
                                String myCode, String status, Integer passedCount,
                                Integer totalCount, String resultsJson, Integer attempts,
                                String feedback) {
    }

    /** GET /api/coding/problems/{id} — 문제 상세 + 내가 마지막에 낸 코드/결과 */
    @GetMapping("/problems/{id}")
    public ProblemDetail problem(@PathVariable Long id, Authentication authentication) {
        User user = authService.requireUser(authentication);
        CodingProblem problem = codingService.problem(id);
        return codingService.mySubmission(user, id)
                .map(s -> new ProblemDetail(problem.getId(), problem.getLanguage(), problem.getTitle(),
                        problem.getDifficulty(), problem.getTopic(), problem.getDescription(),
                        problem.getStarterCode(), problem.getFunctionName(),
                        problem.getSetupSql(), problem.getTestsJson(),
                        s.getCode(), s.getStatus(), s.getPassedCount(), s.getTotalCount(),
                        s.getResultsJson(), s.getAttempts(), s.getFeedback()))
                .orElseGet(() -> new ProblemDetail(problem.getId(), problem.getLanguage(), problem.getTitle(),
                        problem.getDifficulty(), problem.getTopic(), problem.getDescription(),
                        problem.getStarterCode(), problem.getFunctionName(),
                        problem.getSetupSql(), problem.getTestsJson(),
                        null, "TODO", null, null, null, 0, null));
    }

    /** 제출 요청 — 코드와, 브라우저가 매긴 채점 결과(JS 문제일 때) */
    public record SubmitRequest(String code, Integer passedCount, Integer totalCount, String resultsJson) {
    }

    /** 제출 응답 */
    public record SubmitResponse(Long id, String status, Integer passedCount, Integer totalCount,
                                 Integer attempts) {
    }

    /** POST /api/coding/problems/{id}/submit — 코드 제출(재제출이면 기존 행 갱신) */
    @PostMapping("/problems/{id}/submit")
    public SubmitResponse submit(@PathVariable Long id,
                                 @RequestBody SubmitRequest request,
                                 Authentication authentication) {
        User user = authService.requireUser(authentication);
        CodingSubmission submission = codingService.submit(user, id, request.code(),
                request.passedCount(), request.totalCount(), request.resultsJson());
        return new SubmitResponse(submission.getId(), submission.getStatus(),
                submission.getPassedCount(), submission.getTotalCount(), submission.getAttempts());
    }

    /** GET /api/coding/progress/me — 내 진도(전체/제출/통과) */
    @GetMapping("/progress/me")
    public CodingService.ProgressSummary myProgress(Authentication authentication) {
        User user = authService.requireUser(authentication);
        return codingService.progressOf(user);
    }
}
