"""
Unified Inbox Mail API

FastAPI router for the mail system.
"""

import logging
from typing import Optional, List
from datetime import datetime

from fastapi import APIRouter, HTTPException, Depends, Query, BackgroundTasks
from pydantic import BaseModel

from .models import (
    EmailAccountCreate,
    EmailAccountUpdate,
    EmailAccount,
    AccountTestResult,
    AggregatedEmail,
    EmailSearchParams,
    TaskCreate,
    TaskUpdate,
    InboxTask,
    TaskDashboardStats,
    EmailComposeRequest,
    EmailSendResult,
    MailStats,
    MailHealthCheck,
    EmailAnalysisResult,
    ResponseSuggestion,
    TaskStatus,
    TaskPriority,
    EmailCategory,
)
from .mail_db import (
    init_mail_tables,
    create_email_account,
    get_email_accounts,
    get_email_account,
    delete_email_account,
    get_unified_inbox,
    get_email,
    mark_email_read,
    mark_email_starred,
    get_mail_stats,
    log_mail_audit,
)
from .credentials import get_credentials_service
from .aggregator import get_mail_aggregator
from .ai_service import get_ai_email_service
from .task_service import get_task_service

logger = logging.getLogger(__name__)

router = APIRouter(prefix="/api/v1/mail", tags=["Mail"])


# =============================================================================
# Health & Init
# =============================================================================

@router.get("/health", response_model=MailHealthCheck)
async def health_check():
    """Health check for the mail system."""
    # TODO: Implement full health check
    return MailHealthCheck(
        status="healthy",
        database_connected=True,
        vault_connected=True,
    )


@router.post("/init")
async def initialize_mail_system():
    """Initialize mail database tables."""
    success = await init_mail_tables()
    if not success:
        raise HTTPException(status_code=500, detail="Failed to initialize mail tables")
    return {"status": "initialized"}


# =============================================================================
# Account Management
# =============================================================================

class AccountCreateRequest(BaseModel):
    """Request to create an email account."""
    email: str
    display_name: str
    account_type: str = "personal"
    imap_host: str
    imap_port: int = 993
    imap_ssl: bool = True
    smtp_host: str
    smtp_port: int = 465
    smtp_ssl: bool = True
    password: str


@router.post("/accounts", response_model=dict)
async def create_account(
    request: AccountCreateRequest,
    user_id: str = Query(..., description="User ID"),
    tenant_id: str = Query(..., description="Tenant ID"),
):
    """Create a new email account."""
    credentials_service = get_credentials_service()

    # Store credentials securely
    vault_path = await credentials_service.store_credentials(
        account_id=f"{user_id}_{request.email}",
        email=request.email,
        password=request.password,
        imap_host=request.imap_host,
        imap_port=request.imap_port,
        smtp_host=request.smtp_host,
        smtp_port=request.smtp_port,
    )

    # Create account in database
    account_id = await create_email_account(
        user_id=user_id,
        tenant_id=tenant_id,
        email=request.email,
        display_name=request.display_name,
        account_type=request.account_type,
        imap_host=request.imap_host,
        imap_port=request.imap_port,
        imap_ssl=request.imap_ssl,
        smtp_host=request.smtp_host,
        smtp_port=request.smtp_port,
        smtp_ssl=request.smtp_ssl,
        vault_path=vault_path,
    )

    if not account_id:
        raise HTTPException(status_code=500, detail="Failed to create account")

    # Log audit
    await log_mail_audit(
        user_id=user_id,
        action="account_created",
        entity_type="account",
        entity_id=account_id,
        details={"email": request.email},
        tenant_id=tenant_id,
    )

    return {"id": account_id, "status": "created"}


@router.get("/accounts", response_model=List[dict])
async def list_accounts(
    user_id: str = Query(..., description="User ID"),
    tenant_id: Optional[str] = Query(None, description="Tenant ID"),
):
    """List all email accounts for a user."""
    accounts = await get_email_accounts(user_id, tenant_id)
    # Remove sensitive fields
    for account in accounts:
        account.pop("vault_path", None)
    return accounts


@router.get("/accounts/{account_id}", response_model=dict)
async def get_account(
    account_id: str,
    user_id: str = Query(..., description="User ID"),
):
    """Get a single email account."""
    account = await get_email_account(account_id, user_id)
    if not account:
        raise HTTPException(status_code=404, detail="Account not found")
    account.pop("vault_path", None)
    return account


@router.delete("/accounts/{account_id}")
async def remove_account(
    account_id: str,
    user_id: str = Query(..., description="User ID"),
):
    """Delete an email account."""
    account = await get_email_account(account_id, user_id)
    if not account:
        raise HTTPException(status_code=404, detail="Account not found")

    # Delete credentials
    credentials_service = get_credentials_service()
    vault_path = account.get("vault_path", "")
    if vault_path:
        await credentials_service.delete_credentials(account_id, vault_path)

    # Delete from database (cascades to emails)
    success = await delete_email_account(account_id, user_id)
    if not success:
        raise HTTPException(status_code=500, detail="Failed to delete account")

    await log_mail_audit(
        user_id=user_id,
        action="account_deleted",
        entity_type="account",
        entity_id=account_id,
    )

    return {"status": "deleted"}


@router.post("/accounts/{account_id}/test", response_model=AccountTestResult)
async def test_account_connection(
    account_id: str,
    user_id: str = Query(..., description="User ID"),
):
    """Test connection for an email account."""
    account = await get_email_account(account_id, user_id)
    if not account:
        raise HTTPException(status_code=404, detail="Account not found")

    # Get credentials
    credentials_service = get_credentials_service()
    vault_path = account.get("vault_path", "")
    creds = await credentials_service.get_credentials(account_id, vault_path)

    if not creds:
        return AccountTestResult(
            success=False,
            error_message="Credentials not found"
        )

    # Test connection
    aggregator = get_mail_aggregator()
    result = await aggregator.test_account_connection(
        imap_host=account["imap_host"],
        imap_port=account["imap_port"],
        imap_ssl=account["imap_ssl"],
        smtp_host=account["smtp_host"],
        smtp_port=account["smtp_port"],
        smtp_ssl=account["smtp_ssl"],
        email_address=creds.email,
        password=creds.password,
    )

    return result


class ConnectionTestRequest(BaseModel):
    """Request to test connection before saving account."""
    email: str
    imap_host: str
    imap_port: int = 993
    imap_ssl: bool = True
    smtp_host: str
    smtp_port: int = 465
    smtp_ssl: bool = True
    password: str


@router.post("/accounts/test-connection", response_model=AccountTestResult)
async def test_connection_before_save(request: ConnectionTestRequest):
    """
    Test IMAP/SMTP connection before saving an account.

    This allows the wizard to verify credentials are correct
    before creating the account in the database.
    """
    aggregator = get_mail_aggregator()

    result = await aggregator.test_account_connection(
        imap_host=request.imap_host,
        imap_port=request.imap_port,
        imap_ssl=request.imap_ssl,
        smtp_host=request.smtp_host,
        smtp_port=request.smtp_port,
        smtp_ssl=request.smtp_ssl,
        email_address=request.email,
        password=request.password,
    )

    return result


@router.post("/accounts/{account_id}/sync")
async def sync_account(
    account_id: str,
    user_id: str = Query(..., description="User ID"),
    max_emails: int = Query(100, ge=1, le=500),
    background_tasks: BackgroundTasks = None,
):
    """Sync emails from an account."""
    aggregator = get_mail_aggregator()

    try:
        new_count, total_count = await aggregator.sync_account(
            account_id=account_id,
            user_id=user_id,
            max_emails=max_emails,
        )

        return {
            "status": "synced",
            "new_emails": new_count,
            "total_emails": total_count,
        }

    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))


# =============================================================================
# Unified Inbox
# =============================================================================

@router.get("/inbox", response_model=List[dict])
async def get_inbox(
    user_id: str = Query(..., description="User ID"),
    account_ids: Optional[str] = Query(None, description="Comma-separated account IDs"),
    categories: Optional[str] = Query(None, description="Comma-separated categories"),
    is_read: Optional[bool] = Query(None),
    is_starred: Optional[bool] = Query(None),
    limit: int = Query(50, ge=1, le=200),
    offset: int = Query(0, ge=0),
):
    """Get unified inbox with all accounts aggregated."""
    # Parse comma-separated values
    account_id_list = account_ids.split(",") if account_ids else None
    category_list = categories.split(",") if categories else None

    emails = await get_unified_inbox(
        user_id=user_id,
        account_ids=account_id_list,
        categories=category_list,
        is_read=is_read,
        is_starred=is_starred,
        limit=limit,
        offset=offset,
    )

    return emails


@router.get("/inbox/{email_id}", response_model=dict)
async def get_email_detail(
    email_id: str,
    user_id: str = Query(..., description="User ID"),
):
    """Get a single email with full details."""
    email_data = await get_email(email_id, user_id)
    if not email_data:
        raise HTTPException(status_code=404, detail="Email not found")

    # Mark as read
    await mark_email_read(email_id, user_id, is_read=True)

    return email_data


@router.post("/inbox/{email_id}/read")
async def mark_read(
    email_id: str,
    user_id: str = Query(..., description="User ID"),
    is_read: bool = Query(True),
):
    """Mark email as read/unread."""
    success = await mark_email_read(email_id, user_id, is_read)
    if not success:
        raise HTTPException(status_code=500, detail="Failed to update email")
    return {"status": "updated", "is_read": is_read}


@router.post("/inbox/{email_id}/star")
async def mark_starred(
    email_id: str,
    user_id: str = Query(..., description="User ID"),
    is_starred: bool = Query(True),
):
    """Mark email as starred/unstarred."""
    success = await mark_email_starred(email_id, user_id, is_starred)
    if not success:
        raise HTTPException(status_code=500, detail="Failed to update email")
    return {"status": "updated", "is_starred": is_starred}


# =============================================================================
# Send Email
# =============================================================================

@router.post("/send", response_model=EmailSendResult)
async def send_email(
    request: EmailComposeRequest,
    user_id: str = Query(..., description="User ID"),
):
    """Send an email."""
    aggregator = get_mail_aggregator()
    result = await aggregator.send_email(
        account_id=request.account_id,
        user_id=user_id,
        request=request,
    )

    if result.success:
        await log_mail_audit(
            user_id=user_id,
            action="email_sent",
            entity_type="email",
            details={
                "account_id": request.account_id,
                "to": request.to,
                "subject": request.subject,
            },
        )

    return result


# =============================================================================
# AI Analysis
# =============================================================================

@router.post("/analyze/{email_id}", response_model=EmailAnalysisResult)
async def analyze_email(
    email_id: str,
    user_id: str = Query(..., description="User ID"),
):
    """Run AI analysis on an email."""
    email_data = await get_email(email_id, user_id)
    if not email_data:
        raise HTTPException(status_code=404, detail="Email not found")

    ai_service = get_ai_email_service()
    result = await ai_service.analyze_email(
        email_id=email_id,
        sender_email=email_data.get("sender_email", ""),
        sender_name=email_data.get("sender_name"),
        subject=email_data.get("subject", ""),
        body_text=email_data.get("body_text"),
        body_preview=email_data.get("body_preview"),
    )

    return result


@router.get("/suggestions/{email_id}", response_model=List[ResponseSuggestion])
async def get_response_suggestions(
    email_id: str,
    user_id: str = Query(..., description="User ID"),
):
    """Get AI-generated response suggestions for an email."""
    email_data = await get_email(email_id, user_id)
    if not email_data:
        raise HTTPException(status_code=404, detail="Email not found")

    ai_service = get_ai_email_service()

    # Use stored analysis if available
    from .models import SenderType, EmailCategory as EC
    sender_type = SenderType(email_data.get("sender_type", "unbekannt"))
    category = EC(email_data.get("category", "sonstiges"))

    suggestions = await ai_service.suggest_response(
        subject=email_data.get("subject", ""),
        body_text=email_data.get("body_text", ""),
        sender_type=sender_type,
        category=category,
    )

    return suggestions


# =============================================================================
# Tasks (Arbeitsvorrat)
# =============================================================================

@router.get("/tasks", response_model=List[dict])
async def list_tasks(
    user_id: str = Query(..., description="User ID"),
    status: Optional[str] = Query(None, description="Filter by status"),
    priority: Optional[str] = Query(None, description="Filter by priority"),
    include_completed: bool = Query(False),
    limit: int = Query(50, ge=1, le=200),
    offset: int = Query(0, ge=0),
):
    """Get all tasks for a user."""
    task_service = get_task_service()

    status_enum = TaskStatus(status) if status else None
    priority_enum = TaskPriority(priority) if priority else None

    tasks = await task_service.get_user_tasks(
        user_id=user_id,
        status=status_enum,
        priority=priority_enum,
        include_completed=include_completed,
        limit=limit,
        offset=offset,
    )

    return tasks


@router.post("/tasks", response_model=dict)
async def create_task(
    request: TaskCreate,
    user_id: str = Query(..., description="User ID"),
    tenant_id: str = Query(..., description="Tenant ID"),
):
    """Create a new task manually."""
    task_service = get_task_service()

    task_id = await task_service.create_manual_task(
        user_id=user_id,
        tenant_id=tenant_id,
        task_data=request,
    )

    if not task_id:
        raise HTTPException(status_code=500, detail="Failed to create task")

    return {"id": task_id, "status": "created"}


@router.get("/tasks/dashboard", response_model=TaskDashboardStats)
async def get_task_dashboard(
    user_id: str = Query(..., description="User ID"),
):
    """Get dashboard statistics for tasks."""
    task_service = get_task_service()
    return await task_service.get_dashboard_stats(user_id)


@router.get("/tasks/{task_id}", response_model=dict)
async def get_task(
    task_id: str,
    user_id: str = Query(..., description="User ID"),
):
    """Get a single task."""
    task_service = get_task_service()
    task = await task_service.get_task(task_id, user_id)

    if not task:
        raise HTTPException(status_code=404, detail="Task not found")

    return task


@router.put("/tasks/{task_id}")
async def update_task(
    task_id: str,
    request: TaskUpdate,
    user_id: str = Query(..., description="User ID"),
):
    """Update a task."""
    task_service = get_task_service()

    success = await task_service.update_task(task_id, user_id, request)
    if not success:
        raise HTTPException(status_code=500, detail="Failed to update task")

    return {"status": "updated"}


@router.post("/tasks/{task_id}/complete")
async def complete_task(
    task_id: str,
    user_id: str = Query(..., description="User ID"),
):
    """Mark a task as completed."""
    task_service = get_task_service()

    success = await task_service.mark_completed(task_id, user_id)
    if not success:
        raise HTTPException(status_code=500, detail="Failed to complete task")

    return {"status": "completed"}


@router.post("/tasks/from-email/{email_id}")
async def create_task_from_email(
    email_id: str,
    user_id: str = Query(..., description="User ID"),
    tenant_id: str = Query(..., description="Tenant ID"),
):
    """Create a task from an email (after analysis)."""
    email_data = await get_email(email_id, user_id)
    if not email_data:
        raise HTTPException(status_code=404, detail="Email not found")

    # Get deadlines from stored analysis
    deadlines_raw = email_data.get("detected_deadlines", [])
    from .models import DeadlineExtraction, SenderType

    deadlines = []
    for d in deadlines_raw:
        try:
            deadlines.append(DeadlineExtraction(
                deadline_date=datetime.fromisoformat(d["date"]),
                description=d.get("description", "Frist"),
                confidence=0.8,
                source_text="",
                is_firm=d.get("is_firm", True),
            ))
        except (KeyError, ValueError):
            continue

    sender_type = None
    if email_data.get("sender_type"):
        try:
            sender_type = SenderType(email_data["sender_type"])
        except ValueError:
            pass

    task_service = get_task_service()
    task_id = await task_service.create_task_from_email(
        user_id=user_id,
        tenant_id=tenant_id,
        email_id=email_id,
        deadlines=deadlines,
        sender_type=sender_type,
    )

    if not task_id:
        raise HTTPException(status_code=500, detail="Failed to create task")

    return {"id": task_id, "status": "created"}


# =============================================================================
# Statistics
# =============================================================================

@router.get("/stats", response_model=MailStats)
async def get_statistics(
    user_id: str = Query(..., description="User ID"),
):
    """Get overall mail statistics for a user."""
    stats = await get_mail_stats(user_id)
    return MailStats(**stats)


# =============================================================================
# Sync All
# =============================================================================

@router.post("/sync-all")
async def sync_all_accounts(
    user_id: str = Query(..., description="User ID"),
    tenant_id: Optional[str] = Query(None),
):
    """Sync all email accounts for a user."""
    aggregator = get_mail_aggregator()
    results = await aggregator.sync_all_accounts(user_id, tenant_id)
    return {"status": "synced", "results": results}
