import json
from pydantic import BaseModel, EmailStr, Field
from fastapi import APIRouter, Depends, Header, HTTPException, Request
from sqlalchemy import select
from sqlalchemy.orm import Session
from app.core.database import get_db
from app.core.config import settings
from app.api.deps import current_user
from app.models.entities import User,Tenant,BillingInvoice,SaaSOnboardingApplication,TenantRateLimitPolicy,UsageReconciliationRun
from app.services.saas_tenancy import resolve_membership
from app.services.saas_commercial import create_onboarding,activate_onboarding,expire_quota_reservations,create_invoice,verify_webhook,register_webhook
router=APIRouter(prefix='/api/v023',tags=['V023 SaaS Commercial Operations'])
PLATFORM={'admin','director'}
class OnboardingIn(BaseModel): company_name:str=Field(min_length=2,max_length=220); admin_name:str=Field(min_length=2,max_length=180); admin_email:EmailStr; tax_id:str=''; plan_code:str='trial'
class ActivateIn(BaseModel): token:str=Field(min_length=20); password:str=Field(min_length=12,max_length=200)
class RateIn(BaseModel): scope:str='api'; requests_per_minute:int=Field(default=600,ge=1,le=100000); burst:int=Field(default=100,ge=0,le=10000); enabled:bool=True

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')
    role=getattr(user.role,'value',user.role); membership=resolve_membership(db,user,tenant.id)
    if 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)):
    return {'version':'V023','tenant_id':tenant.id,'onboarding':'public_activation','billing':'provider_adapter','reconciliation_runs':len(db.scalars(select(UsageReconciliationRun).where(UsageReconciliationRun.tenant_id==tenant.id)).all())}
@router.post('/onboarding',status_code=201)
def onboarding(p:OnboardingIn,db:Session=Depends(get_db)):
    item,token=create_onboarding(db,p.company_name,p.admin_name,str(p.admin_email),p.tax_id,p.plan_code)
    result={'application_id':item.id,'status':item.status,'activation_expires_at':item.activation_expires_at}
    if settings.app_env!='production': result['activation_token']=token
    return result
@router.post('/onboarding/{application_id}/activate')
def activate(application_id:str,p:ActivateIn,db:Session=Depends(get_db)):
    try: tenant=activate_onboarding(db,application_id,p.token,p.password)
    except ValueError as exc: raise HTTPException(400,str(exc))
    return {'tenant_id':tenant.id,'slug':tenant.slug,'status':tenant.status}
@router.post('/quotas/reconcile')
def reconcile(tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db)):
    return expire_quota_reservations(db,tenant.id)
@router.post('/invoices')
def invoice(tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db)):
    try:return create_invoice(db,tenant.id)
    except ValueError as exc: raise HTTPException(400,str(exc))
@router.get('/invoices')
def invoices(tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db)):
    return db.scalars(select(BillingInvoice).where(BillingInvoice.tenant_id==tenant.id).order_by(BillingInvoice.created_at.desc()).limit(200)).all()
@router.put('/rate-limit')
def rate_limit(p:RateIn,tenant:Tenant=Depends(tenant_admin),db:Session=Depends(get_db)):
    item=db.scalar(select(TenantRateLimitPolicy).where(TenantRateLimitPolicy.tenant_id==tenant.id,TenantRateLimitPolicy.scope==p.scope)) or TenantRateLimitPolicy(tenant_id=tenant.id,scope=p.scope)
    item.requests_per_minute=p.requests_per_minute; item.burst=p.burst; item.enabled=p.enabled; db.add(item); db.commit(); db.refresh(item); return item
@router.post('/billing/webhooks/{provider}')
async def webhook(provider:str,request:Request,x_event_id:str=Header(...,alias='X-Event-ID'),x_event_type:str=Header(...,alias='X-Event-Type'),x_signature:str=Header('',alias='X-Signature'),db:Session=Depends(get_db)):
    body=await request.body(); secret=request.app.state.__dict__.get('billing_webhook_secret','development-secret')
    valid=verify_webhook(secret,body,x_signature)
    try: payload=json.loads(body or b'{}')
    except json.JSONDecodeError: raise HTTPException(400,'JSON inválido')
    item=register_webhook(db,provider,x_event_id,x_event_type,payload,valid)
    if not valid: raise HTTPException(401,'Assinatura inválida')
    return {'event_id':item.external_event_id,'status':item.status}
