"""
Bulk Operations API Routes
Handles batch operations for efficiency
"""
from typing import List, Optional, Dict, Any
from datetime import datetime
from fastapi import APIRouter, Depends, HTTPException, status, BackgroundTasks
from pydantic import BaseModel, validator
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, update, delete, and_

from app.database import get_db
from app.auth.jwt_handler import get_current_user
from app.models.user import User
from app.models.conversation import Conversation, Message, ConversationStatus
from app.models.webhook import ClientWebhook
from app.services.webhook_service import webhook_service

router = APIRouter()


# ============== Schemas ==============

class BulkOperationResult(BaseModel):
    total: int
    successful: int
    failed: int
    errors: List[Dict[str, Any]]


class BulkDeleteRequest(BaseModel):
    ids: List[int]

    @validator('ids')
    def validate_ids(cls, v):
        if not v:
            raise ValueError('At least one ID is required')
        if len(v) > 100:
            raise ValueError('Maximum 100 items per bulk operation')
        return v


class BulkUpdateRequest(BaseModel):
    ids: List[int]
    updates: Dict[str, Any]

    @validator('ids')
    def validate_ids(cls, v):
        if not v:
            raise ValueError('At least one ID is required')
        if len(v) > 100:
            raise ValueError('Maximum 100 items per bulk operation')
        return v


class BulkConversationStatusUpdate(BaseModel):
    ids: List[int]
    status: str

    @validator('status')
    def validate_status(cls, v):
        valid_statuses = ['active', 'closed', 'archived']
        if v not in valid_statuses:
            raise ValueError(f'Invalid status. Must be one of: {valid_statuses}')
        return v


class BulkWebhookToggle(BaseModel):
    ids: List[int]
    is_active: bool


class BulkMessageDelete(BaseModel):
    conversation_ids: List[int]
    before_date: Optional[datetime] = None

    @validator('conversation_ids')
    def validate_ids(cls, v):
        if not v:
            raise ValueError('At least one conversation ID is required')
        if len(v) > 50:
            raise ValueError('Maximum 50 conversations per bulk operation')
        return v


class BulkCreateWebhook(BaseModel):
    webhooks: List[Dict[str, Any]]

    @validator('webhooks')
    def validate_webhooks(cls, v):
        if not v:
            raise ValueError('At least one webhook is required')
        if len(v) > 10:
            raise ValueError('Maximum 10 webhooks per bulk operation')
        for wh in v:
            if 'name' not in wh or 'url' not in wh or 'events' not in wh:
                raise ValueError('Each webhook must have name, url, and events')
        return v


# ============== Bulk Conversation Operations ==============

@router.post("/conversations/status", response_model=BulkOperationResult)
async def bulk_update_conversation_status(
    request: BulkConversationStatusUpdate,
    background_tasks: BackgroundTasks,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    Bulk update conversation statuses
    """
    if not current_user.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User must be associated with a client"
        )

    result = BulkOperationResult(total=len(request.ids), successful=0, failed=0, errors=[])

    # Get conversations belonging to client
    query = select(Conversation).where(
        Conversation.id.in_(request.ids),
        Conversation.client_id == current_user.client_id
    )
    db_result = await db.execute(query)
    conversations = {c.id: c for c in db_result.scalars().all()}

    for conv_id in request.ids:
        if conv_id not in conversations:
            result.failed += 1
            result.errors.append({
                "id": conv_id,
                "error": "Conversation not found or access denied"
            })
            continue

        try:
            conv = conversations[conv_id]
            conv.status = ConversationStatus(request.status)
            if request.status == 'closed':
                conv.ended_at = datetime.utcnow()
            result.successful += 1
        except Exception as e:
            result.failed += 1
            result.errors.append({
                "id": conv_id,
                "error": str(e)
            })

    await db.commit()

    # Trigger webhooks for bulk status change
    background_tasks.add_task(
        trigger_bulk_webhook,
        db,
        current_user.client_id,
        "conversation.bulk_updated",
        {"ids": [c for c in request.ids if c in conversations], "status": request.status}
    )

    return result


@router.post("/conversations/delete", response_model=BulkOperationResult)
async def bulk_delete_conversations(
    request: BulkDeleteRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    Bulk delete conversations (marks as archived and closed)
    """
    if not current_user.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User must be associated with a client"
        )

    result = BulkOperationResult(total=len(request.ids), successful=0, failed=0, errors=[])

    query = select(Conversation).where(
        Conversation.id.in_(request.ids),
        Conversation.client_id == current_user.client_id
    )
    db_result = await db.execute(query)
    conversations = {c.id: c for c in db_result.scalars().all()}

    for conv_id in request.ids:
        if conv_id not in conversations:
            result.failed += 1
            result.errors.append({
                "id": conv_id,
                "error": "Conversation not found or access denied"
            })
            continue

        try:
            conv = conversations[conv_id]
            # Mark as archived since Conversation doesn't have soft delete
            conv.status = ConversationStatus.ARCHIVED
            conv.ended_at = datetime.utcnow()
            result.successful += 1
        except Exception as e:
            result.failed += 1
            result.errors.append({
                "id": conv_id,
                "error": str(e)
            })

    await db.commit()
    return result


@router.post("/conversations/archive", response_model=BulkOperationResult)
async def bulk_archive_conversations(
    request: BulkDeleteRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    Bulk archive conversations
    """
    if not current_user.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User must be associated with a client"
        )

    result = BulkOperationResult(total=len(request.ids), successful=0, failed=0, errors=[])

    query = select(Conversation).where(
        Conversation.id.in_(request.ids),
        Conversation.client_id == current_user.client_id
    )
    db_result = await db.execute(query)
    conversations = {c.id: c for c in db_result.scalars().all()}

    for conv_id in request.ids:
        if conv_id not in conversations:
            result.failed += 1
            result.errors.append({
                "id": conv_id,
                "error": "Conversation not found or access denied"
            })
            continue

        try:
            conv = conversations[conv_id]
            conv.status = ConversationStatus.ARCHIVED
            result.successful += 1
        except Exception as e:
            result.failed += 1
            result.errors.append({
                "id": conv_id,
                "error": str(e)
            })

    await db.commit()
    return result


# ============== Bulk Message Operations ==============

@router.post("/messages/delete", response_model=BulkOperationResult)
async def bulk_delete_messages(
    request: BulkMessageDelete,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    Bulk delete messages from conversations
    Optionally filter by date
    """
    if not current_user.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User must be associated with a client"
        )

    result = BulkOperationResult(total=0, successful=0, failed=0, errors=[])

    # Verify conversations belong to client
    conv_query = select(Conversation).where(
        Conversation.id.in_(request.conversation_ids),
        Conversation.client_id == current_user.client_id
    )
    conv_result = await db.execute(conv_query)
    valid_conv_ids = [c.id for c in conv_result.scalars().all()]

    invalid_ids = set(request.conversation_ids) - set(valid_conv_ids)
    for inv_id in invalid_ids:
        result.errors.append({
            "conversation_id": inv_id,
            "error": "Conversation not found or access denied"
        })

    if not valid_conv_ids:
        result.failed = len(request.conversation_ids)
        return result

    # Build message delete query
    msg_query = select(Message).where(Message.conversation_id.in_(valid_conv_ids))
    if request.before_date:
        msg_query = msg_query.where(Message.created_at < request.before_date)

    msg_result = await db.execute(msg_query)
    messages = msg_result.scalars().all()
    result.total = len(messages)

    for msg in messages:
        try:
            await db.delete(msg)
            result.successful += 1
        except Exception as e:
            result.failed += 1
            result.errors.append({
                "message_id": msg.id,
                "error": str(e)
            })

    # Update message counts
    for conv_id in valid_conv_ids:
        count_query = select(Message).where(Message.conversation_id == conv_id)
        count_result = await db.execute(count_query)
        new_count = len(count_result.scalars().all())

        update_query = select(Conversation).where(Conversation.id == conv_id)
        conv_to_update = (await db.execute(update_query)).scalar_one_or_none()
        if conv_to_update:
            conv_to_update.message_count = new_count

    await db.commit()
    return result


# ============== Bulk Webhook Operations ==============

@router.post("/webhooks/toggle", response_model=BulkOperationResult)
async def bulk_toggle_webhooks(
    request: BulkWebhookToggle,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    Bulk enable/disable webhooks
    """
    if not current_user.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User must be associated with a client"
        )

    result = BulkOperationResult(total=len(request.ids), successful=0, failed=0, errors=[])

    query = select(ClientWebhook).where(
        ClientWebhook.id.in_(request.ids),
        ClientWebhook.client_id == current_user.client_id,
        ClientWebhook.deleted_at.is_(None)
    )
    db_result = await db.execute(query)
    webhooks = {w.id: w for w in db_result.scalars().all()}

    for wh_id in request.ids:
        if wh_id not in webhooks:
            result.failed += 1
            result.errors.append({
                "id": wh_id,
                "error": "Webhook not found or access denied"
            })
            continue

        try:
            webhooks[wh_id].is_active = request.is_active
            result.successful += 1
        except Exception as e:
            result.failed += 1
            result.errors.append({
                "id": wh_id,
                "error": str(e)
            })

    await db.commit()
    return result


@router.post("/webhooks/delete", response_model=BulkOperationResult)
async def bulk_delete_webhooks(
    request: BulkDeleteRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    Bulk delete webhooks (soft delete)
    """
    if not current_user.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User must be associated with a client"
        )

    result = BulkOperationResult(total=len(request.ids), successful=0, failed=0, errors=[])

    query = select(ClientWebhook).where(
        ClientWebhook.id.in_(request.ids),
        ClientWebhook.client_id == current_user.client_id,
        ClientWebhook.deleted_at.is_(None)
    )
    db_result = await db.execute(query)
    webhooks = {w.id: w for w in db_result.scalars().all()}

    for wh_id in request.ids:
        if wh_id not in webhooks:
            result.failed += 1
            result.errors.append({
                "id": wh_id,
                "error": "Webhook not found or access denied"
            })
            continue

        try:
            webhooks[wh_id].deleted_at = datetime.utcnow()
            result.successful += 1
        except Exception as e:
            result.failed += 1
            result.errors.append({
                "id": wh_id,
                "error": str(e)
            })

    await db.commit()
    return result


@router.post("/webhooks/create", response_model=BulkOperationResult)
async def bulk_create_webhooks(
    request: BulkCreateWebhook,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    Bulk create webhooks
    """
    if not current_user.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User must be associated with a client"
        )

    result = BulkOperationResult(total=len(request.webhooks), successful=0, failed=0, errors=[])

    for idx, wh_data in enumerate(request.webhooks):
        try:
            webhook = await webhook_service.create_webhook(
                db=db,
                client_id=current_user.client_id,
                name=wh_data['name'],
                url=wh_data['url'],
                events=wh_data['events'],
                description=wh_data.get('description'),
                custom_headers=wh_data.get('custom_headers'),
                max_retries=wh_data.get('max_retries', 3),
                timeout_seconds=wh_data.get('timeout_seconds', 30)
            )
            result.successful += 1
        except Exception as e:
            result.failed += 1
            result.errors.append({
                "index": idx,
                "name": wh_data.get('name'),
                "error": str(e)
            })

    return result


# ============== Bulk Test Webhooks ==============

@router.post("/webhooks/test", response_model=List[Dict[str, Any]])
async def bulk_test_webhooks(
    request: BulkDeleteRequest,
    db: AsyncSession = Depends(get_db),
    current_user: User = Depends(get_current_user)
):
    """
    Bulk test webhooks
    Returns test results for each webhook
    """
    if not current_user.client_id:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User must be associated with a client"
        )

    results = []

    for wh_id in request.ids:
        test_result = await webhook_service.test_webhook(
            db=db,
            webhook_id=wh_id,
            client_id=current_user.client_id
        )
        test_result['webhook_id'] = wh_id
        results.append(test_result)

    return results


# ============== Helper Functions ==============

async def trigger_bulk_webhook(
    db: AsyncSession,
    client_id: int,
    event_type: str,
    data: Dict[str, Any]
):
    """Helper to trigger webhooks for bulk operations"""
    try:
        await webhook_service.trigger_event(db, client_id, event_type, data)
    except Exception as e:
        # Log but don't fail the operation
        import logging
        logging.error(f"Failed to trigger webhook for bulk operation: {e}")
