from fastapi import APIRouter,Depends,Header,HTTPException,Request
from pydantic import BaseModel,Field
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.api.deps import current_user,require_roles
from app.core.database import get_db
from app.models.entities import User,Role,Tenant,TenantIsolationPolicy,TenantIsolationViolation,TenantMigrationBatch,TenantResourceScope
from app.services.saas_tenancy import resolve_membership
from app.services.tenant_isolation import bind_resource,assert_resource_access,start_migration,finish_migration,isolation_summary
router=APIRouter(prefix='/api/v021',tags=['V021 Tenant Isolation'])
PLATFORM=(Role.admin,Role.director)

class BindingIn(BaseModel):
    resource_type:str; resource_id:str; source_table:str=''; isolation_mode:str='physical'
class AccessCheckIn(BaseModel):
    resource_type:str; resource_id:str; action:str='read'
class MigrationIn(BaseModel):
    resource_type:str; resource_ids:list[str]=Field(default_factory=list,max_length=10000); dry_run:bool=True; strategy:str='manual'
class PolicyIn(BaseModel):
    enforcement_mode:str='strict'; require_tenant_header:bool=True; block_unscoped_resources:bool=True
    audit_denied_access:bool=True; allow_platform_override:bool=False; legacy_migration_complete:bool=False

def tenant_admin(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)
    if not tenant or tenant.status!='active': raise HTTPException(404,'Tenant ativo não encontrado')
    membership=resolve_membership(db,user,tenant.id)
    if user.role not in PLATFORM and (not membership or membership.tenant_role not in ('owner','admin')):
        raise HTTPException(403,'Administração do tenant necessária')
    return tenant

@router.get('/summary')
def summary(tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db),user:User=Depends(current_user)):
    return isolation_summary(db,tenant.id)
@router.post('/resources/bind')
def bind(p:BindingIn,tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db),user:User=Depends(current_user)):
    try:return bind_resource(db,tenant.id,p.resource_type,p.resource_id,user.id,p.source_table,p.isolation_mode)
    except ValueError as exc: raise HTTPException(409,str(exc))
@router.post('/resources/check')
def check(p:AccessCheckIn,request:Request,x_tenant_id:str=Header(...,alias='X-Tenant-ID'),db:Session=Depends(get_db),user:User=Depends(current_user)):
    try:
        scope=assert_resource_access(db,user,x_tenant_id,p.resource_type,p.resource_id,p.action,request.headers.get('X-Request-ID',''))
        return {'allowed':True,'scope_id':getattr(scope,'id',None),'tenant_id':x_tenant_id}
    except PermissionError as exc: raise HTTPException(403,str(exc))
@router.post('/migrations')
def migrate(p:MigrationIn,tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db),user:User=Depends(current_user)):
    try:
        batch=start_migration(db,tenant.id,p.resource_type,user.id,p.dry_run,p.strategy)
        return finish_migration(db,batch,p.resource_ids)
    except ValueError as exc: raise HTTPException(400,str(exc))
@router.get('/migrations')
def migrations(tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db),user:User=Depends(current_user)):
    return db.scalars(select(TenantMigrationBatch).where(TenantMigrationBatch.tenant_id==tenant.id).order_by(TenantMigrationBatch.created_at.desc()).limit(200)).all()
@router.put('/policy')
def policy(p:PolicyIn,tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db),user:User=Depends(current_user)):
    obj=db.scalar(select(TenantIsolationPolicy).where(TenantIsolationPolicy.tenant_id==tenant.id)) or TenantIsolationPolicy(tenant_id=tenant.id)
    for k,v in p.model_dump().items(): setattr(obj,k,v)
    obj.updated_by=user.id; db.add(obj); db.commit(); db.refresh(obj); return obj
@router.get('/violations')
def violations(tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db),user:User=Depends(current_user)):
    return db.scalars(select(TenantIsolationViolation).where(TenantIsolationViolation.tenant_id==tenant.id).order_by(TenantIsolationViolation.created_at.desc()).limit(500)).all()
@router.get('/resources')
def resources(tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db),user:User=Depends(current_user)):
    return db.scalars(select(TenantResourceScope).where(TenantResourceScope.tenant_id==tenant.id).order_by(TenantResourceScope.assigned_at.desc()).limit(1000)).all()
