from contextlib import asynccontextmanager
import json
from typing import List

from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect, HTTPException, Depends
from fastapi.middleware.cors import CORSMiddleware
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

from app.clients.backend_client import close_client, forward
from app.config.settings import settings
from app.middleware.logging import RequestLoggingMiddleware
from app.middleware.rate_limit import RateLimitMiddleware


@asynccontextmanager
async def lifespan(app: FastAPI):
    yield
    await close_client()


app = FastAPI(title="TA-ATS Gateway", version="1.0.0", lifespan=lifespan)

app.add_middleware(RateLimitMiddleware)
app.add_middleware(RequestLoggingMiddleware)
app.add_middleware(
    CORSMiddleware,
    allow_origins=[settings.FRONTEND_ORIGIN],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


# --- WebSocket Manager ---
class ConnectionManager:
    def __init__(self):
        self.active_connections: List[WebSocket] = []

    async def connect(self, websocket: WebSocket):
        await websocket.accept()
        self.active_connections.append(websocket)

    def disconnect(self, websocket: WebSocket):
        if websocket in self.active_connections:
            self.active_connections.remove(websocket)

    async def broadcast(self, message: str):
        for connection in self.active_connections:
            try:
                await connection.send_text(message)
            except Exception:
                pass


manager = ConnectionManager()


@app.websocket("/api/ws/activity")
async def websocket_endpoint(websocket: WebSocket):
    await manager.connect(websocket)
    try:
        while True:
            # Listen to keep connection alive
            await websocket.receive_text()
    except WebSocketDisconnect:
        manager.disconnect(websocket)


# --- Broadcast webhook ---
security = HTTPBearer()


def verify_internal_secret(credentials: HTTPAuthorizationCredentials = Depends(security)):
    if credentials.credentials != settings.INTERNAL_API_SECRET:
        raise HTTPException(status_code=403, detail="Invalid internal API secret")
    return True


@app.post("/api/v1/gateway/broadcast")
async def broadcast_activity(request: Request, authenticated: bool = Depends(verify_internal_secret)):
    """Receives audit events from Django and broadcasts them to all WebSocket clients."""
    try:
        body = await request.json()
        await manager.broadcast(json.dumps(body))
        return {"status": "success", "broadcasted": len(manager.active_connections)}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))


@app.get("/health")
async def health():
    return {"status": "ok", "service": "gateway"}


@app.api_route("/api/{path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE"])
async def proxy(path: str, request: Request):
    """Forward every /api/* request to the Django backend."""
    return await forward(request, f"/api/{path}")
