import json
from datetime import datetime,timezone
from pydantic import BaseModel,Field
from fastapi import APIRouter,Depends,Header,HTTPException
from sqlalchemy import select,func
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.security import encrypt_secret
from app.api.deps import current_user
from app.models.entities import (User,Tenant,AICenterProvider,AICenterModel,AICenterTool,AIAgent,AICenterConversation,
 AICenterMessage,AIPromptAsset,AIApprovalRequest,AICostLedger)
from app.services.saas_tenancy import resolve_membership
from app.services.ai_center import chat,execute_tool,agent_allowed

router=APIRouter(prefix='/api/v027',tags=['V027 Enterprise AI Center'])
ADMIN={'admin','director','data_steward'}

def ctx(x_tenant_id:str=Header(...,alias='X-Tenant-ID'),db:Session=Depends(get_db),user:User=Depends(current_user)):
    tenant=db.get(Tenant,x_tenant_id); member=resolve_membership(db,user,x_tenant_id) if tenant else None
    if not tenant or tenant.status!='active': raise HTTPException(404,'Tenant ativo não encontrado')
    if getattr(user.role,'value',user.role) not in {'admin','director'} and not member: raise HTTPException(403,'Usuário não pertence ao tenant')
    return tenant,user

def admin(c=Depends(ctx)):
    if getattr(c[1].role,'value',c[1].role) not in ADMIN: raise HTTPException(403,'Perfil administrativo necessário')
    return c

class ProviderIn(BaseModel):
    name:str; provider_type:str; base_url:str=''; config:dict=Field(default_factory=dict); enabled:bool=True
class ModelIn(BaseModel):
    provider_id:str; name:str; model_code:str; capabilities:list=Field(default_factory=list); context_window:int=0; input_cost_per_million:int=0; output_cost_per_million:int=0; enabled:bool=True
class AgentIn(BaseModel):
    name:str; description:str=''; department_id:str|None=None; model_id:str; system_prompt:str=''; tool_codes:list=Field(default_factory=list); knowledge_base_ids:list=Field(default_factory=list); dataset_ids:list=Field(default_factory=list); allowed_roles:list=Field(default_factory=list); memory_enabled:bool=True; max_context_chars:int=20000; enabled:bool=True
class PromptIn(BaseModel): name:str; template:str; variables:list=Field(default_factory=list)
class ConversationIn(BaseModel): agent_id:str; title:str='Nova conversa'
class ChatIn(BaseModel): question:str=Field(min_length=1,max_length=20000)
class ToolIn(BaseModel): code:str; name:str; description:str=''; risk_level:str='low'; requires_approval:bool=False; configuration:dict=Field(default_factory=dict)
class ToolExecuteIn(BaseModel): tool_code:str; arguments:dict=Field(default_factory=dict); conversation_id:str|None=None

@router.get('/summary')
def summary(c=Depends(ctx),db:Session=Depends(get_db)):
    t,_=c
    return {'version':'V027','providers':db.scalar(select(func.count()).select_from(AICenterProvider).where(AICenterProvider.tenant_id==t.id)) or 0,'models':db.scalar(select(func.count()).select_from(AICenterModel).where(AICenterModel.tenant_id==t.id)) or 0,'agents':db.scalar(select(func.count()).select_from(AIAgent).where(AIAgent.tenant_id==t.id)) or 0,'conversations':db.scalar(select(func.count()).select_from(AICenterConversation).where(AICenterConversation.tenant_id==t.id)) or 0}

@router.post('/providers')
def create_provider(p:ProviderIn,c=Depends(admin),db:Session=Depends(get_db)):
    t,u=c; x=AICenterProvider(tenant_id=t.id,name=p.name,provider_type=p.provider_type,base_url=p.base_url,encrypted_config=encrypt_secret(json.dumps(p.config)),enabled=p.enabled,created_by=u.id); db.add(x); db.commit(); db.refresh(x); return {'id':x.id,'name':x.name,'provider_type':x.provider_type,'base_url':x.base_url,'enabled':x.enabled}
@router.get('/providers')
def providers(c=Depends(ctx),db:Session=Depends(get_db)):
    t,_=c; rows=db.scalars(select(AICenterProvider).where(AICenterProvider.tenant_id==t.id).order_by(AICenterProvider.created_at.desc())).all(); return [{'id':x.id,'name':x.name,'provider_type':x.provider_type,'base_url':x.base_url,'enabled':x.enabled} for x in rows]

@router.post('/models')
def create_model(p:ModelIn,c=Depends(admin),db:Session=Depends(get_db)):
    t,_=c; prov=db.get(AICenterProvider,p.provider_id)
    if not prov or prov.tenant_id!=t.id: raise HTTPException(404,'Provedor não encontrado')
    x=AICenterModel(tenant_id=t.id,**p.model_dump()); db.add(x); db.commit(); db.refresh(x); return x
@router.get('/models')
def models(c=Depends(ctx),db:Session=Depends(get_db)):
    t,_=c; return db.scalars(select(AICenterModel).where(AICenterModel.tenant_id==t.id).order_by(AICenterModel.created_at.desc())).all()

@router.post('/tools')
def create_tool(p:ToolIn,c=Depends(admin),db:Session=Depends(get_db)):
    t,_=c; x=AICenterTool(tenant_id=t.id,**p.model_dump()); db.add(x); db.commit(); db.refresh(x); return x
@router.get('/tools')
def tools(c=Depends(ctx),db:Session=Depends(get_db)):
    t,_=c; return db.scalars(select(AICenterTool).where((AICenterTool.tenant_id==t.id)|(AICenterTool.tenant_id.is_(None)),AICenterTool.enabled==True).order_by(AICenterTool.name)).all()

@router.post('/agents')
def create_agent(p:AgentIn,c=Depends(admin),db:Session=Depends(get_db)):
    t,u=c; model=db.get(AICenterModel,p.model_id)
    if not model or model.tenant_id!=t.id: raise HTTPException(404,'Modelo não encontrado')
    x=AIAgent(tenant_id=t.id,owner_id=u.id,**p.model_dump()); db.add(x); db.commit(); db.refresh(x); return x
@router.get('/agents')
def agents(c=Depends(ctx),db:Session=Depends(get_db)):
    t,u=c; rows=db.scalars(select(AIAgent).where(AIAgent.tenant_id==t.id,AIAgent.enabled==True).order_by(AIAgent.name)).all(); return [x for x in rows if agent_allowed(x,u)]

@router.post('/prompts')
def create_prompt(p:PromptIn,c=Depends(ctx),db:Session=Depends(get_db)):
    t,u=c; x=AIPromptAsset(tenant_id=t.id,name=p.name,template=p.template,variables=p.variables,created_by=u.id); db.add(x); db.commit(); db.refresh(x); return x
@router.post('/prompts/{prompt_id}/approve')
def approve_prompt(prompt_id:str,c=Depends(admin),db:Session=Depends(get_db)):
    t,u=c; x=db.get(AIPromptAsset,prompt_id)
    if not x or x.tenant_id!=t.id: raise HTTPException(404,'Prompt não encontrado')
    x.status='approved'; x.approved_by=u.id; db.commit(); return x

@router.post('/conversations')
def create_conversation(p:ConversationIn,c=Depends(ctx),db:Session=Depends(get_db)):
    t,u=c; agent=db.get(AIAgent,p.agent_id)
    if not agent or agent.tenant_id!=t.id or not agent_allowed(agent,u): raise HTTPException(403,'Agente não autorizado')
    x=AICenterConversation(tenant_id=t.id,agent_id=agent.id,user_id=u.id,title=p.title); db.add(x); db.commit(); db.refresh(x); return x
@router.get('/conversations')
def conversations(c=Depends(ctx),db:Session=Depends(get_db)):
    t,u=c; return db.scalars(select(AICenterConversation).where(AICenterConversation.tenant_id==t.id,AICenterConversation.user_id==u.id).order_by(AICenterConversation.updated_at.desc()).limit(100)).all()
@router.get('/conversations/{conversation_id}/messages')
def messages(conversation_id:str,c=Depends(ctx),db:Session=Depends(get_db)):
    t,u=c; conv=db.get(AICenterConversation,conversation_id)
    if not conv or conv.tenant_id!=t.id or conv.user_id!=u.id: raise HTTPException(404,'Conversa não encontrada')
    return db.scalars(select(AICenterMessage).where(AICenterMessage.conversation_id==conversation_id).order_by(AICenterMessage.created_at)).all()
@router.post('/conversations/{conversation_id}/chat')
def send_chat(conversation_id:str,p:ChatIn,c=Depends(ctx),db:Session=Depends(get_db)):
    t,u=c; conv=db.get(AICenterConversation,conversation_id)
    if not conv or conv.tenant_id!=t.id or conv.user_id!=u.id: raise HTTPException(404,'Conversa não encontrada')
    agent=db.get(AIAgent,conv.agent_id)
    try: return chat(db,t.id,u,agent,conv,p.question)
    except PermissionError as e: raise HTTPException(403,str(e))
    except Exception as e: raise HTTPException(400,f'Falha na IA: {str(e)[:500]}')

@router.post('/tools/execute')
def run_tool(p:ToolExecuteIn,c=Depends(ctx),db:Session=Depends(get_db)):
    t,u=c; conv=db.get(AICenterConversation,p.conversation_id) if p.conversation_id else None
    if conv and (conv.tenant_id!=t.id or conv.user_id!=u.id): raise HTTPException(403,'Conversa inválida')
    agent=db.get(AIAgent,conv.agent_id) if conv else None
    if not agent: raise HTTPException(400,'Conversa com agente obrigatória')
    try: return execute_tool(db,t.id,u,agent,p.tool_code,p.arguments,p.conversation_id)
    except ValueError as e: raise HTTPException(400,str(e))

@router.get('/approvals')
def approvals(c=Depends(admin),db:Session=Depends(get_db)):
    t,_=c; return db.scalars(select(AIApprovalRequest).where(AIApprovalRequest.tenant_id==t.id).order_by(AIApprovalRequest.created_at.desc()).limit(200)).all()
@router.post('/approvals/{approval_id}/{decision}')
def decide(approval_id:str,decision:str,reason:str='',c=Depends(admin),db:Session=Depends(get_db)):
    t,u=c; x=db.get(AIApprovalRequest,approval_id)
    if not x or x.tenant_id!=t.id: raise HTTPException(404,'Aprovação não encontrada')
    if decision not in {'approved','rejected'}: raise HTTPException(400,'Decisão inválida')
    x.status=decision; x.reviewer_id=u.id; x.reason=reason; x.decided_at=datetime.now(timezone.utc); db.commit(); return x

@router.get('/costs')
def costs(c=Depends(admin),db:Session=Depends(get_db)):
    t,_=c; return db.scalars(select(AICostLedger).where(AICostLedger.tenant_id==t.id).order_by(AICostLedger.created_at.desc()).limit(500)).all()
