"""Phase 4-B v1 세션 분석 enqueue 헬퍼 — finalize/fallback/manual 공유.

3 가지 진입점이 다른 정책으로 동작:
  - auto (finalize/fallback): wrong/unsure < 5 도 enqueue 허용 (worker 가 skipped 처리).
    GET fallback 은 best-effort + idempotent + non-blocking.
  - manual (regenerate endpoint): wrong/unsure < 5 또는 active job 존재 시 즉시 차단.
    사용자 즉시 안내 (UX).

is_stale 정책:
  - active job 있음: is_stale 변경 X
  - active 없음 + 기존 analysis 있음: is_stale=TRUE 박기 + 새 job
  - active 없음 + 기존 analysis 없음: is_stale 처리 X + 새 job
"""

from __future__ import annotations

import logging
from typing import Literal

from sqlalchemy import func, select, update
from sqlalchemy.ext.asyncio import AsyncSession

from models.study_question import StudyQuestionAttempt
from models.study_quiz_session import StudyQuizSession
from models.study_quiz_session_analysis import StudyQuizSessionAnalysis
from models.study_quiz_session_job import StudyQuizSessionJob, enqueue_session_analysis_job

logger = logging.getLogger(__name__)

MIN_ATTEMPTS_FOR_ANALYSIS = 5


async def _count_wrong_unsure(session: AsyncSession, study_quiz_session_id: int) -> int:
    row = await session.execute(
        select(func.count())
        .select_from(StudyQuestionAttempt)
        .where(
            StudyQuestionAttempt.quiz_session_id == study_quiz_session_id,
            StudyQuestionAttempt.outcome.in_(("wrong", "unsure")),
        )
    )
    return int(row.scalar() or 0)


async def _has_active_job(session: AsyncSession, study_quiz_session_id: int) -> bool:
    row = await session.execute(
        select(func.count())
        .select_from(StudyQuizSessionJob)
        .where(
            StudyQuizSessionJob.study_quiz_session_id == study_quiz_session_id,
            StudyQuizSessionJob.status.in_(("pending", "processing")),
        )
    )
    return int(row.scalar() or 0) > 0


async def _has_existing_analysis(session: AsyncSession, study_quiz_session_id: int) -> bool:
    row = await session.execute(
        select(StudyQuizSessionAnalysis.study_quiz_session_id).where(
            StudyQuizSessionAnalysis.study_quiz_session_id == study_quiz_session_id
        )
    )
    return row.scalar_one_or_none() is not None


async def enqueue_session_analysis_auto(
    session: AsyncSession,
    *,
    user_id: int,
    study_quiz_session_id: int,
) -> dict:
    """finalize_session 끝 + GET fallback 공통 자동 트리거.

    wrong/unsure 카운트 무관 enqueue (worker 가 < 5 면 insufficient_attempts skipped).
    active 행은 partial unique idx 가 차단. is_stale 은 안 건드림 (자동 트리거라 UX 무관).
    """
    enqueued = await enqueue_session_analysis_job(
        session,
        study_quiz_session_id=study_quiz_session_id,
        user_id=user_id,
    )
    return {"enqueued": enqueued}


async def request_session_analysis_regenerate(
    session: AsyncSession,
    *,
    user_id: int,
    study_quiz_session_id: int,
) -> dict:
    """사용자 [재생성] 버튼 — manual endpoint 가 호출.

    Returns:
      {'enqueued': bool, 'reason': Literal['insufficient_attempts','already_active'] | None}
    """
    qs = await session.get(StudyQuizSession, study_quiz_session_id)
    if qs is None or qs.user_id != user_id:
        return {"enqueued": False, "reason": "not_found"}
    if qs.status != "done":
        return {"enqueued": False, "reason": "not_done"}

    # 1. wrong/unsure < 5 즉시 차단
    cnt = await _count_wrong_unsure(session, study_quiz_session_id)
    if cnt < MIN_ATTEMPTS_FOR_ANALYSIS:
        return {"enqueued": False, "reason": "insufficient_attempts"}

    # 2. active job 있으면 즉시 차단 (is_stale 변경 X)
    if await _has_active_job(session, study_quiz_session_id):
        return {"enqueued": False, "reason": "already_active"}

    # 3. 기존 analysis 있으면 is_stale=TRUE
    if await _has_existing_analysis(session, study_quiz_session_id):
        await session.execute(
            update(StudyQuizSessionAnalysis)
            .where(StudyQuizSessionAnalysis.study_quiz_session_id == study_quiz_session_id)
            .values(is_stale=True)
        )

    # 4. 새 job
    enqueued = await enqueue_session_analysis_job(
        session,
        study_quiz_session_id=study_quiz_session_id,
        user_id=user_id,
        payload={"trigger": "manual"},
    )
    return {"enqueued": enqueued, "reason": None if enqueued else "race_lost"}
