"""
Webhook Endpoints

Receives notifications from microservices (chatbot, document, etc.)
and processes them accordingly.
"""
from fastapi import APIRouter, Depends, HTTPException, status, Request, Header
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update
from typing import Optional
from pydantic import BaseModel
from datetime import datetime
from enum import Enum
import hmac
import hashlib
import structlog

from app.database import get_db
from app.models.service_config import ServiceConfig, ServiceType
from app.models.usage import UsageLog
from app.config import settings

logger = structlog.get_logger()
router = APIRouter()


class WebhookEventType(str, Enum):
    """Webhook event types from chatbot service"""
    # Conversation events
    CONVERSATION_STARTED = "conversation.started"
    CONVERSATION_ENDED = "conversation.ended"
    MESSAGE_RECEIVED = "message.received"
    MESSAGE_SENT = "message.sent"

    # Handoff events
    HANDOFF_REQUESTED = "handoff.requested"
    HANDOFF_ASSIGNED = "handoff.assigned"
    HANDOFF_RESOLVED = "handoff.resolved"
    HANDOFF_ABANDONED = "handoff.abandoned"

    # Tool events
    TOOL_EXECUTED = "tool.executed"
    TOOL_FAILED = "tool.failed"

    # Conversion events
    LEAD_CREATED = "conversion.lead_created"
    BOOKING_CREATED = "conversion.booking_created"
    ORDER_CREATED = "conversion.order_created"

    # Alert events
    NEGATIVE_SENTIMENT = "alert.negative_sentiment"
    HIGH_VOLUME = "alert.high_volume"
    SERVICE_ERROR = "alert.service_error"

    # Usage events
    USAGE_THRESHOLD = "usage.threshold_reached"
    USAGE_LIMIT = "usage.limit_reached"


class WebhookPayload(BaseModel):
    """Webhook payload from chatbot service"""
    event: str
    client_id: int
    timestamp: datetime
    data: dict


class ConversationEventData(BaseModel):
    """Data for conversation events"""
    conversation_id: str
    user_id: Optional[str] = None
    channel: str = "web"
    metadata: dict = {}


class HandoffEventData(BaseModel):
    """Data for handoff events"""
    conversation_id: str
    request_id: str
    reason: str
    agent_id: Optional[str] = None


class UsageEventData(BaseModel):
    """Data for usage events"""
    resource_type: str  # messages, api_calls, etc.
    current_usage: int
    limit: int
    percentage: float


# ==================== WEBHOOK RECEIVER ====================

@router.post("/chatbot")
async def receive_chatbot_webhook(
    payload: WebhookPayload,
    request: Request,
    x_webhook_signature: Optional[str] = Header(None),
    db: AsyncSession = Depends(get_db)
):
    """
    Receive webhooks from chatbot service.

    Chatbot service sends events like:
    - conversation.started, conversation.ended
    - handoff.requested, handoff.resolved
    - conversion.lead_created, conversion.booking_created
    - alert.negative_sentiment
    - usage.threshold_reached
    """
    # Verify webhook signature (in production)
    # if not await _verify_webhook_signature(request, x_webhook_signature, payload.client_id, db):
    #     raise HTTPException(status_code=401, detail="Invalid webhook signature")

    logger.info(
        "Webhook received",
        event=payload.event,
        client_id=payload.client_id
    )

    try:
        # Process based on event type
        if payload.event.startswith("conversation."):
            await _handle_conversation_event(payload, db)

        elif payload.event.startswith("handoff."):
            await _handle_handoff_event(payload, db)

        elif payload.event.startswith("conversion."):
            await _handle_conversion_event(payload, db)

        elif payload.event.startswith("alert."):
            await _handle_alert_event(payload, db)

        elif payload.event.startswith("usage."):
            await _handle_usage_event(payload, db)

        elif payload.event.startswith("tool."):
            await _handle_tool_event(payload, db)

        else:
            logger.warning(f"Unknown webhook event: {payload.event}")

        return {"status": "received", "event": payload.event}

    except Exception as e:
        logger.error(f"Webhook processing error: {str(e)}")
        raise HTTPException(status_code=500, detail=str(e))


# ==================== EVENT HANDLERS ====================

async def _handle_conversation_event(payload: WebhookPayload, db: AsyncSession):
    """Handle conversation lifecycle events"""
    event = payload.event
    data = payload.data

    if event == WebhookEventType.CONVERSATION_STARTED:
        # Log new conversation
        usage_log = UsageLog(
            client_id=payload.client_id,
            service_type="chatbot",
            resource_type="conversation",
            quantity=1,
            metadata={
                "conversation_id": data.get("conversation_id"),
                "channel": data.get("channel", "web"),
                "event": "started"
            }
        )
        db.add(usage_log)
        await db.commit()

    elif event == WebhookEventType.CONVERSATION_ENDED:
        # Could update metrics, trigger follow-up, etc.
        pass

    elif event == WebhookEventType.MESSAGE_RECEIVED:
        # Track message usage
        usage_log = UsageLog(
            client_id=payload.client_id,
            service_type="chatbot",
            resource_type="message",
            quantity=1,
            metadata={
                "conversation_id": data.get("conversation_id"),
                "direction": "inbound"
            }
        )
        db.add(usage_log)
        await db.commit()


async def _handle_handoff_event(payload: WebhookPayload, db: AsyncSession):
    """Handle handoff events - could notify admin, update dashboards"""
    event = payload.event
    data = payload.data

    if event == WebhookEventType.HANDOFF_REQUESTED:
        # Could send notification to admins
        logger.info(
            "Handoff requested",
            client_id=payload.client_id,
            conversation_id=data.get("conversation_id"),
            reason=data.get("reason")
        )

        # Could trigger email/SMS notification to client admins
        # await notification_service.send_handoff_alert(payload.client_id, data)

    elif event == WebhookEventType.HANDOFF_ABANDONED:
        # Customer left without being helped - important metric
        logger.warning(
            "Handoff abandoned",
            client_id=payload.client_id,
            conversation_id=data.get("conversation_id")
        )


async def _handle_conversion_event(payload: WebhookPayload, db: AsyncSession):
    """Handle conversion events - leads, bookings, orders"""
    event = payload.event
    data = payload.data

    # Log conversion for analytics
    usage_log = UsageLog(
        client_id=payload.client_id,
        service_type="chatbot",
        resource_type="conversion",
        quantity=1,
        metadata={
            "type": event.split(".")[-1],  # lead_created, booking_created, etc.
            "value": data.get("value", 0),
            "conversation_id": data.get("conversation_id"),
            **data
        }
    )
    db.add(usage_log)
    await db.commit()

    logger.info(
        "Conversion tracked",
        client_id=payload.client_id,
        type=event,
        value=data.get("value", 0)
    )


async def _handle_alert_event(payload: WebhookPayload, db: AsyncSession):
    """Handle alert events - negative sentiment, high volume, errors"""
    event = payload.event
    data = payload.data

    if event == WebhookEventType.NEGATIVE_SENTIMENT:
        # Could trigger immediate notification
        logger.warning(
            "Negative sentiment detected",
            client_id=payload.client_id,
            conversation_id=data.get("conversation_id"),
            score=data.get("sentiment_score")
        )

    elif event == WebhookEventType.SERVICE_ERROR:
        logger.error(
            "Chatbot service error",
            client_id=payload.client_id,
            error=data.get("error")
        )


async def _handle_usage_event(payload: WebhookPayload, db: AsyncSession):
    """Handle usage threshold and limit events"""
    event = payload.event
    data = payload.data

    if event == WebhookEventType.USAGE_THRESHOLD:
        # Usage approaching limit (e.g., 80%)
        logger.warning(
            "Usage threshold reached",
            client_id=payload.client_id,
            resource=data.get("resource_type"),
            percentage=data.get("percentage")
        )

        # Could send email notification to client
        # await notification_service.send_usage_alert(payload.client_id, data)

    elif event == WebhookEventType.USAGE_LIMIT:
        # Usage limit reached
        logger.error(
            "Usage limit reached",
            client_id=payload.client_id,
            resource=data.get("resource_type")
        )

        # Could send urgent notification, potentially pause service
        # await notification_service.send_limit_reached(payload.client_id, data)


async def _handle_tool_event(payload: WebhookPayload, db: AsyncSession):
    """Handle tool execution events"""
    event = payload.event
    data = payload.data

    # Log tool usage
    usage_log = UsageLog(
        client_id=payload.client_id,
        service_type="chatbot",
        resource_type="tool_execution",
        quantity=1,
        metadata={
            "tool": data.get("tool_name"),
            "success": event == WebhookEventType.TOOL_EXECUTED,
            "execution_time_ms": data.get("execution_time_ms"),
            "conversation_id": data.get("conversation_id")
        }
    )
    db.add(usage_log)
    await db.commit()


# ==================== VERIFICATION ====================

async def _verify_webhook_signature(
    request: Request,
    signature: str,
    client_id: int,
    db: AsyncSession
) -> bool:
    """Verify webhook signature using client's webhook secret"""
    if not signature:
        return False

    # Get client's webhook secret
    query = select(ServiceConfig).where(
        ServiceConfig.client_id == client_id,
        ServiceConfig.service_type == ServiceType.CHATBOT
    )
    result = await db.execute(query)
    config = result.scalar_one_or_none()

    if not config or not config.webhook_secret:
        return False

    # Calculate expected signature
    body = await request.body()
    expected = hmac.new(
        config.webhook_secret.encode(),
        body,
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(f"sha256={expected}", signature)


# ==================== INTERNAL WEBHOOKS (Service-to-Service) ====================

@router.post("/internal/chatbot-status")
async def chatbot_service_status(
    request: Request,
    db: AsyncSession = Depends(get_db)
):
    """
    Internal webhook for chatbot service health/status updates.
    Used for monitoring and alerting.
    """
    data = await request.json()

    logger.info(
        "Chatbot service status update",
        status=data.get("status"),
        active_conversations=data.get("active_conversations"),
        memory_usage=data.get("memory_usage")
    )

    return {"received": True}
