"""
API routes for Assertion Engine (Anti-Fake-Evidence Phase 2).

Endpoints:
- /assertions: CRUD for assertions
- /assertions/extract: Automatic extraction from entity text
- /assertions/summary: Stats (total assertions, facts, unverified)
"""

import logging
from datetime import datetime
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session

from classroom_engine.database import get_db

from ..db.models import AssertionDB
from ..services.assertion_engine import extract_assertions
from .schemas import (
    AssertionCreate,
    AssertionUpdate,
    AssertionResponse,
    AssertionListResponse,
    AssertionSummaryResponse,
    AssertionExtractRequest,
)
from .audit_trail_utils import log_audit_trail, generate_id

logger = logging.getLogger(__name__)
router = APIRouter(tags=["compliance-assertions"])


def _build_assertion_response(a: AssertionDB) -> AssertionResponse:
    return AssertionResponse(
        id=a.id,
        tenant_id=a.tenant_id,
        entity_type=a.entity_type,
        entity_id=a.entity_id,
        sentence_text=a.sentence_text,
        sentence_index=a.sentence_index,
        assertion_type=a.assertion_type,
        evidence_ids=a.evidence_ids or [],
        confidence=a.confidence or 0.0,
        normative_tier=a.normative_tier,
        verified_by=a.verified_by,
        verified_at=a.verified_at,
        created_at=a.created_at,
        updated_at=a.updated_at,
    )


@router.post("/assertions", response_model=AssertionResponse)
async def create_assertion(
    data: AssertionCreate,
    tenant_id: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    """Create a single assertion manually."""
    a = AssertionDB(
        id=generate_id(),
        tenant_id=tenant_id,
        entity_type=data.entity_type,
        entity_id=data.entity_id,
        sentence_text=data.sentence_text,
        assertion_type=data.assertion_type or "assertion",
        evidence_ids=data.evidence_ids or [],
        normative_tier=data.normative_tier,
    )
    db.add(a)
    db.commit()
    db.refresh(a)
    return _build_assertion_response(a)


@router.get("/assertions", response_model=AssertionListResponse)
async def list_assertions(
    entity_type: Optional[str] = Query(None),
    entity_id: Optional[str] = Query(None),
    assertion_type: Optional[str] = Query(None),
    tenant_id: Optional[str] = Query(None),
    limit: int = Query(100, ge=1, le=500),
    db: Session = Depends(get_db),
):
    """List assertions with optional filters."""
    query = db.query(AssertionDB)
    if entity_type:
        query = query.filter(AssertionDB.entity_type == entity_type)
    if entity_id:
        query = query.filter(AssertionDB.entity_id == entity_id)
    if assertion_type:
        query = query.filter(AssertionDB.assertion_type == assertion_type)
    if tenant_id:
        query = query.filter(AssertionDB.tenant_id == tenant_id)

    total = query.count()
    records = query.order_by(AssertionDB.sentence_index.asc()).limit(limit).all()

    return AssertionListResponse(
        assertions=[_build_assertion_response(a) for a in records],
        total=total,
    )


@router.get("/assertions/summary", response_model=AssertionSummaryResponse)
async def assertion_summary(
    tenant_id: Optional[str] = Query(None),
    entity_type: Optional[str] = Query(None),
    entity_id: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    """Summary stats: total assertions, facts, rationale, unverified."""
    query = db.query(AssertionDB)
    if tenant_id:
        query = query.filter(AssertionDB.tenant_id == tenant_id)
    if entity_type:
        query = query.filter(AssertionDB.entity_type == entity_type)
    if entity_id:
        query = query.filter(AssertionDB.entity_id == entity_id)

    all_records = query.all()

    total = len(all_records)
    facts = sum(1 for a in all_records if a.assertion_type == "fact")
    rationale = sum(1 for a in all_records if a.assertion_type == "rationale")
    unverified = sum(1 for a in all_records if a.assertion_type == "assertion" and not a.verified_by)

    return AssertionSummaryResponse(
        total_assertions=total,
        total_facts=facts,
        total_rationale=rationale,
        unverified_count=unverified,
    )


@router.get("/assertions/{assertion_id}", response_model=AssertionResponse)
async def get_assertion(
    assertion_id: str,
    db: Session = Depends(get_db),
):
    """Get a single assertion by ID."""
    a = db.query(AssertionDB).filter(AssertionDB.id == assertion_id).first()
    if not a:
        raise HTTPException(status_code=404, detail=f"Assertion {assertion_id} not found")
    return _build_assertion_response(a)


@router.put("/assertions/{assertion_id}", response_model=AssertionResponse)
async def update_assertion(
    assertion_id: str,
    data: AssertionUpdate,
    db: Session = Depends(get_db),
):
    """Update an assertion (e.g. link evidence, change type)."""
    a = db.query(AssertionDB).filter(AssertionDB.id == assertion_id).first()
    if not a:
        raise HTTPException(status_code=404, detail=f"Assertion {assertion_id} not found")

    update_fields = data.model_dump(exclude_unset=True)
    for key, value in update_fields.items():
        setattr(a, key, value)
    a.updated_at = datetime.utcnow()
    db.commit()
    db.refresh(a)
    return _build_assertion_response(a)


@router.post("/assertions/{assertion_id}/verify", response_model=AssertionResponse)
async def verify_assertion(
    assertion_id: str,
    verified_by: str = Query(...),
    db: Session = Depends(get_db),
):
    """Mark an assertion as verified fact."""
    a = db.query(AssertionDB).filter(AssertionDB.id == assertion_id).first()
    if not a:
        raise HTTPException(status_code=404, detail=f"Assertion {assertion_id} not found")

    a.assertion_type = "fact"
    a.verified_by = verified_by
    a.verified_at = datetime.utcnow()
    a.updated_at = datetime.utcnow()
    db.commit()
    db.refresh(a)
    return _build_assertion_response(a)


@router.post("/assertions/extract", response_model=AssertionListResponse)
async def extract_assertions_endpoint(
    data: AssertionExtractRequest,
    tenant_id: Optional[str] = Query(None),
    db: Session = Depends(get_db),
):
    """Extract assertions from free text and persist them."""
    extracted = extract_assertions(
        text=data.text,
        entity_type=data.entity_type,
        entity_id=data.entity_id,
        tenant_id=tenant_id,
    )

    created = []
    for item in extracted:
        a = AssertionDB(
            id=generate_id(),
            tenant_id=item["tenant_id"],
            entity_type=item["entity_type"],
            entity_id=item["entity_id"],
            sentence_text=item["sentence_text"],
            sentence_index=item["sentence_index"],
            assertion_type=item["assertion_type"],
            evidence_ids=item["evidence_ids"],
            normative_tier=item.get("normative_tier"),
            confidence=item.get("confidence", 0.0),
        )
        db.add(a)
        created.append(a)

    db.commit()
    for a in created:
        db.refresh(a)

    return AssertionListResponse(
        assertions=[_build_assertion_response(a) for a in created],
        total=len(created),
    )
