from sqlalchemy import func
from sqlalchemy.orm import Session

from app import models
from app.services.feishu_client import FeishuClient


def _default_reviewer_id(db: Session, reviewer_id: int | None) -> int | None:
    if reviewer_id:
        return reviewer_id
    user = db.query(models.User).filter(models.User.role == models.UserRole.reviewer).first()
    return user.id if user else None


def add_audit_log(
    db: Session,
    *,
    user_id: int | None,
    target_type: models.TargetType,
    target_id: int,
    action: models.AuditAction,
    before_status: str | None,
    after_status: str | None,
    comment: str | None = None,
) -> models.AuditLog:
    log = models.AuditLog(
        user_id=user_id,
        target_type=target_type,
        target_id=target_id,
        action=action,
        before_status=before_status,
        after_status=after_status,
        comment=comment,
    )
    db.add(log)
    return log


def refresh_session_counts(db: Session, session_id: int) -> None:
    session = db.get(models.FeishuSession, session_id)
    if not session:
        return
    session.qa_count = db.query(models.RawQAItem).filter(models.RawQAItem.session_id == session_id).count()
    session.pending_review_count = (
        db.query(models.RawQAItem)
        .filter(
            models.RawQAItem.session_id == session_id,
            models.RawQAItem.review_status.in_([models.ReviewStatus.pending, models.ReviewStatus.reviewing]),
        )
        .count()
    )
    session.approved_count = (
        db.query(models.RawQAItem)
        .filter(models.RawQAItem.session_id == session_id, models.RawQAItem.review_status == models.ReviewStatus.approved)
        .count()
    )
    session.standard_qa_count = (
        db.query(models.StandardQAItem).filter(models.StandardQAItem.session_id == session_id).count()
    )
    if session.pending_review_count == 0 and session.qa_count > 0:
        session.process_status = models.ProcessStatus.completed
    elif session.qa_count > 0:
        session.process_status = models.ProcessStatus.pending_review


def create_standard_from_raw(
    db: Session, raw: models.RawQAItem, reviewer_id: int | None
) -> models.StandardQAItem | None:
    if raw.standard_item:
        return raw.standard_item
    if not raw.suggested_to_standard_qa:
        return None
    # 高风险与禁止内容即使被标记状态，也不能自动进入标准问答库。
    if raw.risk_level in {models.RiskLevel.high, models.RiskLevel.forbidden}:
        return None
    if raw.desensitization_status not in {
        models.DesensitizationStatus.not_needed,
        models.DesensitizationStatus.done,
    }:
        return None

    next_id = (db.query(func.count(models.StandardQAItem.id)).scalar() or 0) + 1
    standard = models.StandardQAItem(
        standard_code=f"STD-{next_id:05d}",
        source_raw_qa_id=raw.id,
        session_id=raw.session_id,
        standard_question=raw.suggested_standard_question or raw.normalized_question or raw.raw_question,
        standard_answer=raw.suggested_standard_answer or raw.normalized_answer or raw.raw_answer,
        similar_questions=[raw.normalized_question] if raw.normalized_question else [],
        primary_topic=raw.primary_topic,
        problem_tags=raw.problem_tags,
        course_stage=raw.course_stage,
        audience_tags=raw.audience_tags,
        answer_boundary="只基于已审核答疑内容复用；不做心理诊断、医疗建议、法律判断或课程效果承诺。",
        forbidden_expressions=["保证有效", "一定改变", "诊断为", "法律上必然"],
        risk_level=raw.risk_level,
        audit_status=models.AuditStatus.approved,
        call_status=models.CallStatus.not_callable,
        last_reviewer_id=reviewer_id,
    )
    db.add(standard)
    return standard


def approve_raw_qa(
    db: Session, raw: models.RawQAItem, reviewer_id: int | None = None, comment: str | None = None
) -> models.RawQAItem:
    reviewer_id = _default_reviewer_id(db, reviewer_id)
    before = raw.review_status.value
    raw.review_status = models.ReviewStatus.approved
    raw.reviewer_id = reviewer_id
    if comment:
        raw.review_notes = comment
    add_audit_log(
        db,
        user_id=reviewer_id,
        target_type=models.TargetType.raw_qa,
        target_id=raw.id,
        action=models.AuditAction.approve,
        before_status=before,
        after_status=raw.review_status.value,
        comment=comment,
    )
    standard = create_standard_from_raw(db, raw, reviewer_id)
    if standard:
        db.flush()
        add_audit_log(
            db,
            user_id=reviewer_id,
            target_type=models.TargetType.standard_qa,
            target_id=standard.id,
            action=models.AuditAction.approve,
            before_status="none",
            after_status=models.AuditStatus.approved.value,
            comment="由原始问答审核通过后生成，默认 not_callable。",
        )
    refresh_session_counts(db, raw.session_id)
    db.commit()
    feishu = FeishuClient()
    if standard:
        try:
            feishu.write_standard_qa_items([standard])
        except Exception as exc:  # noqa: BLE001
            add_audit_log(
                db,
                user_id=reviewer_id,
                target_type=models.TargetType.standard_qa,
                target_id=standard.id,
                action=models.AuditAction.revise,
                before_status="feishu_write",
                after_status="failed",
                comment=f"飞书标准问答回写失败：{exc}",
            )
            db.commit()
    session = db.get(models.FeishuSession, raw.session_id)
    if session:
        try:
            feishu.update_session_status(session, session.process_status.value)
        except Exception as exc:  # noqa: BLE001
            add_audit_log(
                db,
                user_id=reviewer_id,
                target_type=models.TargetType.session,
                target_id=session.id,
                action=models.AuditAction.revise,
                before_status="feishu_session_sync",
                after_status="failed",
                comment=f"飞书场次统计回写失败：{exc}",
            )
            db.commit()
    db.refresh(raw)
    return raw


def set_raw_status(
    db: Session,
    raw: models.RawQAItem,
    status: models.ReviewStatus,
    action: models.AuditAction,
    reviewer_id: int | None = None,
    comment: str | None = None,
) -> models.RawQAItem:
    reviewer_id = _default_reviewer_id(db, reviewer_id)
    before = raw.review_status.value
    raw.review_status = status
    raw.reviewer_id = reviewer_id
    if comment:
        raw.review_notes = comment
    add_audit_log(
        db,
        user_id=reviewer_id,
        target_type=models.TargetType.raw_qa,
        target_id=raw.id,
        action=action,
        before_status=before,
        after_status=status.value,
        comment=comment,
    )
    refresh_session_counts(db, raw.session_id)
    db.commit()
    db.refresh(raw)
    return raw


def mark_standard_call_status(
    db: Session,
    standard: models.StandardQAItem,
    status: models.CallStatus,
    reviewer_id: int | None = None,
    comment: str | None = None,
) -> models.StandardQAItem:
    reviewer_id = _default_reviewer_id(db, reviewer_id)
    before = standard.call_status.value
    if status == models.CallStatus.callable:
        raw = standard.source_raw_qa
        if (
            standard.audit_status != models.AuditStatus.approved
            or standard.risk_level not in {models.RiskLevel.low, models.RiskLevel.medium}
            or raw.desensitization_status
            not in {models.DesensitizationStatus.not_needed, models.DesensitizationStatus.done}
        ):
            raise ValueError("只有已审核、低/中风险、且已完成脱敏或无需脱敏的标准问答可以标记为可调用")
    standard.call_status = status
    standard.last_reviewer_id = reviewer_id
    add_audit_log(
        db,
        user_id=reviewer_id,
        target_type=models.TargetType.standard_qa,
        target_id=standard.id,
        action=models.AuditAction.mark_callable if status == models.CallStatus.callable else models.AuditAction.disable,
        before_status=before,
        after_status=status.value,
        comment=comment,
    )
    db.commit()
    db.refresh(standard)
    return standard
