import hmac
import hashlib
from celery import shared_task
import httpx
from sqlalchemy.orm import Session
from app.db.session import SessionLocal
from app.db.models import WebhookEvent, Webhook


@shared_task(bind=True, name="app.workers.webhooks.deliver_webhook", max_retries=5)
def deliver_webhook(self, event_id: int) -> str:
    """
    Deliver webhook event with HMAC signature
    
    Args:
        event_id: WebhookEvent record ID
    
    Retry policy: max 5 attempts with exponential backoff
    Signature: X-Signature header with HMAC-SHA256(secret, payload)
    """
    db: Session = SessionLocal()
    
    try:
        event = db.query(WebhookEvent).filter(WebhookEvent.id == event_id).first()
        if not event:
            return f"webhook_event:{event_id}:not_found"
        
        webhook = db.query(Webhook).filter(Webhook.id == event.webhook_id).first()
        if not webhook:
            return f"webhook_event:{event_id}:webhook_not_found"
        
        # Prepare payload
        import json
        payload_str = json.dumps(event.payload, sort_keys=True)
        
        # Generate HMAC signature
        signature = hmac.new(
            webhook.secret.encode(),
            payload_str.encode(),
            hashlib.sha256
        ).hexdigest()
        
        headers = {
            "Content-Type": "application/json",
            "X-Signature": signature,
            "X-Event-Type": event.type,
        }
        
        # Send webhook
        try:
            with httpx.Client(timeout=10.0) as client:
                response = client.post(webhook.url, content=payload_str, headers=headers)
                response.raise_for_status()
            
            event.delivered_at = db.func.now()
            event.attempts += 1
            db.commit()
            
            return f"webhook_event:{event_id}:delivered"
        
        except httpx.HTTPError as e:
            event.attempts += 1
            db.commit()
            
            if event.attempts < 5:
                raise self.retry(countdown=2 ** event.attempts)
            else:
                return f"webhook_event:{event_id}:exhausted:{str(e)}"
    
    except Exception as e:
        raise self.retry(exc=e, countdown=10)
    
    finally:
        db.close()
