"""study_memo_card_progress ORM — 카드 SR(간격반복) 상태 (문제 progress '분리 미러').

migration 294. 226 골격 축소: SR 4컬럼(last_outcome/last_reviewed_at/due_at/review_stage)만,
pattern 분류 컬럼은 미보유(카드 복습함은 due/미확인/완료 3탭). UNIQUE(user_id, card_id).
간격 산술은 sr_schedule.py 단일 source.

입고 정책(결정 2026-06-07): '평가 즉시 자동 입고' — 애매/모름 카드는 평가 즉시 due 부여
(문제 SR의 [학습완료] 수동 게이트와 달리 자동). 암(correct) 카드는 due 안 박음(큐 폭발 방지).
"""

from __future__ import annotations

from datetime import datetime

from sqlalchemy import BigInteger, DateTime, ForeignKey, SmallInteger, String, UniqueConstraint, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, mapped_column

from core.database import Base
from models.study_memo_card import StudyMemoCard
from services.study import sr_schedule


class StudyMemoCardProgress(Base):
    __tablename__ = "study_memo_card_progress"
    __table_args__ = (UniqueConstraint("user_id", "card_id", name="uq_card_progress_user_card"),)

    id: Mapped[int] = mapped_column(BigInteger, primary_key=True)
    user_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("users.id", ondelete="CASCADE"), nullable=False
    )
    study_topic_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("study_topics.id", ondelete="CASCADE"), nullable=False
    )
    card_id: Mapped[int] = mapped_column(
        BigInteger, ForeignKey("study_memo_cards.id", ondelete="CASCADE"), nullable=False
    )

    last_outcome: Mapped[str | None] = mapped_column(String(20))
    last_reviewed_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
    due_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
    review_stage: Mapped[int | None] = mapped_column(SmallInteger)

    created_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), default=datetime.now, nullable=False
    )
    updated_at: Mapped[datetime] = mapped_column(
        DateTime(timezone=True), default=datetime.now, onupdate=datetime.now, nullable=False
    )


async def rate_card(
    session: AsyncSession, *, card: StudyMemoCard, outcome: str, now: datetime
) -> StudyMemoCardProgress:
    """카드 자기평가 1건 처리 (SR 즉시 자동 입고). outcome ∈ correct/wrong/unsure.

    - progress 없으면 생성. last_outcome/last_reviewed_at 갱신.
    - 이미 due(복습 큐)면 sr_schedule.advance(전진/리셋/졸업).
    - due 없으면 애매/모름만 first_due 부여(즉시 입고), 암은 due 안 박음.
    caller 가 commit.
    """
    progress = (
        await session.execute(
            select(StudyMemoCardProgress).where(
                StudyMemoCardProgress.user_id == card.user_id,
                StudyMemoCardProgress.card_id == card.id,
            )
        )
    ).scalar_one_or_none()
    if progress is None:
        progress = StudyMemoCardProgress(
            user_id=card.user_id, study_topic_id=card.study_topic_id, card_id=card.id
        )
        session.add(progress)

    progress.last_outcome = outcome
    progress.last_reviewed_at = now

    if progress.due_at is not None:
        result = sr_schedule.advance(progress.review_stage, outcome, now)
        if result is not None:  # skipped 는 None → 불변
            progress.review_stage, progress.due_at = result
    elif outcome in ("wrong", "unsure"):
        # 즉시 자동 입고: 애매·모름은 평가 즉시 복습 큐로 (stage0 + 내일)
        progress.review_stage, progress.due_at = sr_schedule.first_due(now)
    # outcome == 'correct' 이고 due 없음 → due 안 박음(큐 폭발 방지)

    return progress
