"""concept_links — 이론↔문제 브리지 롤업 (Stage B).

study_concept_links(개념 doc ↔ 기출문항, 임베딩 코사인) + study_question_progress(내 풀이상태)를
조인해 (a) 개념별 관련 기출 + 내 정답률(related_questions), (b) 개념 약점 지도(weakness_map) 산출.
읽기 전용 집계 · LLM 0. 링크 적재는 scripts/concept_links_backfill.sql(임베딩) 배치.
정답률 = 링크된 문항 중 progress.last_outcome 기준(attempted=풀이이력 보유, correct=최근정답).
"""

from __future__ import annotations

from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession

_ACCURACY_WEAK_PCT = 60  # 정답률 < 60% = 약점(attempted>0 일 때만)

_AGG_SQL = text(
    """
    SELECT count(*) AS linked,
           count(pr.study_question_id) FILTER (WHERE pr.last_outcome IS NOT NULL) AS attempted,
           count(*) FILTER (WHERE pr.last_outcome = 'correct') AS correct
    FROM study_concept_links l
    LEFT JOIN study_question_progress pr
      ON pr.study_question_id = l.question_id AND pr.user_id = :uid
    WHERE l.concept_doc_id = :doc_id AND l.link_source = 'embedding'
    """
)

_QROWS_SQL = text(
    """
    SELECT q.id AS id, q.subject AS subject, q.exam_round AS exam_round,
           q.exam_question_number AS qnum, l.score AS score,
           pr.last_outcome AS last_outcome, pr.review_stage AS review_stage
    FROM study_concept_links l
    JOIN study_questions q ON q.id = l.question_id AND q.deleted_at IS NULL AND q.is_active
    LEFT JOIN study_question_progress pr
      ON pr.study_question_id = q.id AND pr.user_id = :uid
    WHERE l.concept_doc_id = :doc_id AND l.link_source = 'embedding'
    ORDER BY l.score DESC
    LIMIT :limit
    """
)

_WEAKNESS_SQL = text(
    """
    SELECT d.id AS doc_id, d.title AS title,
           split_part(replace(d.user_tags::text, '"', ''), '/', 3) AS subject,
           count(l.id) AS linked,
           count(pr.study_question_id) FILTER (WHERE pr.last_outcome IS NOT NULL) AS attempted,
           count(*) FILTER (WHERE pr.last_outcome = 'correct') AS correct
    FROM documents d
    JOIN study_concept_links l ON l.concept_doc_id = d.id AND l.link_source = 'embedding'
    LEFT JOIN study_question_progress pr
      ON pr.study_question_id = l.question_id AND pr.user_id = :uid
    WHERE d.user_tags::text LIKE :like AND d.deleted_at IS NULL
    GROUP BY d.id, d.title, subject
    """
)


async def related_questions(
    session: AsyncSession, user_id: int, doc_id: int, limit: int = 20
) -> dict:
    """개념 doc 의 관련 기출 + 내 정답률(전체 링크 기준 집계 + 상위 N 표시용)."""
    agg = (
        await session.execute(_AGG_SQL, {"uid": user_id, "doc_id": doc_id})
    ).mappings().first()
    rows = (
        await session.execute(
            _QROWS_SQL, {"uid": user_id, "doc_id": doc_id, "limit": limit}
        )
    ).mappings().all()

    linked = (agg["linked"] if agg else 0) or 0
    attempted = (agg["attempted"] if agg else 0) or 0
    correct = (agg["correct"] if agg else 0) or 0
    accuracy = round(100 * correct / attempted) if attempted else None

    return {
        "linked": linked,
        "attempted": attempted,
        "correct": correct,
        "accuracy": accuracy,
        "questions": [
            {
                "id": r["id"],
                "subject": r["subject"],
                "exam_round": r["exam_round"],
                "qnum": r["qnum"],
                "score": round(r["score"], 3) if r["score"] is not None else None,
                "last_outcome": r["last_outcome"],
                "review_stage": r["review_stage"],
            }
            for r in rows
        ],
    }


async def weakness_map(
    session: AsyncSession, user_id: int, topic_name: str, limit: int = 12
) -> dict:
    """개념 약점 지도 — 링크된 기출 정답률로 개념 채색. 약점(attempted>0·정답률<60%) 우선 정렬."""
    like = f"%@library/{topic_name}/%"
    rows = (
        await session.execute(_WEAKNESS_SQL, {"uid": user_id, "like": like})
    ).mappings().all()

    concepts = []
    for r in rows:
        attempted = r["attempted"] or 0
        correct = r["correct"] or 0
        accuracy = round(100 * correct / attempted) if attempted else None
        if accuracy is None:
            state = "unattempted"
        elif accuracy < _ACCURACY_WEAK_PCT:
            state = "weak"
        else:
            state = "ok"
        concepts.append(
            {
                "doc_id": r["doc_id"],
                "title": r["title"],
                "subject": r["subject"],
                "linked": r["linked"] or 0,
                "attempted": attempted,
                "accuracy": accuracy,
                "state": state,
            }
        )

    # 약점 우선(정답률 오름차순) → 미평가는 뒤로. 홈 위젯용 상위 N.
    weak = sorted(
        [c for c in concepts if c["state"] == "weak"],
        key=lambda c: (c["accuracy"], -c["attempted"], c["doc_id"]),
    )
    return {
        "weak": weak[:limit],
        "weak_total": len(weak),
        "evaluated_total": sum(1 for c in concepts if c["state"] != "unattempted"),
    }
