"""
Client Portal API Routes
Knowledge Base, Training Data, Webhooks, Team Management, White-label Settings
"""
from fastapi import APIRouter, HTTPException, Depends, Query, UploadFile, File, Form, BackgroundTasks
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, or_, func, desc
from typing import Optional, List, Dict, Any
from datetime import datetime, timedelta
from pydantic import BaseModel, Field, EmailStr
import secrets
import json
import hashlib
import logging

from app.database import get_db
from app.models.knowledge_base import (
    KnowledgeBaseCategory, KnowledgeBaseArticle, FAQ,
    TrainingData, TrainingJob, ArticleStatus, DataSourceType
)
from app.models.client_settings import (
    ClientWhiteLabelSettings, ClientChatbotSettings, TeamInvitation
)
from app.models.user import User, UserRole
from app.models.webhook import ClientWebhook, WebhookEventType
from app.services.email_service import email_service

logger = logging.getLogger(__name__)
router = APIRouter()


# ============================================================
# SCHEMAS
# ============================================================

# Knowledge Base Categories
class CategoryCreate(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    description: Optional[str] = None
    icon: Optional[str] = None
    color: Optional[str] = None
    parent_id: Optional[int] = None
    display_order: int = 0
    is_visible: bool = True


class CategoryUpdate(BaseModel):
    name: Optional[str] = Field(None, max_length=100)
    description: Optional[str] = None
    icon: Optional[str] = None
    color: Optional[str] = None
    parent_id: Optional[int] = None
    display_order: Optional[int] = None
    is_visible: Optional[bool] = None


class CategoryResponse(BaseModel):
    id: int
    name: str
    slug: str
    description: Optional[str]
    icon: Optional[str]
    color: Optional[str]
    parent_id: Optional[int]
    display_order: int
    is_visible: bool
    article_count: int = 0
    faq_count: int = 0

    class Config:
        from_attributes = True


# FAQ
class FAQCreate(BaseModel):
    question: str = Field(..., min_length=1)
    answer: str = Field(..., min_length=1)
    answer_format: str = "text"
    category_id: Optional[int] = None
    question_variations: Optional[List[str]] = None
    display_order: int = 0
    is_featured: bool = False
    is_visible: bool = True
    include_in_training: bool = True
    confidence_threshold: float = 0.7


class FAQUpdate(BaseModel):
    question: Optional[str] = None
    answer: Optional[str] = None
    answer_format: Optional[str] = None
    category_id: Optional[int] = None
    question_variations: Optional[List[str]] = None
    display_order: Optional[int] = None
    is_featured: Optional[bool] = None
    is_visible: Optional[bool] = None
    status: Optional[str] = None
    include_in_training: Optional[bool] = None
    confidence_threshold: Optional[float] = None


class FAQResponse(BaseModel):
    id: int
    question: str
    answer: str
    answer_format: str
    category_id: Optional[int]
    category_name: Optional[str] = None
    question_variations: Optional[List[str]]
    display_order: int
    is_featured: bool
    is_visible: bool
    status: str
    view_count: int
    helpful_count: int
    not_helpful_count: int
    times_asked: int
    include_in_training: bool
    created_at: datetime

    class Config:
        from_attributes = True


# Articles
class ArticleCreate(BaseModel):
    title: str = Field(..., min_length=1, max_length=255)
    content: str = Field(..., min_length=1)
    content_format: str = "markdown"
    summary: Optional[str] = None
    category_id: Optional[int] = None
    meta_title: Optional[str] = None
    meta_description: Optional[str] = None
    keywords: Optional[str] = None
    featured_image: Optional[str] = None
    status: str = "draft"
    include_in_training: bool = True


class ArticleUpdate(BaseModel):
    title: Optional[str] = Field(None, max_length=255)
    content: Optional[str] = None
    content_format: Optional[str] = None
    summary: Optional[str] = None
    category_id: Optional[int] = None
    meta_title: Optional[str] = None
    meta_description: Optional[str] = None
    keywords: Optional[str] = None
    featured_image: Optional[str] = None
    status: Optional[str] = None
    include_in_training: Optional[bool] = None


class ArticleResponse(BaseModel):
    id: int
    title: str
    slug: str
    content: str
    content_format: str
    summary: Optional[str]
    category_id: Optional[int]
    category_name: Optional[str] = None
    meta_title: Optional[str]
    meta_description: Optional[str]
    keywords: Optional[str]
    featured_image: Optional[str]
    status: str
    published_at: Optional[datetime]
    view_count: int
    helpful_count: int
    include_in_training: bool
    created_at: datetime

    class Config:
        from_attributes = True


# Training Data
class TrainingDataResponse(BaseModel):
    id: int
    source_type: str
    source_name: str
    source_url: Optional[str]
    file_size: Optional[int]
    file_type: Optional[str]
    is_processed: bool
    is_trained: bool
    embedding_count: int
    created_at: datetime


# White-label Settings
class WhiteLabelSettingsUpdate(BaseModel):
    logo_url: Optional[str] = None
    logo_dark_url: Optional[str] = None
    favicon_url: Optional[str] = None
    primary_color: Optional[str] = None
    secondary_color: Optional[str] = None
    accent_color: Optional[str] = None
    background_color: Optional[str] = None
    text_color: Optional[str] = None
    widget_position: Optional[str] = None
    widget_button_color: Optional[str] = None
    widget_header_color: Optional[str] = None
    widget_border_radius: Optional[int] = None
    widget_shadow: Optional[bool] = None
    widget_title: Optional[str] = None
    widget_subtitle: Optional[str] = None
    widget_welcome_message: Optional[str] = None
    widget_placeholder_text: Optional[str] = None
    widget_offline_message: Optional[str] = None
    custom_domain: Optional[str] = None
    email_from_name: Optional[str] = None
    email_reply_to: Optional[str] = None
    email_footer_text: Optional[str] = None
    social_links: Optional[Dict[str, str]] = None
    privacy_policy_url: Optional[str] = None
    terms_of_service_url: Optional[str] = None
    custom_css: Optional[str] = None
    show_powered_by: Optional[bool] = None
    enable_file_upload: Optional[bool] = None
    enable_voice_input: Optional[bool] = None
    enable_emoji: Optional[bool] = None


# Chatbot Settings
class ChatbotSettingsUpdate(BaseModel):
    ai_model: Optional[str] = None
    temperature: Optional[int] = None
    max_tokens: Optional[int] = None
    context_window: Optional[int] = None
    bot_name: Optional[str] = None
    bot_avatar_url: Optional[str] = None
    system_prompt: Optional[str] = None
    tone: Optional[str] = None
    fallback_message: Optional[str] = None
    handoff_enabled: Optional[bool] = None
    handoff_trigger_keywords: Optional[List[str]] = None
    handoff_message: Optional[str] = None
    business_hours_enabled: Optional[bool] = None
    business_hours: Optional[Dict] = None
    timezone: Optional[str] = None
    outside_hours_message: Optional[str] = None
    greeting_message: Optional[str] = None
    goodbye_message: Optional[str] = None
    typing_indicator_delay: Optional[int] = None
    collect_email: Optional[bool] = None
    collect_phone: Optional[bool] = None
    collect_name: Optional[bool] = None
    lead_form_position: Optional[str] = None
    default_language: Optional[str] = None
    supported_languages: Optional[List[str]] = None
    auto_detect_language: Optional[bool] = None
    use_knowledge_base: Optional[bool] = None
    kb_confidence_threshold: Optional[int] = None
    kb_fallback_to_ai: Optional[bool] = None
    messages_per_minute: Optional[int] = None
    messages_per_day: Optional[int] = None


# Team Management
class TeamInviteRequest(BaseModel):
    email: EmailStr
    role: str = "client_user"


class TeamMemberUpdate(BaseModel):
    role: Optional[str] = None
    is_active: Optional[bool] = None


# Webhook
class WebhookCreate(BaseModel):
    name: str = Field(..., min_length=1, max_length=100)
    url: str = Field(..., min_length=1)
    events: List[str]
    is_active: bool = True
    headers: Optional[Dict[str, str]] = None


class WebhookUpdate(BaseModel):
    name: Optional[str] = None
    url: Optional[str] = None
    events: Optional[List[str]] = None
    is_active: Optional[bool] = None
    headers: Optional[Dict[str, str]] = None


# ============================================================
# HELPER FUNCTIONS
# ============================================================

def generate_slug(text: str) -> str:
    """Generate URL-friendly slug"""
    import re
    slug = text.lower()
    slug = re.sub(r'[^a-z0-9\s-]', '', slug)
    slug = re.sub(r'[\s_]+', '-', slug)
    slug = re.sub(r'-+', '-', slug)
    return slug.strip('-')


# ============================================================
# KNOWLEDGE BASE - CATEGORIES
# ============================================================

@router.get("/knowledge-base/categories")
async def list_categories(
    client_id: int,
    include_counts: bool = Query(True),
    db: AsyncSession = Depends(get_db)
):
    """List all knowledge base categories for a client"""
    result = await db.execute(
        select(KnowledgeBaseCategory)
        .where(and_(
            KnowledgeBaseCategory.client_id == client_id,
            KnowledgeBaseCategory.deleted_at.is_(None)
        ))
        .order_by(KnowledgeBaseCategory.display_order)
    )
    categories = result.scalars().all()

    response = []
    for cat in categories:
        cat_data = {
            "id": cat.id,
            "name": cat.name,
            "slug": cat.slug,
            "description": cat.description,
            "icon": cat.icon,
            "color": cat.color,
            "parent_id": cat.parent_id,
            "display_order": cat.display_order,
            "is_visible": cat.is_visible,
            "article_count": 0,
            "faq_count": 0
        }

        if include_counts:
            # Get counts
            article_count = await db.execute(
                select(func.count(KnowledgeBaseArticle.id))
                .where(and_(
                    KnowledgeBaseArticle.category_id == cat.id,
                    KnowledgeBaseArticle.deleted_at.is_(None)
                ))
            )
            faq_count = await db.execute(
                select(func.count(FAQ.id))
                .where(and_(
                    FAQ.category_id == cat.id,
                    FAQ.deleted_at.is_(None)
                ))
            )
            cat_data["article_count"] = article_count.scalar()
            cat_data["faq_count"] = faq_count.scalar()

        response.append(cat_data)

    return {"categories": response}


@router.post("/knowledge-base/categories", status_code=201)
async def create_category(
    client_id: int,
    request: CategoryCreate,
    db: AsyncSession = Depends(get_db)
):
    """Create a new category"""
    category = KnowledgeBaseCategory(
        client_id=client_id,
        name=request.name,
        slug=generate_slug(request.name),
        description=request.description,
        icon=request.icon,
        color=request.color,
        parent_id=request.parent_id,
        display_order=request.display_order,
        is_visible=request.is_visible
    )

    db.add(category)
    await db.commit()
    await db.refresh(category)

    return CategoryResponse(
        id=category.id,
        name=category.name,
        slug=category.slug,
        description=category.description,
        icon=category.icon,
        color=category.color,
        parent_id=category.parent_id,
        display_order=category.display_order,
        is_visible=category.is_visible
    )


@router.put("/knowledge-base/categories/{category_id}")
async def update_category(
    category_id: int,
    request: CategoryUpdate,
    db: AsyncSession = Depends(get_db)
):
    """Update a category"""
    result = await db.execute(
        select(KnowledgeBaseCategory).where(KnowledgeBaseCategory.id == category_id)
    )
    category = result.scalar_one_or_none()

    if not category:
        raise HTTPException(status_code=404, detail="Category not found")

    update_data = request.model_dump(exclude_unset=True)

    if "name" in update_data:
        update_data["slug"] = generate_slug(update_data["name"])

    for field, value in update_data.items():
        setattr(category, field, value)

    category.updated_at = datetime.utcnow()
    await db.commit()
    await db.refresh(category)

    return {"success": True, "category": CategoryResponse.model_validate(category)}


@router.delete("/knowledge-base/categories/{category_id}")
async def delete_category(
    category_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Delete a category (soft delete)"""
    result = await db.execute(
        select(KnowledgeBaseCategory).where(KnowledgeBaseCategory.id == category_id)
    )
    category = result.scalar_one_or_none()

    if not category:
        raise HTTPException(status_code=404, detail="Category not found")

    category.deleted_at = datetime.utcnow()
    await db.commit()

    return {"success": True, "message": "Category deleted"}


# ============================================================
# KNOWLEDGE BASE - FAQs
# ============================================================

@router.get("/knowledge-base/faqs")
async def list_faqs(
    client_id: int,
    category_id: Optional[int] = Query(None),
    status: Optional[str] = Query(None),
    search: Optional[str] = Query(None),
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    db: AsyncSession = Depends(get_db)
):
    """List FAQs with filtering"""
    conditions = [
        FAQ.client_id == client_id,
        FAQ.deleted_at.is_(None)
    ]

    if category_id:
        conditions.append(FAQ.category_id == category_id)
    if status:
        conditions.append(FAQ.status == ArticleStatus(status))
    if search:
        conditions.append(or_(
            FAQ.question.ilike(f"%{search}%"),
            FAQ.answer.ilike(f"%{search}%")
        ))

    # Count
    count_result = await db.execute(
        select(func.count(FAQ.id)).where(and_(*conditions))
    )
    total = count_result.scalar()

    # Get FAQs
    result = await db.execute(
        select(FAQ)
        .where(and_(*conditions))
        .order_by(FAQ.display_order, FAQ.created_at.desc())
        .offset((page - 1) * page_size)
        .limit(page_size)
    )
    faqs = result.scalars().all()

    # Get category names
    category_ids = [f.category_id for f in faqs if f.category_id]
    category_names = {}
    if category_ids:
        cat_result = await db.execute(
            select(KnowledgeBaseCategory.id, KnowledgeBaseCategory.name)
            .where(KnowledgeBaseCategory.id.in_(category_ids))
        )
        category_names = {row[0]: row[1] for row in cat_result.fetchall()}

    return {
        "faqs": [
            FAQResponse(
                id=f.id,
                question=f.question,
                answer=f.answer,
                answer_format=f.answer_format,
                category_id=f.category_id,
                category_name=category_names.get(f.category_id),
                question_variations=json.loads(f.question_variations) if f.question_variations else None,
                display_order=f.display_order,
                is_featured=f.is_featured,
                is_visible=f.is_visible,
                status=f.status.value,
                view_count=f.view_count,
                helpful_count=f.helpful_count,
                not_helpful_count=f.not_helpful_count,
                times_asked=f.times_asked,
                include_in_training=f.include_in_training,
                created_at=f.created_at
            )
            for f in faqs
        ],
        "total": total,
        "page": page,
        "page_size": page_size
    }


@router.post("/knowledge-base/faqs", status_code=201)
async def create_faq(
    client_id: int,
    request: FAQCreate,
    db: AsyncSession = Depends(get_db)
):
    """Create a new FAQ"""
    faq = FAQ(
        client_id=client_id,
        question=request.question,
        answer=request.answer,
        answer_format=request.answer_format,
        category_id=request.category_id,
        question_variations=json.dumps(request.question_variations) if request.question_variations else None,
        display_order=request.display_order,
        is_featured=request.is_featured,
        is_visible=request.is_visible,
        include_in_training=request.include_in_training,
        confidence_threshold=request.confidence_threshold,
        status=ArticleStatus.PUBLISHED
    )

    db.add(faq)
    await db.commit()
    await db.refresh(faq)

    return {
        "success": True,
        "faq": FAQResponse(
            id=faq.id,
            question=faq.question,
            answer=faq.answer,
            answer_format=faq.answer_format,
            category_id=faq.category_id,
            question_variations=request.question_variations,
            display_order=faq.display_order,
            is_featured=faq.is_featured,
            is_visible=faq.is_visible,
            status=faq.status.value,
            view_count=0,
            helpful_count=0,
            not_helpful_count=0,
            times_asked=0,
            include_in_training=faq.include_in_training,
            created_at=faq.created_at
        )
    }


@router.get("/knowledge-base/faqs/{faq_id}")
async def get_faq(
    faq_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Get FAQ by ID"""
    result = await db.execute(
        select(FAQ).where(and_(FAQ.id == faq_id, FAQ.deleted_at.is_(None)))
    )
    faq = result.scalar_one_or_none()

    if not faq:
        raise HTTPException(status_code=404, detail="FAQ not found")

    return FAQResponse(
        id=faq.id,
        question=faq.question,
        answer=faq.answer,
        answer_format=faq.answer_format,
        category_id=faq.category_id,
        question_variations=json.loads(faq.question_variations) if faq.question_variations else None,
        display_order=faq.display_order,
        is_featured=faq.is_featured,
        is_visible=faq.is_visible,
        status=faq.status.value,
        view_count=faq.view_count,
        helpful_count=faq.helpful_count,
        not_helpful_count=faq.not_helpful_count,
        times_asked=faq.times_asked,
        include_in_training=faq.include_in_training,
        created_at=faq.created_at
    )


@router.put("/knowledge-base/faqs/{faq_id}")
async def update_faq(
    faq_id: int,
    request: FAQUpdate,
    db: AsyncSession = Depends(get_db)
):
    """Update FAQ"""
    result = await db.execute(
        select(FAQ).where(FAQ.id == faq_id)
    )
    faq = result.scalar_one_or_none()

    if not faq:
        raise HTTPException(status_code=404, detail="FAQ not found")

    update_data = request.model_dump(exclude_unset=True)

    if "question_variations" in update_data:
        update_data["question_variations"] = json.dumps(update_data["question_variations"])

    if "status" in update_data:
        update_data["status"] = ArticleStatus(update_data["status"])

    for field, value in update_data.items():
        setattr(faq, field, value)

    faq.updated_at = datetime.utcnow()
    await db.commit()

    return {"success": True, "message": "FAQ updated"}


@router.delete("/knowledge-base/faqs/{faq_id}")
async def delete_faq(
    faq_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Delete FAQ"""
    result = await db.execute(
        select(FAQ).where(FAQ.id == faq_id)
    )
    faq = result.scalar_one_or_none()

    if not faq:
        raise HTTPException(status_code=404, detail="FAQ not found")

    faq.deleted_at = datetime.utcnow()
    await db.commit()

    return {"success": True, "message": "FAQ deleted"}


@router.post("/knowledge-base/faqs/bulk-import")
async def bulk_import_faqs(
    client_id: int,
    faqs: List[FAQCreate],
    db: AsyncSession = Depends(get_db)
):
    """Import multiple FAQs at once"""
    if len(faqs) > 100:
        raise HTTPException(status_code=400, detail="Maximum 100 FAQs per import")

    created = 0
    errors = []

    for idx, faq_data in enumerate(faqs):
        try:
            faq = FAQ(
                client_id=client_id,
                question=faq_data.question,
                answer=faq_data.answer,
                answer_format=faq_data.answer_format,
                category_id=faq_data.category_id,
                question_variations=json.dumps(faq_data.question_variations) if faq_data.question_variations else None,
                display_order=faq_data.display_order,
                is_featured=faq_data.is_featured,
                is_visible=faq_data.is_visible,
                include_in_training=faq_data.include_in_training,
                status=ArticleStatus.PUBLISHED
            )
            db.add(faq)
            created += 1
        except Exception as e:
            errors.append({"index": idx, "error": str(e)})

    await db.commit()

    return {
        "created": created,
        "errors": errors
    }


# ============================================================
# KNOWLEDGE BASE - ARTICLES
# ============================================================

@router.get("/knowledge-base/articles")
async def list_articles(
    client_id: int,
    category_id: Optional[int] = Query(None),
    status: Optional[str] = Query(None),
    search: Optional[str] = Query(None),
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    db: AsyncSession = Depends(get_db)
):
    """List articles with filtering"""
    conditions = [
        KnowledgeBaseArticle.client_id == client_id,
        KnowledgeBaseArticle.deleted_at.is_(None)
    ]

    if category_id:
        conditions.append(KnowledgeBaseArticle.category_id == category_id)
    if status:
        conditions.append(KnowledgeBaseArticle.status == ArticleStatus(status))
    if search:
        conditions.append(or_(
            KnowledgeBaseArticle.title.ilike(f"%{search}%"),
            KnowledgeBaseArticle.content.ilike(f"%{search}%")
        ))

    # Count
    count_result = await db.execute(
        select(func.count(KnowledgeBaseArticle.id)).where(and_(*conditions))
    )
    total = count_result.scalar()

    # Get articles
    result = await db.execute(
        select(KnowledgeBaseArticle)
        .where(and_(*conditions))
        .order_by(KnowledgeBaseArticle.created_at.desc())
        .offset((page - 1) * page_size)
        .limit(page_size)
    )
    articles = result.scalars().all()

    return {
        "articles": [
            ArticleResponse(
                id=a.id,
                title=a.title,
                slug=a.slug,
                content=a.content[:500] + "..." if len(a.content) > 500 else a.content,
                content_format=a.content_format,
                summary=a.summary,
                category_id=a.category_id,
                meta_title=a.meta_title,
                meta_description=a.meta_description,
                keywords=a.keywords,
                featured_image=a.featured_image,
                status=a.status.value,
                published_at=a.published_at,
                view_count=a.view_count,
                helpful_count=a.helpful_count,
                include_in_training=a.include_in_training,
                created_at=a.created_at
            )
            for a in articles
        ],
        "total": total,
        "page": page,
        "page_size": page_size
    }


@router.post("/knowledge-base/articles", status_code=201)
async def create_article(
    client_id: int,
    request: ArticleCreate,
    db: AsyncSession = Depends(get_db)
):
    """Create a new article"""
    article = KnowledgeBaseArticle(
        client_id=client_id,
        title=request.title,
        slug=generate_slug(request.title),
        content=request.content,
        content_format=request.content_format,
        summary=request.summary,
        category_id=request.category_id,
        meta_title=request.meta_title,
        meta_description=request.meta_description,
        keywords=request.keywords,
        featured_image=request.featured_image,
        status=ArticleStatus(request.status),
        include_in_training=request.include_in_training
    )

    if request.status == "published":
        article.published_at = datetime.utcnow()

    db.add(article)
    await db.commit()
    await db.refresh(article)

    return {"success": True, "article_id": article.id, "slug": article.slug}


@router.get("/knowledge-base/articles/{article_id}")
async def get_article(
    article_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Get article by ID"""
    result = await db.execute(
        select(KnowledgeBaseArticle).where(
            and_(KnowledgeBaseArticle.id == article_id, KnowledgeBaseArticle.deleted_at.is_(None))
        )
    )
    article = result.scalar_one_or_none()

    if not article:
        raise HTTPException(status_code=404, detail="Article not found")

    return ArticleResponse(
        id=article.id,
        title=article.title,
        slug=article.slug,
        content=article.content,
        content_format=article.content_format,
        summary=article.summary,
        category_id=article.category_id,
        meta_title=article.meta_title,
        meta_description=article.meta_description,
        keywords=article.keywords,
        featured_image=article.featured_image,
        status=article.status.value,
        published_at=article.published_at,
        view_count=article.view_count,
        helpful_count=article.helpful_count,
        include_in_training=article.include_in_training,
        created_at=article.created_at
    )


@router.put("/knowledge-base/articles/{article_id}")
async def update_article(
    article_id: int,
    request: ArticleUpdate,
    db: AsyncSession = Depends(get_db)
):
    """Update article"""
    result = await db.execute(
        select(KnowledgeBaseArticle).where(KnowledgeBaseArticle.id == article_id)
    )
    article = result.scalar_one_or_none()

    if not article:
        raise HTTPException(status_code=404, detail="Article not found")

    update_data = request.model_dump(exclude_unset=True)

    if "title" in update_data:
        update_data["slug"] = generate_slug(update_data["title"])

    if "status" in update_data:
        new_status = ArticleStatus(update_data["status"])
        if new_status == ArticleStatus.PUBLISHED and article.status != ArticleStatus.PUBLISHED:
            article.published_at = datetime.utcnow()
        update_data["status"] = new_status

    for field, value in update_data.items():
        setattr(article, field, value)

    article.updated_at = datetime.utcnow()
    await db.commit()

    return {"success": True, "message": "Article updated"}


@router.delete("/knowledge-base/articles/{article_id}")
async def delete_article(
    article_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Delete article"""
    result = await db.execute(
        select(KnowledgeBaseArticle).where(KnowledgeBaseArticle.id == article_id)
    )
    article = result.scalar_one_or_none()

    if not article:
        raise HTTPException(status_code=404, detail="Article not found")

    article.deleted_at = datetime.utcnow()
    await db.commit()

    return {"success": True, "message": "Article deleted"}


# ============================================================
# TRAINING DATA
# ============================================================

@router.get("/training-data")
async def list_training_data(
    client_id: int,
    source_type: Optional[str] = Query(None),
    is_trained: Optional[bool] = Query(None),
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100),
    db: AsyncSession = Depends(get_db)
):
    """List training data sources"""
    conditions = [
        TrainingData.client_id == client_id,
        TrainingData.deleted_at.is_(None)
    ]

    if source_type:
        conditions.append(TrainingData.source_type == DataSourceType(source_type))
    if is_trained is not None:
        conditions.append(TrainingData.is_trained == is_trained)

    result = await db.execute(
        select(TrainingData)
        .where(and_(*conditions))
        .order_by(TrainingData.created_at.desc())
        .offset((page - 1) * page_size)
        .limit(page_size)
    )
    data = result.scalars().all()

    return {
        "training_data": [
            TrainingDataResponse(
                id=d.id,
                source_type=d.source_type.value,
                source_name=d.source_name,
                source_url=d.source_url,
                file_size=d.file_size,
                file_type=d.file_type,
                is_processed=d.is_processed,
                is_trained=d.is_trained,
                embedding_count=d.embedding_count,
                created_at=d.created_at
            )
            for d in data
        ]
    }


@router.post("/training-data/upload")
async def upload_training_data(
    client_id: int = Form(...),
    file: UploadFile = File(...),
    source_type: str = Form("document"),
    background_tasks: BackgroundTasks = None,
    db: AsyncSession = Depends(get_db)
):
    """Upload training data file"""
    # Validate file type
    allowed_types = [
        "application/pdf",
        "text/plain",
        "text/csv",
        "application/json",
        "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
    ]

    if file.content_type not in allowed_types:
        raise HTTPException(
            status_code=400,
            detail=f"File type not allowed. Allowed: PDF, TXT, CSV, JSON, DOCX"
        )

    # Read file
    content = await file.read()
    content_hash = hashlib.md5(content).hexdigest()

    # Check for duplicate
    existing = await db.execute(
        select(TrainingData).where(
            and_(
                TrainingData.client_id == client_id,
                TrainingData.content_hash == content_hash,
                TrainingData.deleted_at.is_(None)
            )
        )
    )
    if existing.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="This file has already been uploaded")

    # Create training data record
    training_data = TrainingData(
        client_id=client_id,
        source_type=DataSourceType(source_type),
        source_name=file.filename,
        file_size=len(content),
        file_type=file.content_type,
        content_hash=content_hash
    )

    db.add(training_data)
    await db.commit()
    await db.refresh(training_data)

    # TODO: Queue background processing task
    # background_tasks.add_task(process_training_data, training_data.id)

    return {
        "success": True,
        "training_data_id": training_data.id,
        "message": "File uploaded. Processing will begin shortly."
    }


@router.post("/training-data/url")
async def add_training_url(
    client_id: int,
    url: str = Form(...),
    name: Optional[str] = Form(None),
    db: AsyncSession = Depends(get_db)
):
    """Add website URL as training data source"""
    training_data = TrainingData(
        client_id=client_id,
        source_type=DataSourceType.WEBSITE,
        source_name=name or url,
        source_url=url
    )

    db.add(training_data)
    await db.commit()
    await db.refresh(training_data)

    return {
        "success": True,
        "training_data_id": training_data.id,
        "message": "URL added. Crawling will begin shortly."
    }


@router.delete("/training-data/{data_id}")
async def delete_training_data(
    data_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Delete training data source"""
    result = await db.execute(
        select(TrainingData).where(TrainingData.id == data_id)
    )
    data = result.scalar_one_or_none()

    if not data:
        raise HTTPException(status_code=404, detail="Training data not found")

    data.deleted_at = datetime.utcnow()
    await db.commit()

    return {"success": True, "message": "Training data deleted"}


@router.post("/training-data/train")
async def trigger_training(
    client_id: int,
    job_type: str = Form("full"),  # full, incremental, faq_only
    db: AsyncSession = Depends(get_db)
):
    """Trigger AI training job"""
    # Create training job
    job = TrainingJob(
        client_id=client_id,
        job_type=job_type,
        status="pending"
    )

    db.add(job)
    await db.commit()
    await db.refresh(job)

    # TODO: Queue actual training job

    return {
        "success": True,
        "job_id": job.id,
        "status": "pending",
        "message": "Training job queued"
    }


@router.get("/training-data/jobs")
async def list_training_jobs(
    client_id: int,
    status: Optional[str] = Query(None),
    db: AsyncSession = Depends(get_db)
):
    """List training jobs"""
    conditions = [TrainingJob.client_id == client_id]

    if status:
        conditions.append(TrainingJob.status == status)

    result = await db.execute(
        select(TrainingJob)
        .where(and_(*conditions))
        .order_by(TrainingJob.created_at.desc())
        .limit(20)
    )
    jobs = result.scalars().all()

    return {
        "jobs": [
            {
                "id": j.id,
                "job_type": j.job_type,
                "status": j.status,
                "total_items": j.total_items,
                "processed_items": j.processed_items,
                "error_count": j.error_count,
                "started_at": j.started_at,
                "completed_at": j.completed_at,
                "created_at": j.created_at
            }
            for j in jobs
        ]
    }


# ============================================================
# WHITE-LABEL SETTINGS
# ============================================================

@router.get("/settings/whitelabel")
async def get_whitelabel_settings(
    client_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Get white-label settings for client"""
    result = await db.execute(
        select(ClientWhiteLabelSettings).where(
            ClientWhiteLabelSettings.client_id == client_id
        )
    )
    settings = result.scalar_one_or_none()

    if not settings:
        # Return defaults
        return {
            "client_id": client_id,
            "logo_url": None,
            "primary_color": "#3B82F6",
            "secondary_color": "#10B981",
            "widget_position": "bottom-right",
            "widget_title": "Chat with us",
            "show_powered_by": True
        }

    return settings


@router.put("/settings/whitelabel")
async def update_whitelabel_settings(
    client_id: int,
    request: WhiteLabelSettingsUpdate,
    db: AsyncSession = Depends(get_db)
):
    """Update white-label settings"""
    result = await db.execute(
        select(ClientWhiteLabelSettings).where(
            ClientWhiteLabelSettings.client_id == client_id
        )
    )
    settings = result.scalar_one_or_none()

    if not settings:
        # Create new
        settings = ClientWhiteLabelSettings(client_id=client_id)
        db.add(settings)

    update_data = request.model_dump(exclude_unset=True)
    for field, value in update_data.items():
        setattr(settings, field, value)

    settings.updated_at = datetime.utcnow()
    await db.commit()
    await db.refresh(settings)

    return {"success": True, "message": "White-label settings updated"}


@router.post("/settings/whitelabel/verify-domain")
async def verify_custom_domain(
    client_id: int,
    domain: str = Form(...),
    db: AsyncSession = Depends(get_db)
):
    """Verify custom domain ownership"""
    # TODO: Implement actual domain verification (DNS check)
    # For now, just store the domain

    result = await db.execute(
        select(ClientWhiteLabelSettings).where(
            ClientWhiteLabelSettings.client_id == client_id
        )
    )
    settings = result.scalar_one_or_none()

    if not settings:
        settings = ClientWhiteLabelSettings(client_id=client_id)
        db.add(settings)

    settings.custom_domain = domain
    settings.custom_domain_verified = False  # Will be verified async
    await db.commit()

    return {
        "success": True,
        "domain": domain,
        "verification_required": True,
        "dns_records": [
            {"type": "CNAME", "name": domain, "value": "chat.ai360.com"},
            {"type": "TXT", "name": f"_ai360.{domain}", "value": f"verify={client_id}"}
        ]
    }


# ============================================================
# CHATBOT SETTINGS
# ============================================================

@router.get("/settings/chatbot")
async def get_chatbot_settings(
    client_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Get chatbot settings for client"""
    result = await db.execute(
        select(ClientChatbotSettings).where(
            ClientChatbotSettings.client_id == client_id
        )
    )
    settings = result.scalar_one_or_none()

    if not settings:
        # Return defaults
        return {
            "client_id": client_id,
            "ai_model": "gpt-4o-mini",
            "temperature": 70,
            "max_tokens": 1000,
            "bot_name": "AI Assistant",
            "tone": "professional",
            "use_knowledge_base": True,
            "kb_confidence_threshold": 70
        }

    return settings


@router.put("/settings/chatbot")
async def update_chatbot_settings(
    client_id: int,
    request: ChatbotSettingsUpdate,
    db: AsyncSession = Depends(get_db)
):
    """Update chatbot settings"""
    result = await db.execute(
        select(ClientChatbotSettings).where(
            ClientChatbotSettings.client_id == client_id
        )
    )
    settings = result.scalar_one_or_none()

    if not settings:
        settings = ClientChatbotSettings(client_id=client_id)
        db.add(settings)

    update_data = request.model_dump(exclude_unset=True)

    if "handoff_trigger_keywords" in update_data:
        update_data["handoff_trigger_keywords"] = json.dumps(update_data["handoff_trigger_keywords"])

    for field, value in update_data.items():
        setattr(settings, field, value)

    settings.updated_at = datetime.utcnow()
    await db.commit()

    return {"success": True, "message": "Chatbot settings updated"}


# ============================================================
# TEAM MANAGEMENT
# ============================================================

@router.get("/team/members")
async def list_team_members(
    client_id: int,
    db: AsyncSession = Depends(get_db)
):
    """List team members for client"""
    result = await db.execute(
        select(User).where(
            and_(
                User.client_id == client_id,
                User.deleted_at.is_(None)
            )
        ).order_by(User.created_at)
    )
    members = result.scalars().all()

    return {
        "members": [
            {
                "id": m.id,
                "email": m.email,
                "first_name": m.first_name,
                "last_name": m.last_name,
                "full_name": m.full_name,
                "role": m.role.value,
                "is_active": m.is_active,
                "last_login_at": m.last_login_at,
                "created_at": m.created_at
            }
            for m in members
        ]
    }


@router.post("/team/invite")
async def invite_team_member(
    client_id: int,
    request: TeamInviteRequest,
    invited_by_id: int,  # Would come from auth
    background_tasks: BackgroundTasks,
    db: AsyncSession = Depends(get_db)
):
    """Invite a new team member"""
    # Check if email already exists
    existing_user = await db.execute(
        select(User).where(User.email == request.email)
    )
    if existing_user.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="Email already registered")

    # Check for existing pending invitation
    existing_invite = await db.execute(
        select(TeamInvitation).where(
            and_(
                TeamInvitation.email == request.email,
                TeamInvitation.client_id == client_id,
                TeamInvitation.status == "pending"
            )
        )
    )
    if existing_invite.scalar_one_or_none():
        raise HTTPException(status_code=400, detail="Invitation already sent")

    # Validate role
    valid_roles = ["client_owner", "client_admin", "client_user"]
    if request.role not in valid_roles:
        raise HTTPException(status_code=400, detail="Invalid role")

    # Create invitation
    invitation = TeamInvitation(
        client_id=client_id,
        email=request.email,
        role=request.role,
        token=secrets.token_urlsafe(32),
        invited_by_id=invited_by_id,
        expires_at=datetime.utcnow() + timedelta(days=7)
    )

    db.add(invitation)
    await db.commit()
    await db.refresh(invitation)

    # Send invitation email
    background_tasks.add_task(
        email_service.send_team_invite_email,
        to_email=request.email,
        user_name=request.email.split('@')[0],
        inviter_name="Team Admin",  # Would get from auth
        company_name="Your Company",  # Would get from client
        role=request.role,
        invite_token=invitation.token
    )

    return {
        "success": True,
        "invitation_id": invitation.id,
        "message": f"Invitation sent to {request.email}"
    }


@router.get("/team/invitations")
async def list_invitations(
    client_id: int,
    status: Optional[str] = Query(None),
    db: AsyncSession = Depends(get_db)
):
    """List pending invitations"""
    conditions = [TeamInvitation.client_id == client_id]

    if status:
        conditions.append(TeamInvitation.status == status)

    result = await db.execute(
        select(TeamInvitation)
        .where(and_(*conditions))
        .order_by(TeamInvitation.created_at.desc())
    )
    invitations = result.scalars().all()

    return {
        "invitations": [
            {
                "id": inv.id,
                "email": inv.email,
                "role": inv.role,
                "status": inv.status,
                "expires_at": inv.expires_at,
                "created_at": inv.created_at
            }
            for inv in invitations
        ]
    }


@router.delete("/team/invitations/{invitation_id}")
async def cancel_invitation(
    invitation_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Cancel a pending invitation"""
    result = await db.execute(
        select(TeamInvitation).where(TeamInvitation.id == invitation_id)
    )
    invitation = result.scalar_one_or_none()

    if not invitation:
        raise HTTPException(status_code=404, detail="Invitation not found")

    if invitation.status != "pending":
        raise HTTPException(status_code=400, detail="Can only cancel pending invitations")

    invitation.status = "cancelled"
    await db.commit()

    return {"success": True, "message": "Invitation cancelled"}


@router.put("/team/members/{member_id}")
async def update_team_member(
    member_id: int,
    request: TeamMemberUpdate,
    db: AsyncSession = Depends(get_db)
):
    """Update team member"""
    result = await db.execute(
        select(User).where(User.id == member_id)
    )
    member = result.scalar_one_or_none()

    if not member:
        raise HTTPException(status_code=404, detail="Member not found")

    if request.role:
        try:
            member.role = UserRole(request.role)
        except ValueError:
            raise HTTPException(status_code=400, detail="Invalid role")

    if request.is_active is not None:
        member.is_active = request.is_active

    member.updated_at = datetime.utcnow()
    await db.commit()

    return {"success": True, "message": "Member updated"}


@router.delete("/team/members/{member_id}")
async def remove_team_member(
    member_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Remove team member"""
    result = await db.execute(
        select(User).where(User.id == member_id)
    )
    member = result.scalar_one_or_none()

    if not member:
        raise HTTPException(status_code=404, detail="Member not found")

    # Don't allow removing account owner
    if member.role == UserRole.CLIENT_OWNER:
        raise HTTPException(status_code=400, detail="Cannot remove account owner")

    member.deleted_at = datetime.utcnow()
    member.is_active = False
    await db.commit()

    return {"success": True, "message": "Member removed"}


# ============================================================
# WEBHOOK CONFIGURATION
# ============================================================

@router.get("/webhooks")
async def list_webhooks(
    client_id: int,
    db: AsyncSession = Depends(get_db)
):
    """List webhooks for client"""
    result = await db.execute(
        select(ClientWebhook).where(
            and_(
                ClientWebhook.client_id == client_id,
                ClientWebhook.deleted_at.is_(None)
            )
        )
    )
    webhooks = result.scalars().all()

    return {
        "webhooks": [
            {
                "id": w.id,
                "name": w.name,
                "url": w.url,
                "events": json.loads(w.events) if w.events else [],
                "is_active": w.is_active,
                "last_triggered_at": w.last_triggered_at,
                "success_count": w.success_count,
                "failure_count": w.failure_count,
                "created_at": w.created_at
            }
            for w in webhooks
        ]
    }


@router.post("/webhooks", status_code=201)
async def create_webhook(
    client_id: int,
    request: WebhookCreate,
    db: AsyncSession = Depends(get_db)
):
    """Create a new webhook"""
    # Validate events
    valid_events = [e.value for e in WebhookEventType]
    for event in request.events:
        if event not in valid_events:
            raise HTTPException(status_code=400, detail=f"Invalid event: {event}")

    webhook = ClientWebhook(
        client_id=client_id,
        name=request.name,
        url=request.url,
        events=json.dumps(request.events),
        is_active=request.is_active,
        headers=json.dumps(request.headers) if request.headers else None,
        secret=secrets.token_urlsafe(32)
    )

    db.add(webhook)
    await db.commit()
    await db.refresh(webhook)

    return {
        "success": True,
        "webhook_id": webhook.id,
        "secret": webhook.secret,
        "message": "Webhook created. Save the secret - it won't be shown again."
    }


@router.put("/webhooks/{webhook_id}")
async def update_webhook(
    webhook_id: int,
    request: WebhookUpdate,
    db: AsyncSession = Depends(get_db)
):
    """Update webhook"""
    result = await db.execute(
        select(ClientWebhook).where(ClientWebhook.id == webhook_id)
    )
    webhook = result.scalar_one_or_none()

    if not webhook:
        raise HTTPException(status_code=404, detail="Webhook not found")

    update_data = request.model_dump(exclude_unset=True)

    if "events" in update_data:
        update_data["events"] = json.dumps(update_data["events"])
    if "headers" in update_data:
        update_data["headers"] = json.dumps(update_data["headers"])

    for field, value in update_data.items():
        setattr(webhook, field, value)

    webhook.updated_at = datetime.utcnow()
    await db.commit()

    return {"success": True, "message": "Webhook updated"}


@router.delete("/webhooks/{webhook_id}")
async def delete_webhook(
    webhook_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Delete webhook"""
    result = await db.execute(
        select(ClientWebhook).where(ClientWebhook.id == webhook_id)
    )
    webhook = result.scalar_one_or_none()

    if not webhook:
        raise HTTPException(status_code=404, detail="Webhook not found")

    webhook.deleted_at = datetime.utcnow()
    await db.commit()

    return {"success": True, "message": "Webhook deleted"}


@router.post("/webhooks/{webhook_id}/test")
async def test_webhook(
    webhook_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Send test webhook"""
    result = await db.execute(
        select(ClientWebhook).where(ClientWebhook.id == webhook_id)
    )
    webhook = result.scalar_one_or_none()

    if not webhook:
        raise HTTPException(status_code=404, detail="Webhook not found")

    # TODO: Actually send test webhook
    # For now, just return success

    return {
        "success": True,
        "message": "Test webhook sent",
        "test_payload": {
            "event": "test",
            "timestamp": datetime.utcnow().isoformat(),
            "data": {"message": "This is a test webhook"}
        }
    }


@router.post("/webhooks/{webhook_id}/rotate-secret")
async def rotate_webhook_secret(
    webhook_id: int,
    db: AsyncSession = Depends(get_db)
):
    """Rotate webhook secret"""
    result = await db.execute(
        select(ClientWebhook).where(ClientWebhook.id == webhook_id)
    )
    webhook = result.scalar_one_or_none()

    if not webhook:
        raise HTTPException(status_code=404, detail="Webhook not found")

    new_secret = secrets.token_urlsafe(32)
    webhook.secret = new_secret
    webhook.updated_at = datetime.utcnow()
    await db.commit()

    return {
        "success": True,
        "new_secret": new_secret,
        "message": "Secret rotated. Update your webhook handler."
    }


@router.get("/webhooks/events")
async def list_webhook_events():
    """List available webhook events"""
    return {
        "events": [
            {"event": e.value, "description": _get_event_description(e)}
            for e in WebhookEventType
        ]
    }


def _get_event_description(event: WebhookEventType) -> str:
    descriptions = {
        WebhookEventType.CONVERSATION_STARTED: "Triggered when a new conversation starts",
        WebhookEventType.CONVERSATION_ENDED: "Triggered when a conversation ends",
        WebhookEventType.MESSAGE_RECEIVED: "Triggered when a new message is received",
        WebhookEventType.MESSAGE_SENT: "Triggered when a message is sent",
        WebhookEventType.LEAD_CAPTURED: "Triggered when lead information is captured",
        WebhookEventType.HANDOFF_REQUESTED: "Triggered when handoff to human is requested",
        WebhookEventType.FEEDBACK_RECEIVED: "Triggered when user feedback is received"
    }
    return descriptions.get(event, "")
