from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException, Response, Header
from pydantic import BaseModel, Field
from sqlalchemy import select, func
from sqlalchemy.orm import Session
from app.api.deps import current_user, require_roles
from app.core.database import get_db
from app.core.config import settings
from app.models.entities import User, Role, ServiceHealthSnapshot, OperationalIncident, ObservabilityAlertPolicy, OperationalLogEvent, IngestionRun, QualityRun
from app.services.observability import collect_health, prometheus_text
router=APIRouter(prefix='/api/v013',tags=['V013 Observability'])
class PolicyIn(BaseModel):
    name:str; metric_name:str; operator:str='gt'; threshold:int=0; window_minutes:int=5; severity:str='warning'; cooldown_minutes:int=30; channels:list=Field(default_factory=list)
class IncidentPatch(BaseModel): status:str; resolution:str=''; owner_id:str|None=None
@router.get('/summary')
def summary(db:Session=Depends(get_db),user:User=Depends(current_user)):
    latest={}
    for s in db.scalars(select(ServiceHealthSnapshot).order_by(ServiceHealthSnapshot.checked_at.desc()).limit(30)).all(): latest.setdefault(s.service_name,{'status':s.status,'latency_ms':s.latency_ms,'checked_at':s.checked_at})
    return {'services':latest,'open_incidents':db.scalar(select(func.count()).select_from(OperationalIncident).where(OperationalIncident.status!='resolved')) or 0,'failed_ingestions':db.scalar(select(func.count()).select_from(IngestionRun).where(IngestionRun.status=='failed')) or 0,'failed_quality_runs':db.scalar(select(func.count()).select_from(QualityRun).where(QualityRun.status=='failed')) or 0}
@router.post('/health/check')
def health_check(user:User=Depends(require_roles(Role.admin,Role.director,Role.auditor,Role.data_engineer))): return {'checks':collect_health()}
@router.get('/health/history')
def health_history(limit:int=100,db:Session=Depends(get_db),user:User=Depends(current_user)):
    return db.scalars(select(ServiceHealthSnapshot).order_by(ServiceHealthSnapshot.checked_at.desc()).limit(min(limit,500))).all()
@router.get('/incidents')
def incidents(status:str|None=None,db:Session=Depends(get_db),user:User=Depends(current_user)):
    q=select(OperationalIncident).order_by(OperationalIncident.opened_at.desc()); q=q.where(OperationalIncident.status==status) if status else q
    return db.scalars(q.limit(300)).all()
@router.patch('/incidents/{incident_id}')
def update_incident(incident_id:str,p:IncidentPatch,db:Session=Depends(get_db),user:User=Depends(require_roles(Role.admin,Role.director,Role.auditor,Role.data_engineer))):
    obj=db.get(OperationalIncident,incident_id)
    if not obj: raise HTTPException(404,'Incidente não encontrado')
    obj.status=p.status; obj.resolution=p.resolution; obj.owner_id=p.owner_id or obj.owner_id
    if p.status=='acknowledged': obj.acknowledged_at=datetime.now(timezone.utc)
    if p.status=='resolved': obj.resolved_at=datetime.now(timezone.utc)
    db.commit(); db.refresh(obj); return obj
@router.post('/policies')
def create_policy(p:PolicyIn,db:Session=Depends(get_db),user:User=Depends(require_roles(Role.admin,Role.director,Role.data_engineer))):
    obj=ObservabilityAlertPolicy(**p.model_dump(),created_by=user.id); db.add(obj); db.commit(); db.refresh(obj); return obj
@router.get('/policies')
def policies(db:Session=Depends(get_db),user:User=Depends(current_user)): return db.scalars(select(ObservabilityAlertPolicy).order_by(ObservabilityAlertPolicy.created_at.desc())).all()
@router.get('/logs')
def logs(level:str|None=None,service:str|None=None,db:Session=Depends(get_db),user:User=Depends(require_roles(Role.admin,Role.director,Role.auditor,Role.data_engineer))):
    q=select(OperationalLogEvent).order_by(OperationalLogEvent.created_at.desc())
    if level:q=q.where(OperationalLogEvent.level==level)
    if service:q=q.where(OperationalLogEvent.service==service)
    return db.scalars(q.limit(500)).all()
@router.get('/metrics')
def metrics(authorization:str=Header(default='')):
    expected='Bearer '+settings.observability_metrics_token
    if not settings.observability_metrics_token or authorization!=expected: raise HTTPException(401,'Credencial de monitoramento inválida')
    return Response(prometheus_text(),media_type='text/plain; version=0.0.4')
