from fastapi import APIRouter,Depends,HTTPException
from pydantic import BaseModel,Field
from sqlalchemy import select,delete
from sqlalchemy.orm import Session
from app.api.deps import get_db,current_user,require_roles
from app.models.entities import User,Role,SemanticModel,SemanticExecution,SemanticQueryCache,SemanticCostPolicy,SemanticMaterialization
from app.services.semantic_execution import execute_semantic,build_sql
from app.services.semantic_engine import semantic_plan
router=APIRouter(prefix='/api/v016',tags=['V016 Federated Semantic Execution'])
GOV=(Role.admin,Role.director,Role.data_engineer,Role.data_steward)
class ExecuteIn(BaseModel):
 model_id:str; metrics:list[str]=Field(default_factory=list); dimensions:list[str]=Field(default_factory=list); filters:dict=Field(default_factory=dict); limit:int=500; use_cache:bool=True
class PolicyIn(BaseModel):
 name:str; subject_type:str='role'; subject_value:str='viewer'; max_rows:int=5000; max_dimensions:int=8; max_metrics:int=12; max_cost_units:int=10000; timeout_seconds:int=30; cache_ttl_seconds:int=300
class MaterializationIn(BaseModel):
 model_id:str; name:str; metrics:list[str]=Field(default_factory=list); dimensions:list[str]=Field(default_factory=list); filters:dict=Field(default_factory=dict); schedule_cron:str='0 * * * *'; destination_object:str=''
@router.get('/summary')
def summary(db:Session=Depends(get_db),user:User=Depends(current_user)):
 return {'executions':len(db.scalars(select(SemanticExecution)).all()),'cache_entries':len(db.scalars(select(SemanticQueryCache)).all()),'cost_policies':len(db.scalars(select(SemanticCostPolicy)).all()),'materializations':len(db.scalars(select(SemanticMaterialization)).all())}
@router.post('/query/plan')
def plan(p:ExecuteIn,db:Session=Depends(get_db),user:User=Depends(current_user)):
 model=db.get(SemanticModel,p.model_id)
 if not model: raise HTTPException(404,'Modelo não encontrado')
 try: q=semantic_plan(db,user,model,p.metrics,p.dimensions,p.filters,p.limit); sql,params=build_sql(q); return {'plan':q,'sql_preview':sql,'parameter_names':list(params)}
 except (ValueError,PermissionError) as e: raise HTTPException(400,str(e))
@router.post('/query/execute')
def execute(p:ExecuteIn,db:Session=Depends(get_db),user:User=Depends(current_user)):
 model=db.get(SemanticModel,p.model_id)
 if not model: raise HTTPException(404,'Modelo não encontrado')
 try: return execute_semantic(db,user,model,p.metrics,p.dimensions,p.filters,p.limit,p.use_cache)
 except PermissionError as e: raise HTTPException(403,str(e))
 except ValueError as e: raise HTTPException(400,str(e))
 except Exception as e: raise HTTPException(502,f'Falha na execução física: {str(e)[:500]}')
@router.get('/executions')
def executions(limit:int=100,db:Session=Depends(get_db),user:User=Depends(current_user)):
 q=select(SemanticExecution).order_by(SemanticExecution.created_at.desc()).limit(min(max(limit,1),500))
 if user.role not in GOV and user.role!=Role.auditor: q=q.where(SemanticExecution.user_id==user.id)
 return db.scalars(q).all()
@router.post('/cost-policies')
def create_policy(p:PolicyIn,db:Session=Depends(get_db),user:User=Depends(require_roles(*GOV))):
 obj=SemanticCostPolicy(**p.model_dump(),created_by=user.id); db.add(obj); db.commit(); db.refresh(obj); return obj
@router.get('/cost-policies')
def policies(db:Session=Depends(get_db),user:User=Depends(require_roles(*GOV))): return db.scalars(select(SemanticCostPolicy)).all()
@router.delete('/cache')
def clear_cache(model_id:str|None=None,db:Session=Depends(get_db),user:User=Depends(require_roles(*GOV))):
 stmt=delete(SemanticQueryCache); stmt=stmt.where(SemanticQueryCache.model_id==model_id) if model_id else stmt; r=db.execute(stmt); db.commit(); return {'deleted':r.rowcount}
@router.post('/materializations')
def create_materialization(p:MaterializationIn,db:Session=Depends(get_db),user:User=Depends(require_roles(*GOV))):
 obj=SemanticMaterialization(**p.model_dump(),owner_id=user.id); db.add(obj); db.commit(); db.refresh(obj); return obj
@router.get('/materializations')
def materializations(db:Session=Depends(get_db),user:User=Depends(current_user)): return db.scalars(select(SemanticMaterialization).order_by(SemanticMaterialization.created_at.desc())).all()
