"""
Webhook API Routes

- GET /logs: Get webhook delivery history
- POST /trigger: Manually trigger webhook for a job
"""

from typing import Optional

from app.repositories.job_repository import JobRepository
from app.repositories.webhook_repository import WebhookRepository
from app.api.dependencies.current_user import with_current_user
from app.services.rate_limit.data_structures import CurrentUser
from fastapi import APIRouter, Depends, Query
from loguru import logger
from sqlalchemy.ext.asyncio import AsyncSession

from shared.core.database import get_db
from shared.core.exceptions.domain_exceptions import (
    NotFoundException,
    PermissionDeniedException,
    WebhookServiceException,
)
from shared.core.exceptions.knowhere_exception import KnowhereException
from shared.models.schemas.webhook import (
    WebhookLogList,
    WebhookLogResponse,
    WebhookTriggerRequest,
    WebhookTriggerResponse,
)
from shared.services.webhook import get_webhook_dispatcher

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


@router.get("/logs", response_model=WebhookLogList, summary="Get Webhook Delivery Logs")
async def get_webhook_logs(
    job_id: Optional[str] = Query(None, description="Filter by Job ID"),
    page: int = Query(1, ge=1, description="Page number"),
    page_size: int = Query(20, ge=1, le=100, description="Page size"),
    current_user: CurrentUser = Depends(with_current_user),
    db: AsyncSession = Depends(get_db),
):
    """
    Get webhook delivery history logs.

    Returns a paginated list of webhook delivery attempts, optionally filtered by job_id.
    Each log entry includes the delivery status, duration, and response details.
    """
    try:
        repo = WebhookRepository()
        offset = (page - 1) * page_size
        logs, total = await repo.get_webhook_logs(
            db=db,
            user_id=current_user.user_id,
            job_id=job_id,
            limit=page_size,
            offset=offset,
        )

        return WebhookLogList(
            total=total,
            page=page,
            page_size=page_size,
            logs=[
                WebhookLogResponse(
                    id=log.id,
                    job_id=log.job_id,
                    webhook_url=log.webhook_url,
                    attempt_number=log.attempt_number,
                    request_payload=log.request_payload or {},
                    signature=log.signature,
                    idempotency_key=log.idempotency_key,
                    response_status_code=log.response_status_code,
                    response_body=log.response_body,
                    error_message=log.error_message,
                    duration_ms=log.duration_ms,
                    created_at=log.created_at,
                )
                for log in logs
            ],
        )
    except Exception as e:
        logger.error(f"Failed to get webhook logs: {e}")
        raise WebhookServiceException(
            internal_message=f"Failed to retrieve webhook logs: {str(e)}"
        )


@router.post(
    "/trigger",
    response_model=WebhookTriggerResponse,
    summary="Manually Trigger Webhook",
)
async def trigger_webhook(
    request: WebhookTriggerRequest,
    current_user: CurrentUser = Depends(with_current_user),
    db: AsyncSession = Depends(get_db),
):
    """
    Manually trigger a webhook for a completed or failed job.

    This sends a webhook notification synchronously and returns the delivery result.
    Use this for testing or retrying failed webhook deliveries.
    """
    try:
        job_repo = JobRepository()

        # 1. Fetch Job
        job = await job_repo.get_job_by_id(db, request.job_id)
        if not job:
            raise NotFoundException(resource="Job", resource_id=request.job_id)

        # Verify ownership
        if str(job.user_id) != current_user.user_id:
            raise PermissionDeniedException(
                user_message="You don't have permission to trigger webhook for this job",
                required_permission="job:webhook:trigger",
            )

        # 2. Validation - client errors (400)
        if not job.is_terminal_state():
            from shared.core.exceptions.domain_exceptions import ValidationException

            raise ValidationException(
                user_message=f"Job must be in terminal state to trigger webhook. Current status: {job.status}",
                violations=[
                    {
                        "field": "job_id",
                        "description": f"Job status is '{job.status}', expected 'done' or 'failed'",
                    }
                ],
            )

        if not job.webhook_url:
            from shared.core.exceptions.webhook_exceptions import WebhookConfigException

            raise WebhookConfigException(
                internal_message=f"Job {request.job_id} does not have webhook_url configured",
                user_message="Job does not have a webhook URL configured. Configure webhook_url when creating the job.",
                details={"field": "webhook_url", "reason": "not_configured"},
            )

        # 3. Fetch existing WebhookEvent (Transactional Outbox)
        from sqlalchemy import select

        from shared.models.database.webhook import WebhookEvent

        result = await db.execute(
            select(WebhookEvent).where(WebhookEvent.job_id == request.job_id)
        )
        event = result.scalars().first()

        if not event:
            raise NotFoundException(
                resource="WebhookEvent",
                resource_id=request.job_id,
                internal_message=(
                    "No webhook event found for this job. Ensure the job has "
                    "completed and webhooks are configured."
                ),
            )

        dispatcher = get_webhook_dispatcher()
        delivery_result = await dispatcher.send_manual_webhook(db=db, event=event)

        # 5. Return response
        return WebhookTriggerResponse(
            success=delivery_result.success,
            status_code=delivery_result.status_code,
            response_body=None,  # Dispatcher doesn't return response body
            duration_ms=delivery_result.duration_ms,
            delivery_id=None,  # Manual trigger doesn't create delivery log
            error_message=delivery_result.error_message,
        )

    except KnowhereException:
        # Re-raise all known exceptions (NotFoundException, ValidationException, etc.)
        raise
    except Exception as e:
        raise WebhookServiceException(
            internal_message=f"Failed to trigger webhook: {str(e)}"
        )


# @router.post("/test-callback", summary="Test Webhook Callback Endpoint")
# async def test_webhook_callback(
#     request: Request,
#     payload: dict = Body(...),
# ):
#     """
#     Test endpoint to receive webhook callbacks.

#     Use this endpoint to verify webhook delivery. It logs receiving data
#     to the server console and returns the received payload.
#     """
#     # Log the event
#     logger.info("🔔 [Test Callback] Webhook Received!")
#     logger.info(f"Headers: {dict(request.headers)}")
#     logger.info(f"Payload: {payload}")

#     return {
#         "status": "received",
#         "timestamp": datetime.utcnow().isoformat(),
#         "payload": payload,
#         "received_headers": {k: v for k, v in request.headers.items() if k.lower().startswith("x-") or k.lower() == "user-agent"},
#     }
