"""대시보드 위젯 데이터 API"""

from typing import Annotated

from fastapi import APIRouter, Depends
from pydantic import BaseModel
from sqlalchemy import func, select, text
from sqlalchemy.ext.asyncio import AsyncSession

from core.auth import get_current_user
from core.database import get_session
from models.document import Document
from models.queue import ProcessingQueue
from models.user import User

router = APIRouter()


class DomainCount(BaseModel):
    domain: str | None
    count: int


class RecentDocument(BaseModel):
    id: int
    title: str | None
    file_format: str
    ai_domain: str | None
    created_at: str


class PipelineStatus(BaseModel):
    stage: str
    status: str
    count: int


class QueueLag(BaseModel):
    """파이프라인 stage 별 처리 지연 — 운영 카드용.

    pipeline_status 는 24h 누적 통계라 현재 적체 신호로 부족.
    queue_lag 는 현재 시점 pending/processing/failed + oldest pending age 로
    "지금 막힌 게 있는가" 를 보여준다.
    """
    stage: str
    pending: int
    processing: int
    failed: int
    oldest_pending_age_sec: int | None  # 가장 오래된 pending 의 created_at 기준 경과 (초)


class TierHealthStack(BaseModel):
    """PR-B B-3 — tier 관측성 카드 소스 (24h 윈도우).

    대시보드 카드 (Day 4 튜닝 — 2026-04-27 임계치 재조정):
      - "에스컬레이션 비율": escalated_total / triage_total
        · <80% 적색 (정책 매칭 실패 증가 — 진짜 튜닝 필요)
        · 80~99% 정상 (safety/health 정책 의도)
      - "triage JSON 건강도": triage_json_invalid / triage_total (>5% 적색)
      - "Backlog Suppression": suppressed_total / triage_total (>10% 주황)
      - "Deep summary 안정성": deep_err_total / deep_total (>5% 적색)
    """
    triage_total: int = 0
    escalated_total: int = 0
    escalation_by_reason: dict[str, int] = {}     # long_context / low_confidence / deep_requested / self_declare
    escalation_by_domain: dict[str, int] = {}     # safety_reference / news_item / ...
    triage_json_invalid: int = 0                  # error_code='triage_json_invalid'
    suppressed_total: int = 0                     # suppressed_reason IS NOT NULL
    # Day 4 튜닝 신규 — deep_summary 호출 안정성
    deep_total: int = 0                           # mode='summary_deep' 전체
    deep_err_total: int = 0                       # error_code IS NOT NULL (call_failed / parse:*)


class DashboardResponse(BaseModel):
    today_added: int
    today_by_domain: list[DomainCount]
    inbox_count: int
    law_alerts: int
    recent_documents: list[RecentDocument]
    pipeline_status: list[PipelineStatus]
    failed_count: int
    total_documents: int
    # 카운트 분리: 문서함(비-note/비-news) / 메모(memo+note) / 뉴스(news)
    documents_count: int = 0
    memos_count: int = 0
    news_count: int = 0
    # §4 — category 기반 카드 + 승인 pending + queue lag
    category_counts: dict[str, int] = {}
    library_pending_suggestions: int = 0
    queue_lag: list[QueueLag] = []
    # PR-B B-3 — tier 관측성
    tier_health: TierHealthStack = TierHealthStack()


@router.get("/", response_model=DashboardResponse)
async def get_dashboard(
    user: Annotated[User, Depends(get_current_user)],
    session: Annotated[AsyncSession, Depends(get_session)],
):
    """대시보드 위젯 데이터 집계"""

    # 오늘 추가된 문서
    today_result = await session.execute(
        select(Document.ai_domain, func.count(Document.id))
        .where(func.date(Document.created_at) == func.current_date())
        .group_by(Document.ai_domain)
    )
    today_rows = today_result.all()
    today_added = sum(row[1] for row in today_rows)

    # Inbox 미분류 수 (review_status = pending)
    inbox_result = await session.execute(
        select(func.count(Document.id))
        .where(
            Document.review_status == "pending",
            Document.deleted_at == None,
        )
    )
    inbox_count = inbox_result.scalar() or 0

    # 법령 알림 (오늘)
    law_result = await session.execute(
        select(func.count(Document.id))
        .where(
            Document.source_channel == "law_monitor",
            func.date(Document.created_at) == func.current_date(),
        )
    )
    law_alerts = law_result.scalar() or 0

    # 최근 문서 7건
    recent_result = await session.execute(
        select(Document)
        .order_by(Document.created_at.desc())
        .limit(7)
    )
    recent_docs = recent_result.scalars().all()

    # 파이프라인 상태 (24h)
    pipeline_result = await session.execute(
        text("""
            SELECT stage, status, COUNT(*)
            FROM processing_queue
            WHERE created_at > NOW() - INTERVAL '24 hours'
            GROUP BY stage, status
        """)
    )

    # 실패 건수
    failed_result = await session.execute(
        select(func.count())
        .select_from(ProcessingQueue)
        .where(ProcessingQueue.status == "failed")
    )
    failed_count = failed_result.scalar() or 0

    # 전체 문서 수 + 카테고리별 분리 (단일 쿼리)
    # 문서함: 비-note, 비-news / 메모: memo+note / 뉴스: news 유입 경로 기준
    count_result = await session.execute(
        text("""
            SELECT
                COUNT(*) AS total,
                COUNT(*) FILTER (WHERE source_channel NOT IN ('news', 'law_monitor') AND file_type != 'note') AS documents,
                COUNT(*) FILTER (WHERE source_channel = 'memo' AND file_type = 'note') AS memos,
                COUNT(*) FILTER (WHERE source_channel = 'news') AS news
            FROM documents WHERE deleted_at IS NULL
        """)
    )
    counts = count_result.one()
    total_documents = counts[0]
    documents_count = counts[1]
    memos_count = counts[2]
    news_count = counts[3]

    # §4 — 카테고리별 count (§1 documents.category enum)
    cat_result = await session.execute(
        text("""
            SELECT category, COUNT(*)
            FROM documents
            WHERE deleted_at IS NULL AND category IS NOT NULL
            GROUP BY category
        """)
    )
    category_counts = {row[0]: row[1] for row in cat_result.all()}

    # §4 — 승인 대기 (library 제안)
    pending_result = await session.execute(
        text("""
            SELECT COUNT(*)
            FROM documents
            WHERE deleted_at IS NULL
              AND ai_suggestion IS NOT NULL
              AND ai_suggestion->>'proposed_category' = 'library'
        """)
    )
    library_pending_suggestions = pending_result.scalar() or 0

    # §4 — queue lag (현재 시점 stage 별 적체 신호)
    # extract/classify/embed 외에 stt/thumbnail (§3) 도 자동 포함.
    lag_result = await session.execute(
        text("""
            SELECT
                stage,
                COUNT(*) FILTER (WHERE status='pending')        AS pending,
                COUNT(*) FILTER (WHERE status='processing')     AS processing,
                COUNT(*) FILTER (WHERE status='failed')         AS failed,
                EXTRACT(EPOCH FROM (NOW() - MIN(created_at) FILTER (WHERE status='pending')))::int
                                                                AS oldest_pending_age_sec
            FROM processing_queue
            GROUP BY stage
            ORDER BY stage
        """)
    )
    queue_lag = [
        QueueLag(
            stage=row[0],
            pending=row[1] or 0,
            processing=row[2] or 0,
            failed=row[3] or 0,
            oldest_pending_age_sec=row[4],
        )
        for row in lag_result.all()
    ]

    # ─── PR-B B-3 — tier 관측성 (24h) + Day 4 deep_err 추가 ───
    tier_rows = (await session.execute(text("""
        SELECT
          COUNT(*) FILTER (WHERE mode = 'summary_triage')                                   AS triage_total,
          COUNT(*) FILTER (WHERE mode = 'summary_triage' AND escalated_to_26b = true)       AS escalated_total,
          COUNT(*) FILTER (WHERE mode = 'summary_triage' AND error_code = 'triage_json_invalid') AS json_invalid,
          COUNT(*) FILTER (WHERE mode = 'summary_triage' AND suppressed_reason IS NOT NULL) AS suppressed_total,
          COUNT(*) FILTER (WHERE mode = 'summary_deep')                                     AS deep_total,
          COUNT(*) FILTER (WHERE mode = 'summary_deep' AND error_code IS NOT NULL)          AS deep_err_total
        FROM analyze_events
        WHERE created_at > NOW() - INTERVAL '24 hours'
    """))).one()

    reason_rows = await session.execute(text("""
        SELECT unnest(escalation_reasons) AS reason, COUNT(*) AS n
        FROM analyze_events
        WHERE created_at > NOW() - INTERVAL '24 hours'
          AND mode = 'summary_triage'
          AND escalated_to_26b = true
        GROUP BY 1 ORDER BY 2 DESC
    """))
    escalation_by_reason = {r[0]: r[1] for r in reason_rows if r[0]}

    domain_rows = await session.execute(text("""
        SELECT subject_domain, COUNT(*) AS n
        FROM analyze_events
        WHERE created_at > NOW() - INTERVAL '24 hours'
          AND mode = 'summary_triage'
          AND escalated_to_26b = true
          AND subject_domain IS NOT NULL
        GROUP BY 1 ORDER BY 2 DESC
    """))
    escalation_by_domain = {r[0]: r[1] for r in domain_rows}

    tier_health = TierHealthStack(
        triage_total=int(tier_rows.triage_total or 0),
        escalated_total=int(tier_rows.escalated_total or 0),
        triage_json_invalid=int(tier_rows.json_invalid or 0),
        suppressed_total=int(tier_rows.suppressed_total or 0),
        deep_total=int(tier_rows.deep_total or 0),
        deep_err_total=int(tier_rows.deep_err_total or 0),
        escalation_by_reason=escalation_by_reason,
        escalation_by_domain=escalation_by_domain,
    )

    return DashboardResponse(
        today_added=today_added,
        today_by_domain=[
            DomainCount(domain=row[0], count=row[1]) for row in today_rows
        ],
        inbox_count=inbox_count,
        law_alerts=law_alerts,
        recent_documents=[
            RecentDocument(
                id=doc.id,
                title=doc.title,
                file_format=doc.file_format,
                ai_domain=doc.ai_domain,
                created_at=doc.created_at.isoformat() if doc.created_at else "",
            )
            for doc in recent_docs
        ],
        pipeline_status=[
            PipelineStatus(stage=row[0], status=row[1], count=row[2])
            for row in pipeline_result
        ],
        failed_count=failed_count,
        total_documents=total_documents,
        documents_count=documents_count,
        memos_count=memos_count,
        news_count=news_count,
        category_counts=category_counts,
        library_pending_suggestions=library_pending_suggestions,
        queue_lag=queue_lag,
        tier_health=tier_health,
    )
