"""
Webhook Secrets API Routes

Endpoints for managing user webhook signing secrets.
"""

from typing import List, Optional

from app.api.dependencies.current_user import with_current_user
from app.services.rate_limit.data_structures import CurrentUser
from fastapi import APIRouter, Depends
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession

from shared.core.database import get_db
from shared.core.exceptions.domain_exceptions import NotFoundException
from shared.repositories.webhook_secret_repository import WebhookSecretRepository

router = APIRouter(tags=["Webhook Secrets"])


# --- Request/Response Schemas ---


class SecretCreateRequest(BaseModel):
    """Request to create a new webhook secret."""

    endpoint: Optional[str] = Field(
        None,
        description="Optional endpoint URL. If omitted, creates a default account secret.",
    )


class SecretResponse(BaseModel):
    """Webhook secret response (masked)."""

    id: str = Field(..., description="Secret ID (ws_...)")
    endpoint: Optional[str] = Field(
        None, description="Endpoint URL or null for default"
    )
    secret_masked: str = Field(..., description="Masked secret (whsec_****...)")
    status: str = Field(..., description="'active' or 'revoked'")
    created_at: str = Field(..., description="Creation timestamp (ISO 8601)")


class SecretFullResponse(SecretResponse):
    """Webhook secret response with full value (creation only)."""

    secret: str = Field(..., description="Secret value")


class SecretListResponse(BaseModel):
    """List of webhook secrets."""

    secrets: List[SecretResponse]
    total: int


# --- Helper Functions ---


def mask_secret(secret: str) -> str:
    """Mask a secret, showing only prefix and last 4 chars."""
    if len(secret) <= 12:
        return secret[:6] + "****"
    return secret[:6] + "****" + secret[-4:]


def to_response(secret) -> SecretResponse:
    """Convert WebhookSecret to masked response model."""
    # For masked display, we rely on the ID if raw is not available to verify
    raw_secret = getattr(secret, "_raw_secret", None)
    masked = mask_secret(raw_secret) if raw_secret else f"whsec_****...{secret.id[-4:]}"

    return SecretResponse(
        id=secret.id,
        endpoint=secret.endpoint,
        secret_masked=masked,
        status=secret.status,
        created_at=secret.created_at.isoformat(),
    )


def to_full_response(secret) -> SecretFullResponse:
    """Convert WebhookSecret to full response model (creation only)."""
    raw_secret = getattr(secret, "_raw_secret", None)
    if not raw_secret:
        # Should not happen during creation, but as safeguard
        raise ValueError("Cannot create full response without raw secret")

    masked = mask_secret(raw_secret)

    return SecretFullResponse(
        id=secret.id,
        endpoint=secret.endpoint,
        secret=raw_secret,
        secret_masked=masked,
        status=secret.status,
        created_at=secret.created_at.isoformat(),
    )


# --- API Endpoints ---


@router.get("", response_model=SecretListResponse, summary="List Webhook Secrets")
async def list_secrets(
    current_user: CurrentUser = Depends(with_current_user),
    db: AsyncSession = Depends(get_db),
):
    """
    List all webhook secrets for the current user.

    Returns masked secrets by default. Use POST to create new secrets
    and see the full value (one-time display).
    """
    repo = WebhookSecretRepository()
    secrets = await repo.list_secrets(db, current_user.user_id)

    return SecretListResponse(
        secrets=[to_response(s) for s in secrets],
        total=len(secrets),
    )


@router.post(
    "",
    response_model=SecretResponse | SecretFullResponse,
    summary="Create Webhook Secret",
)
async def create_secret(
    request: SecretCreateRequest,
    current_user: CurrentUser = Depends(with_current_user),
    db: AsyncSession = Depends(get_db),
):
    """
    Create a new webhook secret.

    If no endpoint is specified, creates a default account-level secret.
    The full secret value is returned ONLY in this response (one-time display).
    """
    repo = WebhookSecretRepository()

    # Check if secret already exists for this endpoint
    existing = await repo.get_active_secret(db, current_user.user_id, request.endpoint)
    if existing:
        # Return existing secret (masked, because we can't decrypt for display)
        # Type verification: This returns SecretResponse, which is valid for the union return type
        return to_response(existing)

    # Create new secret
    secret = await repo.create_secret(db, current_user.user_id, request.endpoint)

    # Return with raw secret visible (one-time)
    return to_full_response(secret)


@router.delete("/{secret_id}", summary="Revoke Webhook Secret")
async def revoke_secret(
    secret_id: str,
    current_user: CurrentUser = Depends(with_current_user),
    db: AsyncSession = Depends(get_db),
):
    """
    Revoke a webhook secret immediately.

    Revoked secrets cannot be used for signing. This action is irreversible.
    """
    repo = WebhookSecretRepository()

    success = await repo.revoke_secret(db, secret_id, current_user.user_id)

    if not success:
        raise NotFoundException(
            resource="WebhookSecret",
            resource_id=secret_id,
        )

    return {"status": "revoked", "id": secret_id}
