from fastapi import APIRouter, Request, HTTPException, Depends, Header from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, and_ from typing import Optional from pydantic import BaseModel from app.database import get_db from app.services.whatsapp import WhatsAppService from app.services.customer import CustomerService from app.api.v1.deps import get_current_user_id from app.models.customer import Customer from app.models.user import User router = APIRouter() @router.get("/webhook") async def verify_webhook( hub_mode: str = None, hub_verify_token: str = None, hub_challenge: str = None, ): svc = WhatsAppService() result = svc.verify_webhook(hub_mode, hub_verify_token, hub_challenge) if result: return int(result) raise HTTPException(status_code=403, detail="Verification failed") @router.post("/webhook") async def handle_webhook( request: Request, x_hub_signature_256: Optional[str] = Header(None), db: AsyncSession = Depends(get_db), ): svc = WhatsAppService() body = await request.body() if x_hub_signature_256: if not svc.verify_signature(body, x_hub_signature_256): raise HTTPException(status_code=403, detail="Invalid signature") import json body_json = json.loads(body) msg_data = svc.parse_webhook(body_json) if not msg_data: return {"status": "ok"} from_number = msg_data.get("from") text = msg_data.get("text", "") if from_number: result = await db.execute( select(Customer).where(Customer.whatsapp_id == from_number) ) customer = result.scalar_one_or_none() if customer: user_id = str(customer.user_id) cust_svc = CustomerService(db) await cust_svc.save_message( user_id=user_id, customer_id=str(customer.id), direction="inbound", content=text, ) return {"status": "ok", "message": "received"} class SendMessageRequest(BaseModel): to: str text: str = "" template_name: Optional[str] = None template_params: Optional[dict] = None media_url: Optional[str] = None media_type: Optional[str] = None @router.post("/send") async def send_message( data: SendMessageRequest, user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): svc = WhatsAppService() sent = False if data.template_name and data.template_params: sent = await svc.send_template(data.to, data.template_name, data.template_params) elif data.media_url and data.media_type: sent = await svc.send_media(data.to, data.media_url, data.media_type, caption=data.text) elif data.text: sent = await svc.send_text(data.to, data.text) else: raise HTTPException(status_code=400, detail="text, template, or media required") if not sent: raise HTTPException(status_code=500, detail="Failed to send WhatsApp message") cust_svc = CustomerService(db) result = await db.execute( select(Customer).where( and_(Customer.whatsapp_id == data.to, Customer.user_id == user_id) ) ) customer = result.scalar_one_or_none() if customer: await cust_svc.save_message( user_id=user_id, customer_id=str(customer.id), direction="outbound", content=data.text or f"[{data.media_type or 'template'}]", ) return {"status": "sent", "to": data.to} @router.get("/qr") async def get_qr(): return {"message": "WhatsApp QR login not available via API. Use WhatsApp Cloud API instead."}