"""eid 학습 약점 판정/포맷 — 순수 함수 (DB·LLM 무관, 단위테스트 대상). W3-2.

worker(workers/study_weakness.py)가 decide_tier/topic_trend/overall_trend 로 판정,
surface(api/study_topics.py study_diagnosis)가 format_*_block 으로 스냅샷 JSONB → 프롬프트 블록.
임계는 worker 가 주입(여기선 받기만) — 튜닝값은 한 곳(worker)에서 관리.
"""

from __future__ import annotations

# 표면 약점 토픽 상한 (포맷)
TOP_WEAKNESS = 5


def decide_tier(
    *, chronic: int, relapsed: int, overdue: int, unsure: int, attempted: int,
    min_attempts: int, chronic_focus: int, relapse_focus: int, review_overdue: int,
) -> str | None:
    """bounded 권고 tier(watch/review/focus). None = 약점 아님(스냅샷 미포함).

    conservative: 표본 미달(attempted < min_attempts)이면 focus/review 단정 안 하고 watch 상한.
    """
    shallow = attempted < min_attempts
    if not shallow and (chronic >= chronic_focus or relapsed >= relapse_focus):
        return "focus"
    if not shallow and (chronic >= 1 or relapsed >= 1 or overdue >= review_overdue):
        return "review"
    if chronic >= 1 or relapsed >= 1 or unsure >= 2 or overdue >= 1:
        return "watch"
    return None


def topic_trend(sessions: list[dict]) -> str:
    """recent 세션 finalize 카운트 → 개선|정체|악화. conservative: 명확하지 않으면 정체."""
    if not sessions:
        return "정체"
    gained = sum(s.get("newly_correct", 0) for s in sessions)
    lost = sum(s.get("relapsed", 0) + s.get("chronic_remaining", 0) for s in sessions)
    if gained > lost * 1.5:
        return "개선"
    if lost > gained * 1.5:
        return "악화"
    return "정체"


def overall_trend(topic_trends: list[str]) -> str:
    """토픽별 추세 다수결 → 전체 추세. conservative: 동률/공백이면 정체."""
    if not topic_trends:
        return "정체"
    worse = topic_trends.count("악화")
    better = topic_trends.count("개선")
    if worse > better:
        return "악화"
    if better > worse:
        return "개선"
    return "정체"


def format_weakness_block(weaknesses: list[dict], *, shallow_overall: bool) -> str:
    """약점 스냅샷 list → study overlay {weakness_snapshot_block} 텍스트. 워커 값만(추측 없음)."""
    if not weaknesses:
        return "(약점으로 판정된 토픽 없음. 스냅샷에 없는 토픽을 약점으로 추정하지 마라.)"
    lines = []
    for w in weaknesses[:TOP_WEAKNESS]:
        lines.append(
            f"- {w['topic']}: chronic 반복오답 {w['chronic']}건 / relapsed(회복후재오답) {w['relapsed']}건 / "
            f"모르겠음 {w['unsure']}건 / 미답(커버리지공백) {w['coverage_gap']}건 / 묵힌 due {w['overdue']}건 / "
            f"추세 {w['trend']} / 권고 tier={w['tier']}"
        )
    if shallow_overall:
        lines.append("- (전체 표본 적음 — 약점 단정 대신 '지켜볼 토픽'으로만 해석)")
    return "\n".join(lines)


def format_habit_block(habits: dict) -> str:
    """태도 신호 dict → study overlay {habit_signal_block} 텍스트."""
    parts = []
    if habits.get("avoidance_topics"):
        parts.append(f"- 재시도 회피 신호(모르겠음 누적) 토픽: {', '.join(habits['avoidance_topics'])}")
    parts.append(f"- 세션 중단율: {round(habits.get('session_abandon_rate', 0.0) * 100)}%")
    parts.append(f"- 오래 묵힌 due(복습 밀림): {habits.get('stale_due_count', 0)}건")
    if habits.get("skew_topic"):
        parts.append(f"- 편중: '{habits['skew_topic']}' 에 풀이 집중")
    return "\n".join(parts)
