"""
backend/routers/vault.py — Velocity Vault (Trackable Link) Router

Endpoints:
  POST /api/vault/generate-link  → Generate a trackable URL for a shared asset
  GET  /vault/{tracking_hash}    → Public link accessed by the prospect;
                                   logs the open, fires WS_ASSET_OPENED

SRS Reference: Section 3C — Velocity Link Generation
"""

from __future__ import annotations

import os
import secrets
from datetime import datetime, timezone
from typing import Optional

import asyncpg
from fastapi import APIRouter, Depends, HTTPException, Request, status
from fastapi.responses import RedirectResponse, JSONResponse
from pydantic import BaseModel, UUID4

from backend.auth.dependencies import UserPrincipal, require_role
from backend.db.pool import get_pool

router = APIRouter()

# ── Pydantic models ───────────────────────────────────────────────────────────

class GenerateLinkRequest(BaseModel):
    lead_id: str
    asset_name: str
    asset_type: str    # 'pdf' | 'image' | 'video'
    storage_path: str  # relative to /opt/dlami/nvme/assets/


class GenerateLinkResponse(BaseModel):
    tracking_hash: str
    vault_url: str
    asset_id: str


# ── Helper: WebSocket broadcast ───────────────────────────────────────────────

async def _broadcast_vault_opened(
    request: Request,
    lead_id: str,
    lead_name: str,
    asset_name: str,
    tracking_hash: str,
    ip: Optional[str],
) -> None:
    """Fires WS_ASSET_OPENED to all broker WebSocket clients watching this lead."""
    broadcast = getattr(request.app.state, "broadcast_sentinel_event", None)
    if broadcast:
        await broadcast({
            "type": "WS_ASSET_OPENED",
            "data": {
                "lead_id": lead_id,
                "lead_name": lead_name,
                "asset_name": asset_name,
                "tracking_hash": tracking_hash,
                "opened_at": datetime.now(timezone.utc).isoformat(),
                "ip": ip,
            },
        })


# ── POST /api/vault/generate-link ─────────────────────────────────────────────

@router.post(
    "/generate-link",
    response_model=GenerateLinkResponse,
    status_code=status.HTTP_201_CREATED,
    summary="Generate a trackable Velocity Link for a document share",
)
async def generate_link(
    body: GenerateLinkRequest,
    request: Request,
    pool: asyncpg.Pool = Depends(get_pool),
    user: UserPrincipal = Depends(require_role("SENIOR_BROKER")),
) -> GenerateLinkResponse:
    """
    Creates a cryptographically unique URL for every document share instance.
    When the prospect opens the URL, FastAPI logs the event and fires a
    real-time WebSocket notification to the broker's Active Notification Center.
    """
    tracking_hash = secrets.token_hex(32)  # 64 character hex string

    async with pool.acquire() as conn:
        row = await conn.fetchrow(
            """
            INSERT INTO velocity_vault_assets
              (asset_name, asset_type, storage_path, tracking_hash, lead_id, created_by)
            VALUES ($1, $2, $3, $4, $5::uuid, $6::uuid)
            RETURNING id::text
            """,
            body.asset_name,
            body.asset_type,
            body.storage_path,
            tracking_hash,
            body.lead_id,
            user.user_id,
        )

    base_url = os.getenv("VELOCITY_API_BASE_URL", "http://localhost:8000")
    vault_url = f"{base_url}/vault/{tracking_hash}"

    return GenerateLinkResponse(
        tracking_hash=tracking_hash,
        vault_url=vault_url,
        asset_id=row["id"],
    )


# ── GET /vault/{tracking_hash} ────────────────────────────────────────────────

@router.get(
    "/{tracking_hash}",
    summary="Public Velocity Link endpoint — accessed by the prospect",
    include_in_schema=False,
)
async def open_vault_link(
    tracking_hash: str,
    request: Request,
    pool: asyncpg.Pool = Depends(get_pool),
) -> RedirectResponse:
    """
    No auth required — this URL is shared with the prospect externally.

    On access:
      1. Appends NOW() to velocity_vault_assets.opened_at
      2. Writes a WS_ASSET_OPENED entry to omnichannel_logs
      3. Broadcasts the event to all connected broker WebSocket clients
      4. Redirects the prospect to the actual asset file
    """
    async with pool.acquire() as conn:
        row = await conn.fetchrow(
            """
            UPDATE velocity_vault_assets
            SET    opened_at = array_append(opened_at, NOW())
            WHERE  tracking_hash = $1
            RETURNING id::text, lead_id::text, asset_name, storage_path
            """,
            tracking_hash,
        )

        if row is None:
            raise HTTPException(status_code=404, detail="Link not found or expired.")

        lead_id = row["lead_id"]
        asset_name = row["asset_name"]

        # Fetch lead name for the notification body
        lead_row = await conn.fetchrow(
            "SELECT name FROM leads_intelligence WHERE id = $1::uuid",
            lead_id,
        )
        lead_name = lead_row["name"] if lead_row else "Unknown Lead"

        # Write to omnichannel_logs
        ip = request.client.host if request.client else None
        await conn.execute(
            """
            INSERT INTO omnichannel_logs (event_type, lead_id, payload)
            VALUES ('WS_ASSET_OPENED', $1::uuid, $2::jsonb)
            """,
            lead_id,
            {
                "tracking_hash": tracking_hash,
                "asset_name": asset_name,
                "ip": ip,
                "user_agent": request.headers.get("user-agent", ""),
            },
        )

    # Fire real-time WebSocket broadcast to all brokers
    await _broadcast_vault_opened(
        request=request,
        lead_id=lead_id,
        lead_name=lead_name,
        asset_name=asset_name,
        tracking_hash=tracking_hash,
        ip=ip,
    )

    # Redirect to the static asset file served by FastAPI
    asset_url = f"/assets/{row['storage_path']}"
    return RedirectResponse(url=asset_url, status_code=302)
