from datetime import datetime, timezone
from fastapi import APIRouter, Depends, Header, HTTPException
from pydantic import BaseModel, Field
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.api.deps import current_user
from app.core.database import get_db
from app.models.entities import ImplementationProjectV034, NativeBackupRunV034, PlatformDiagnosticRunV034, PlatformReleaseV034, PlatformUpdateRunV034, Tenant, User
from app.services.deployment_v034 import create_native_backup, default_checklist, recalc_project, run_diagnostics
from app.services.saas_tenancy import resolve_membership
router=APIRouter(prefix='/api/v034',tags=['V034 Deployment and Implementation'])
ADMIN={'admin','director','manager','data_steward'}
def ctx(x_tenant_id:str|None=Header(None,alias='X-Tenant-ID'),db:Session=Depends(get_db),user:User=Depends(current_user)):
    tenant=db.get(Tenant,x_tenant_id) if x_tenant_id else None
    if tenant and tenant.status!='active': raise HTTPException(404,'Tenant ativo não encontrado')
    if tenant and getattr(user.role,'value',user.role) not in {'admin','director'} and not resolve_membership(db,user,tenant.id): 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 de gestão necessário')
    return c
class ProjectIn(BaseModel): name:str='Implantação inicial'; configuration:dict=Field(default_factory=dict)
class StepIn(BaseModel): status:str=Field(pattern='^(pending|in_progress|completed|blocked)$'); notes:str=''
class ReleaseIn(BaseModel): version:str; channel:str='stable'; package_path:str=''; checksum_sha256:str=''; changelog:str=''
@router.get('/summary')
def summary(c=Depends(ctx),db:Session=Depends(get_db)):
    tid=c[0].id if c[0] else None
    return {'version':'V034','projects':len(db.scalars(select(ImplementationProjectV034).where(ImplementationProjectV034.tenant_id==tid)).all()) if tid else 0,'diagnostics':len(db.scalars(select(PlatformDiagnosticRunV034)).all()),'backups':len(db.scalars(select(NativeBackupRunV034)).all())}
@router.post('/implementation-projects',status_code=201)
def create_project(p:ProjectIn,c=Depends(admin),db:Session=Depends(get_db)):
    if not c[0]: raise HTTPException(400,'X-Tenant-ID obrigatório')
    item=ImplementationProjectV034(tenant_id=c[0].id,name=p.name,configuration=p.configuration,checklist=default_checklist(),owner_id=c[1].id); recalc_project(item); db.add(item); db.commit(); db.refresh(item); return item
@router.get('/implementation-projects')
def projects(c=Depends(ctx),db:Session=Depends(get_db)):
    if not c[0]: return []
    return db.scalars(select(ImplementationProjectV034).where(ImplementationProjectV034.tenant_id==c[0].id).order_by(ImplementationProjectV034.started_at.desc())).all()
@router.patch('/implementation-projects/{project_id}/steps/{step_code}')
def update_step(project_id:str,step_code:str,p:StepIn,c=Depends(admin),db:Session=Depends(get_db)):
    item=db.get(ImplementationProjectV034,project_id)
    if not item or not c[0] or item.tenant_id!=c[0].id: raise HTTPException(404,'Projeto não encontrado')
    checklist=item.checklist or default_checklist(); found=False
    for step in checklist:
        if step['code']==step_code: step['status']=p.status; step['notes']=p.notes; found=True
    if not found: raise HTTPException(404,'Etapa não encontrada')
    item.checklist=list(checklist); recalc_project(item); db.commit(); db.refresh(item); return item
@router.post('/diagnostics')
def diagnostics(c=Depends(admin),db:Session=Depends(get_db)): return run_diagnostics(db,c[0].id if c[0] else None,c[1].id)
@router.get('/diagnostics')
def diagnostic_history(c=Depends(admin),db:Session=Depends(get_db)):
    q=select(PlatformDiagnosticRunV034).order_by(PlatformDiagnosticRunV034.started_at.desc()).limit(100)
    if c[0]: q=q.where((PlatformDiagnosticRunV034.tenant_id==c[0].id)|(PlatformDiagnosticRunV034.tenant_id.is_(None)))
    return db.scalars(q).all()
@router.post('/backups')
def backup(c=Depends(admin),db:Session=Depends(get_db)): return create_native_backup(db,c[0].id if c[0] else None,c[1].id)
@router.get('/backups')
def backups(c=Depends(admin),db:Session=Depends(get_db)): return db.scalars(select(NativeBackupRunV034).order_by(NativeBackupRunV034.started_at.desc()).limit(100)).all()
@router.post('/releases',status_code=201)
def release(p:ReleaseIn,c=Depends(admin),db:Session=Depends(get_db)):
    if getattr(c[1].role,'value',c[1].role) not in {'admin','director'}: raise HTTPException(403,'Administrador global necessário')
    item=PlatformReleaseV034(created_by=c[1].id,**p.model_dump()); db.add(item); db.commit(); db.refresh(item); return item
@router.get('/releases')
def releases(c=Depends(admin),db:Session=Depends(get_db)): return db.scalars(select(PlatformReleaseV034).order_by(PlatformReleaseV034.created_at.desc())).all()
@router.post('/releases/{release_id}/plan-update',status_code=201)
def plan_update(release_id:str,c=Depends(admin),db:Session=Depends(get_db)):
    release=db.get(PlatformReleaseV034,release_id)
    if not release: raise HTTPException(404,'Release não encontrada')
    item=PlatformUpdateRunV034(release_id=release.id,status='planned',previous_version='0.34.0',target_version=release.version,rollback_available=True,requested_by=c[1].id,log=[{'at':datetime.now(timezone.utc).isoformat(),'message':'Atualização planejada; backup obrigatório antes da aplicação'}]); db.add(item); db.commit(); db.refresh(item); return item
