package dev.awesomedev.mirim.domain;

import jakarta.persistence.*;

/**
 * 이 파일이 하는 일:
 * 코딩 문제 하나를 담는 JPA 엔티티다.
 * 퀴즈(4지선다)가 "아는지"를 묻는다면, 코딩 문제는 "짤 수 있는지"를 묻는다.
 *
 * 언어(language)에 따라 채점 방식이 다르다:
 *  - JS   : 브라우저(Web Worker)가 테스트케이스를 돌려 즉시 통과/실패를 가린다.
 *  - SQL  : 브라우저 안의 SQLite(sql.js, WASM)가 쿼리를 실행해 기대 결과와 비교한다.
 *           서버 DB에는 손끝 하나 닿지 않는다 — 학생마다 자기 브라우저에 1회용 DB가 생긴다.
 *  - JAVA : 실행하지 않는다. 코드를 제출하면 멘토가 직접 읽고 피드백한다.
 *
 * 학습 포인트: 왜 자바는 서버에서 실행하지 않을까?
 * 남이 보낸 코드를 서버에서 그대로 돌리는 건 "내 집 열쇠를 모르는 사람에게 주는 것"과 같다.
 * 무한루프로 CPU를 잡아먹거나(System.exit로 서버를 끄거나) 파일을 뒤질 수 있다.
 * 안전하게 하려면 Docker 같은 격리된 방을 매 제출마다 만들어야 하는데, 비용과 복잡도가 크다.
 * 그래서 우리 규모에서는 "자바는 사람(멘토)이 읽는다"가 가장 합리적인 선택이다.
 * — 기술적으로 가능한 것과 지금 규모에 맞는 것은 다르다.
 */
@Entity
@Table(name = "coding_problem")
public class CodingProblem {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /** 문제 언어: JS | SQL | JAVA */
    @Column(nullable = false, length = 8)
    private String language;

    /** 문제 제목 */
    @Column(nullable = false)
    private String title;

    /** 난이도: EASY | NORMAL | HARD */
    @Column(nullable = false, length = 8)
    private String difficulty;

    /** 관련 학습 주제(코스 slug 느낌의 분류 — 예: javascript, java-basics) */
    @Column(name = "topic", nullable = false, length = 60)
    private String topic;

    /** 문제 설명 (마크다운 아님 — 줄바꿈만 살려서 그대로 보여준다) */
    @Column(nullable = false, columnDefinition = "text")
    private String description;

    /** 학생 화면에 처음 채워져 있는 뼈대 코드 */
    @Column(name = "starter_code", nullable = false, columnDefinition = "text")
    private String starterCode;

    /**
     * 학생이 구현해야 하는 함수 이름 (JS 전용 — 채점기가 이 이름으로 함수를 찾아 호출한다).
     * JAVA 문제는 실행하지 않으므로 null.
     */
    @Column(name = "function_name", length = 60)
    private String functionName;

    /**
     * 문제를 풀 때 브라우저 SQLite에 먼저 실행할 준비 SQL (SQL 전용, 나머지는 null).
     * CREATE TABLE + INSERT — 즉 "문제의 데이터 세트"가 이 안에 통째로 들어 있다.
     * 학습 포인트: 같은 준비 SQL을 여러 문제가 복사해서 갖는다. 정규화하면 테이블이 하나 늘고
     * 조인이 생기는데, 문제 5개 규모에선 "그냥 들고 다니는" 쪽이 단순하다.
     */
    @Column(name = "setup_sql", columnDefinition = "text")
    private String setupSql;

    /**
     * 테스트케이스 묶음을 JSON 문자열로 통째로 담는다 (JS·SQL 전용, JAVA는 null).
     * JS 형식: [{"name":"설명","args":[1,2],"expected":3}, ...]
     * SQL 형식: {"expectedColumns":[...],"expectedRows":[[...]],"orderMatters":false}
     *
     * 학습 포인트: 왜 테스트케이스용 테이블을 따로 만들지 않고 JSON 한 덩어리로 넣을까?
     * 테스트케이스는 (1) 항상 문제와 함께 통째로 읽고, (2) 따로 검색하거나 조인할 일이 없다.
     * 이럴 땐 테이블을 쪼개는 것보다 JSON으로 두는 편이 단순하다.
     * 반대로 "테스트케이스별 통과율 통계"처럼 개별 조회가 필요해지면 그때 테이블로 승격하면 된다.
     */
    @Column(name = "tests_json", columnDefinition = "text")
    private String testsJson;

    /** 목록에서의 정렬 순서 */
    @Column(name = "sort_order", nullable = false)
    private Integer sortOrder;

    protected CodingProblem() {
    }

    public CodingProblem(String language, String title, String difficulty, String topic,
                         String description, String starterCode, String functionName,
                         String setupSql, String testsJson, Integer sortOrder) {
        this.language = language;
        this.title = title;
        this.difficulty = difficulty;
        this.topic = topic;
        this.description = description;
        this.starterCode = starterCode;
        this.functionName = functionName;
        this.setupSql = setupSql;
        this.testsJson = testsJson;
        this.sortOrder = sortOrder;
    }

    /** 브라우저에서 자동채점이 가능한 문제인가 (JS와 SQL — JAVA만 멘토 수동 채점) */
    public boolean isAutoGraded() {
        return "JS".equals(language) || "SQL".equals(language);
    }

    public Long getId() {
        return id;
    }

    public String getLanguage() {
        return language;
    }

    public String getTitle() {
        return title;
    }

    public String getDifficulty() {
        return difficulty;
    }

    public String getTopic() {
        return topic;
    }

    public String getDescription() {
        return description;
    }

    public String getStarterCode() {
        return starterCode;
    }

    public String getFunctionName() {
        return functionName;
    }

    public String getSetupSql() {
        return setupSql;
    }

    public String getTestsJson() {
        return testsJson;
    }

    public Integer getSortOrder() {
        return sortOrder;
    }
}
