"""
Unified Inbox Mail Database Service

PostgreSQL database operations for multi-account mail aggregation.
"""

import os
import json
import uuid
from typing import Optional, List, Dict, Any
from datetime import datetime, timedelta

# Database Configuration - from Vault or environment (test default for CI)
DATABASE_URL = os.getenv("DATABASE_URL", "postgresql://test:test@localhost:5432/test")

# Flag to check if using test defaults
_DB_CONFIGURED = DATABASE_URL != "postgresql://test:test@localhost:5432/test"

# Connection pool (shared with metrics_db)
_pool = None


async def get_pool():
    """Get or create database connection pool."""
    global _pool
    if _pool is None:
        try:
            import asyncpg
            _pool = await asyncpg.create_pool(DATABASE_URL, min_size=2, max_size=10)
        except ImportError:
            print("Warning: asyncpg not installed. Mail database disabled.")
            return None
        except Exception as e:
            print(f"Warning: Failed to connect to PostgreSQL: {e}")
            return None
    return _pool


async def init_mail_tables() -> bool:
    """Initialize mail tables in PostgreSQL."""
    pool = await get_pool()
    if pool is None:
        return False

    create_tables_sql = """
    -- =============================================================================
    -- External Email Accounts
    -- =============================================================================
    CREATE TABLE IF NOT EXISTS external_email_accounts (
        id VARCHAR(36) PRIMARY KEY,
        user_id VARCHAR(36) NOT NULL,
        tenant_id VARCHAR(36) NOT NULL,
        email VARCHAR(255) NOT NULL,
        display_name VARCHAR(255),
        account_type VARCHAR(50) DEFAULT 'personal',

        -- IMAP Settings (password stored in Vault)
        imap_host VARCHAR(255) NOT NULL,
        imap_port INTEGER DEFAULT 993,
        imap_ssl BOOLEAN DEFAULT TRUE,

        -- SMTP Settings
        smtp_host VARCHAR(255) NOT NULL,
        smtp_port INTEGER DEFAULT 465,
        smtp_ssl BOOLEAN DEFAULT TRUE,

        -- Vault path for credentials
        vault_path VARCHAR(500),

        -- Status tracking
        status VARCHAR(20) DEFAULT 'pending',
        last_sync TIMESTAMP,
        sync_error TEXT,
        email_count INTEGER DEFAULT 0,
        unread_count INTEGER DEFAULT 0,

        -- Timestamps
        created_at TIMESTAMP DEFAULT NOW(),
        updated_at TIMESTAMP DEFAULT NOW(),

        -- Constraints
        UNIQUE(user_id, email)
    );

    CREATE INDEX IF NOT EXISTS idx_mail_accounts_user ON external_email_accounts(user_id);
    CREATE INDEX IF NOT EXISTS idx_mail_accounts_tenant ON external_email_accounts(tenant_id);
    CREATE INDEX IF NOT EXISTS idx_mail_accounts_status ON external_email_accounts(status);

    -- =============================================================================
    -- Aggregated Emails
    -- =============================================================================
    CREATE TABLE IF NOT EXISTS aggregated_emails (
        id VARCHAR(36) PRIMARY KEY,
        account_id VARCHAR(36) REFERENCES external_email_accounts(id) ON DELETE CASCADE,
        user_id VARCHAR(36) NOT NULL,
        tenant_id VARCHAR(36) NOT NULL,

        -- Email identification
        message_id VARCHAR(500) NOT NULL,
        folder VARCHAR(100) DEFAULT 'INBOX',

        -- Email content
        subject TEXT,
        sender_email VARCHAR(255),
        sender_name VARCHAR(255),
        recipients JSONB DEFAULT '[]',
        cc JSONB DEFAULT '[]',
        body_preview TEXT,
        body_text TEXT,
        body_html TEXT,
        has_attachments BOOLEAN DEFAULT FALSE,
        attachments JSONB DEFAULT '[]',
        headers JSONB DEFAULT '{}',

        -- Status flags
        is_read BOOLEAN DEFAULT FALSE,
        is_starred BOOLEAN DEFAULT FALSE,
        is_deleted BOOLEAN DEFAULT FALSE,

        -- Dates
        date_sent TIMESTAMP,
        date_received TIMESTAMP,

        -- AI enrichment
        category VARCHAR(50),
        sender_type VARCHAR(50),
        sender_authority_name VARCHAR(255),
        detected_deadlines JSONB DEFAULT '[]',
        suggested_priority VARCHAR(20),
        ai_summary TEXT,
        ai_analyzed_at TIMESTAMP,

        created_at TIMESTAMP DEFAULT NOW(),

        -- Prevent duplicate imports
        UNIQUE(account_id, message_id)
    );

    CREATE INDEX IF NOT EXISTS idx_emails_account ON aggregated_emails(account_id);
    CREATE INDEX IF NOT EXISTS idx_emails_user ON aggregated_emails(user_id);
    CREATE INDEX IF NOT EXISTS idx_emails_tenant ON aggregated_emails(tenant_id);
    CREATE INDEX IF NOT EXISTS idx_emails_date ON aggregated_emails(date_received DESC);
    CREATE INDEX IF NOT EXISTS idx_emails_category ON aggregated_emails(category);
    CREATE INDEX IF NOT EXISTS idx_emails_unread ON aggregated_emails(is_read) WHERE is_read = FALSE;
    CREATE INDEX IF NOT EXISTS idx_emails_starred ON aggregated_emails(is_starred) WHERE is_starred = TRUE;
    CREATE INDEX IF NOT EXISTS idx_emails_sender ON aggregated_emails(sender_email);

    -- =============================================================================
    -- Inbox Tasks (Arbeitsvorrat)
    -- =============================================================================
    CREATE TABLE IF NOT EXISTS inbox_tasks (
        id VARCHAR(36) PRIMARY KEY,
        user_id VARCHAR(36) NOT NULL,
        tenant_id VARCHAR(36) NOT NULL,
        email_id VARCHAR(36) REFERENCES aggregated_emails(id) ON DELETE SET NULL,
        account_id VARCHAR(36) REFERENCES external_email_accounts(id) ON DELETE SET NULL,

        -- Task content
        title VARCHAR(500) NOT NULL,
        description TEXT,
        priority VARCHAR(20) DEFAULT 'medium',
        status VARCHAR(20) DEFAULT 'pending',
        deadline TIMESTAMP,

        -- Source information
        source_email_subject TEXT,
        source_sender VARCHAR(255),
        source_sender_type VARCHAR(50),

        -- AI extraction info
        ai_extracted BOOLEAN DEFAULT FALSE,
        confidence_score FLOAT,

        -- Completion tracking
        completed_at TIMESTAMP,
        reminder_at TIMESTAMP,

        -- Timestamps
        created_at TIMESTAMP DEFAULT NOW(),
        updated_at TIMESTAMP DEFAULT NOW()
    );

    CREATE INDEX IF NOT EXISTS idx_tasks_user ON inbox_tasks(user_id);
    CREATE INDEX IF NOT EXISTS idx_tasks_tenant ON inbox_tasks(tenant_id);
    CREATE INDEX IF NOT EXISTS idx_tasks_status ON inbox_tasks(status);
    CREATE INDEX IF NOT EXISTS idx_tasks_deadline ON inbox_tasks(deadline) WHERE deadline IS NOT NULL;
    CREATE INDEX IF NOT EXISTS idx_tasks_priority ON inbox_tasks(priority);
    CREATE INDEX IF NOT EXISTS idx_tasks_email ON inbox_tasks(email_id) WHERE email_id IS NOT NULL;

    -- =============================================================================
    -- Email Templates
    -- =============================================================================
    CREATE TABLE IF NOT EXISTS email_templates (
        id VARCHAR(36) PRIMARY KEY,
        user_id VARCHAR(36),  -- NULL for system templates
        tenant_id VARCHAR(36),

        name VARCHAR(255) NOT NULL,
        category VARCHAR(100),
        subject_template TEXT,
        body_template TEXT,
        variables JSONB DEFAULT '[]',

        is_system BOOLEAN DEFAULT FALSE,
        usage_count INTEGER DEFAULT 0,

        created_at TIMESTAMP DEFAULT NOW(),
        updated_at TIMESTAMP DEFAULT NOW()
    );

    CREATE INDEX IF NOT EXISTS idx_templates_user ON email_templates(user_id);
    CREATE INDEX IF NOT EXISTS idx_templates_tenant ON email_templates(tenant_id);
    CREATE INDEX IF NOT EXISTS idx_templates_system ON email_templates(is_system);

    -- =============================================================================
    -- Mail Audit Log
    -- =============================================================================
    CREATE TABLE IF NOT EXISTS mail_audit_log (
        id VARCHAR(36) PRIMARY KEY,
        user_id VARCHAR(36) NOT NULL,
        tenant_id VARCHAR(36),
        action VARCHAR(100) NOT NULL,
        entity_type VARCHAR(50),  -- account, email, task
        entity_id VARCHAR(36),
        details JSONB,
        ip_address VARCHAR(45),
        user_agent TEXT,
        created_at TIMESTAMP DEFAULT NOW()
    );

    CREATE INDEX IF NOT EXISTS idx_mail_audit_user ON mail_audit_log(user_id);
    CREATE INDEX IF NOT EXISTS idx_mail_audit_created ON mail_audit_log(created_at DESC);
    CREATE INDEX IF NOT EXISTS idx_mail_audit_action ON mail_audit_log(action);

    -- =============================================================================
    -- Sync Status Tracking
    -- =============================================================================
    CREATE TABLE IF NOT EXISTS mail_sync_status (
        id VARCHAR(36) PRIMARY KEY,
        account_id VARCHAR(36) REFERENCES external_email_accounts(id) ON DELETE CASCADE,
        folder VARCHAR(100),
        last_uid INTEGER DEFAULT 0,
        last_sync TIMESTAMP,
        sync_errors INTEGER DEFAULT 0,
        created_at TIMESTAMP DEFAULT NOW(),
        updated_at TIMESTAMP DEFAULT NOW(),

        UNIQUE(account_id, folder)
    );
    """

    try:
        async with pool.acquire() as conn:
            await conn.execute(create_tables_sql)
        print("Mail tables initialized successfully")
        return True
    except Exception as e:
        print(f"Failed to initialize mail tables: {e}")
        return False


# =============================================================================
# Email Account Operations
# =============================================================================

async def create_email_account(
    user_id: str,
    tenant_id: str,
    email: str,
    display_name: str,
    account_type: str,
    imap_host: str,
    imap_port: int,
    imap_ssl: bool,
    smtp_host: str,
    smtp_port: int,
    smtp_ssl: bool,
    vault_path: str,
) -> Optional[str]:
    """Create a new email account. Returns the account ID."""
    pool = await get_pool()
    if pool is None:
        return None

    account_id = str(uuid.uuid4())
    try:
        async with pool.acquire() as conn:
            await conn.execute(
                """
                INSERT INTO external_email_accounts
                (id, user_id, tenant_id, email, display_name, account_type,
                 imap_host, imap_port, imap_ssl, smtp_host, smtp_port, smtp_ssl, vault_path)
                VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
                """,
                account_id, user_id, tenant_id, email, display_name, account_type,
                imap_host, imap_port, imap_ssl, smtp_host, smtp_port, smtp_ssl, vault_path
            )
        return account_id
    except Exception as e:
        print(f"Failed to create email account: {e}")
        return None


async def get_email_accounts(
    user_id: str,
    tenant_id: Optional[str] = None,
) -> List[Dict]:
    """Get all email accounts for a user."""
    pool = await get_pool()
    if pool is None:
        return []

    try:
        async with pool.acquire() as conn:
            if tenant_id:
                rows = await conn.fetch(
                    """
                    SELECT * FROM external_email_accounts
                    WHERE user_id = $1 AND tenant_id = $2
                    ORDER BY created_at
                    """,
                    user_id, tenant_id
                )
            else:
                rows = await conn.fetch(
                    """
                    SELECT * FROM external_email_accounts
                    WHERE user_id = $1
                    ORDER BY created_at
                    """,
                    user_id
                )
            return [dict(r) for r in rows]
    except Exception as e:
        print(f"Failed to get email accounts: {e}")
        return []


async def get_email_account(account_id: str, user_id: str) -> Optional[Dict]:
    """Get a single email account."""
    pool = await get_pool()
    if pool is None:
        return None

    try:
        async with pool.acquire() as conn:
            row = await conn.fetchrow(
                """
                SELECT * FROM external_email_accounts
                WHERE id = $1 AND user_id = $2
                """,
                account_id, user_id
            )
            return dict(row) if row else None
    except Exception as e:
        print(f"Failed to get email account: {e}")
        return None


async def update_account_status(
    account_id: str,
    status: str,
    sync_error: Optional[str] = None,
    email_count: Optional[int] = None,
    unread_count: Optional[int] = None,
) -> bool:
    """Update account sync status."""
    pool = await get_pool()
    if pool is None:
        return False

    try:
        async with pool.acquire() as conn:
            await conn.execute(
                """
                UPDATE external_email_accounts SET
                    status = $2,
                    sync_error = $3,
                    email_count = COALESCE($4, email_count),
                    unread_count = COALESCE($5, unread_count),
                    last_sync = NOW(),
                    updated_at = NOW()
                WHERE id = $1
                """,
                account_id, status, sync_error, email_count, unread_count
            )
        return True
    except Exception as e:
        print(f"Failed to update account status: {e}")
        return False


async def delete_email_account(account_id: str, user_id: str) -> bool:
    """Delete an email account (cascades to emails)."""
    pool = await get_pool()
    if pool is None:
        return False

    try:
        async with pool.acquire() as conn:
            result = await conn.execute(
                """
                DELETE FROM external_email_accounts
                WHERE id = $1 AND user_id = $2
                """,
                account_id, user_id
            )
            return "DELETE" in result
    except Exception as e:
        print(f"Failed to delete email account: {e}")
        return False


# =============================================================================
# Aggregated Email Operations
# =============================================================================

async def upsert_email(
    account_id: str,
    user_id: str,
    tenant_id: str,
    message_id: str,
    subject: str,
    sender_email: str,
    sender_name: Optional[str],
    recipients: List[str],
    cc: List[str],
    body_preview: Optional[str],
    body_text: Optional[str],
    body_html: Optional[str],
    has_attachments: bool,
    attachments: List[Dict],
    headers: Dict,
    folder: str,
    date_sent: datetime,
    date_received: datetime,
) -> Optional[str]:
    """Insert or update an email. Returns the email ID."""
    pool = await get_pool()
    if pool is None:
        return None

    email_id = str(uuid.uuid4())
    try:
        async with pool.acquire() as conn:
            # Try insert, on conflict update (for re-sync scenarios)
            row = await conn.fetchrow(
                """
                INSERT INTO aggregated_emails
                (id, account_id, user_id, tenant_id, message_id, subject,
                 sender_email, sender_name, recipients, cc, body_preview,
                 body_text, body_html, has_attachments, attachments, headers,
                 folder, date_sent, date_received)
                VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)
                ON CONFLICT (account_id, message_id) DO UPDATE SET
                    subject = EXCLUDED.subject,
                    is_read = EXCLUDED.is_read,
                    folder = EXCLUDED.folder
                RETURNING id
                """,
                email_id, account_id, user_id, tenant_id, message_id, subject,
                sender_email, sender_name, json.dumps(recipients), json.dumps(cc),
                body_preview, body_text, body_html, has_attachments,
                json.dumps(attachments), json.dumps(headers), folder,
                date_sent, date_received
            )
            return row['id'] if row else None
    except Exception as e:
        print(f"Failed to upsert email: {e}")
        return None


async def get_unified_inbox(
    user_id: str,
    account_ids: Optional[List[str]] = None,
    categories: Optional[List[str]] = None,
    is_read: Optional[bool] = None,
    is_starred: Optional[bool] = None,
    limit: int = 50,
    offset: int = 0,
) -> List[Dict]:
    """Get unified inbox with filtering."""
    pool = await get_pool()
    if pool is None:
        return []

    try:
        async with pool.acquire() as conn:
            # Build dynamic query
            conditions = ["user_id = $1", "is_deleted = FALSE"]
            params = [user_id]
            param_idx = 2

            if account_ids:
                conditions.append(f"account_id = ANY(${param_idx})")
                params.append(account_ids)
                param_idx += 1

            if categories:
                conditions.append(f"category = ANY(${param_idx})")
                params.append(categories)
                param_idx += 1

            if is_read is not None:
                conditions.append(f"is_read = ${param_idx}")
                params.append(is_read)
                param_idx += 1

            if is_starred is not None:
                conditions.append(f"is_starred = ${param_idx}")
                params.append(is_starred)
                param_idx += 1

            where_clause = " AND ".join(conditions)
            params.extend([limit, offset])

            query = f"""
                SELECT e.*, a.email as account_email, a.display_name as account_name
                FROM aggregated_emails e
                JOIN external_email_accounts a ON e.account_id = a.id
                WHERE {where_clause}
                ORDER BY e.date_received DESC
                LIMIT ${param_idx} OFFSET ${param_idx + 1}
            """

            rows = await conn.fetch(query, *params)
            return [dict(r) for r in rows]
    except Exception as e:
        print(f"Failed to get unified inbox: {e}")
        return []


async def get_email(email_id: str, user_id: str) -> Optional[Dict]:
    """Get a single email by ID."""
    pool = await get_pool()
    if pool is None:
        return None

    try:
        async with pool.acquire() as conn:
            row = await conn.fetchrow(
                """
                SELECT e.*, a.email as account_email, a.display_name as account_name
                FROM aggregated_emails e
                JOIN external_email_accounts a ON e.account_id = a.id
                WHERE e.id = $1 AND e.user_id = $2
                """,
                email_id, user_id
            )
            return dict(row) if row else None
    except Exception as e:
        print(f"Failed to get email: {e}")
        return None


async def update_email_ai_analysis(
    email_id: str,
    category: str,
    sender_type: str,
    sender_authority_name: Optional[str],
    detected_deadlines: List[Dict],
    suggested_priority: str,
    ai_summary: Optional[str],
) -> bool:
    """Update email with AI analysis results."""
    pool = await get_pool()
    if pool is None:
        return False

    try:
        async with pool.acquire() as conn:
            await conn.execute(
                """
                UPDATE aggregated_emails SET
                    category = $2,
                    sender_type = $3,
                    sender_authority_name = $4,
                    detected_deadlines = $5,
                    suggested_priority = $6,
                    ai_summary = $7,
                    ai_analyzed_at = NOW()
                WHERE id = $1
                """,
                email_id, category, sender_type, sender_authority_name,
                json.dumps(detected_deadlines), suggested_priority, ai_summary
            )
        return True
    except Exception as e:
        print(f"Failed to update email AI analysis: {e}")
        return False


async def mark_email_read(email_id: str, user_id: str, is_read: bool = True) -> bool:
    """Mark email as read/unread."""
    pool = await get_pool()
    if pool is None:
        return False

    try:
        async with pool.acquire() as conn:
            await conn.execute(
                """
                UPDATE aggregated_emails SET is_read = $3
                WHERE id = $1 AND user_id = $2
                """,
                email_id, user_id, is_read
            )
        return True
    except Exception as e:
        print(f"Failed to mark email read: {e}")
        return False


async def mark_email_starred(email_id: str, user_id: str, is_starred: bool = True) -> bool:
    """Mark email as starred/unstarred."""
    pool = await get_pool()
    if pool is None:
        return False

    try:
        async with pool.acquire() as conn:
            await conn.execute(
                """
                UPDATE aggregated_emails SET is_starred = $3
                WHERE id = $1 AND user_id = $2
                """,
                email_id, user_id, is_starred
            )
        return True
    except Exception as e:
        print(f"Failed to mark email starred: {e}")
        return False


# =============================================================================
# Inbox Task Operations
# =============================================================================

async def create_task(
    user_id: str,
    tenant_id: str,
    title: str,
    description: Optional[str] = None,
    priority: str = "medium",
    deadline: Optional[datetime] = None,
    email_id: Optional[str] = None,
    account_id: Optional[str] = None,
    source_email_subject: Optional[str] = None,
    source_sender: Optional[str] = None,
    source_sender_type: Optional[str] = None,
    ai_extracted: bool = False,
    confidence_score: Optional[float] = None,
) -> Optional[str]:
    """Create a new inbox task."""
    pool = await get_pool()
    if pool is None:
        return None

    task_id = str(uuid.uuid4())
    try:
        async with pool.acquire() as conn:
            await conn.execute(
                """
                INSERT INTO inbox_tasks
                (id, user_id, tenant_id, title, description, priority, deadline,
                 email_id, account_id, source_email_subject, source_sender,
                 source_sender_type, ai_extracted, confidence_score)
                VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)
                """,
                task_id, user_id, tenant_id, title, description, priority, deadline,
                email_id, account_id, source_email_subject, source_sender,
                source_sender_type, ai_extracted, confidence_score
            )
        return task_id
    except Exception as e:
        print(f"Failed to create task: {e}")
        return None


async def get_tasks(
    user_id: str,
    status: Optional[str] = None,
    priority: Optional[str] = None,
    include_completed: bool = False,
    limit: int = 50,
    offset: int = 0,
) -> List[Dict]:
    """Get tasks for a user."""
    pool = await get_pool()
    if pool is None:
        return []

    try:
        async with pool.acquire() as conn:
            conditions = ["user_id = $1"]
            params = [user_id]
            param_idx = 2

            if not include_completed:
                conditions.append("status != 'completed'")

            if status:
                conditions.append(f"status = ${param_idx}")
                params.append(status)
                param_idx += 1

            if priority:
                conditions.append(f"priority = ${param_idx}")
                params.append(priority)
                param_idx += 1

            where_clause = " AND ".join(conditions)
            params.extend([limit, offset])

            query = f"""
                SELECT * FROM inbox_tasks
                WHERE {where_clause}
                ORDER BY
                    CASE priority
                        WHEN 'urgent' THEN 1
                        WHEN 'high' THEN 2
                        WHEN 'medium' THEN 3
                        WHEN 'low' THEN 4
                    END,
                    deadline ASC NULLS LAST,
                    created_at DESC
                LIMIT ${param_idx} OFFSET ${param_idx + 1}
            """

            rows = await conn.fetch(query, *params)
            return [dict(r) for r in rows]
    except Exception as e:
        print(f"Failed to get tasks: {e}")
        return []


async def get_task(task_id: str, user_id: str) -> Optional[Dict]:
    """Get a single task."""
    pool = await get_pool()
    if pool is None:
        return None

    try:
        async with pool.acquire() as conn:
            row = await conn.fetchrow(
                "SELECT * FROM inbox_tasks WHERE id = $1 AND user_id = $2",
                task_id, user_id
            )
            return dict(row) if row else None
    except Exception as e:
        print(f"Failed to get task: {e}")
        return None


async def update_task(
    task_id: str,
    user_id: str,
    title: Optional[str] = None,
    description: Optional[str] = None,
    priority: Optional[str] = None,
    status: Optional[str] = None,
    deadline: Optional[datetime] = None,
) -> bool:
    """Update a task."""
    pool = await get_pool()
    if pool is None:
        return False

    try:
        async with pool.acquire() as conn:
            # Build dynamic update
            updates = ["updated_at = NOW()"]
            params = [task_id, user_id]
            param_idx = 3

            if title is not None:
                updates.append(f"title = ${param_idx}")
                params.append(title)
                param_idx += 1

            if description is not None:
                updates.append(f"description = ${param_idx}")
                params.append(description)
                param_idx += 1

            if priority is not None:
                updates.append(f"priority = ${param_idx}")
                params.append(priority)
                param_idx += 1

            if status is not None:
                updates.append(f"status = ${param_idx}")
                params.append(status)
                param_idx += 1
                if status == "completed":
                    updates.append("completed_at = NOW()")

            if deadline is not None:
                updates.append(f"deadline = ${param_idx}")
                params.append(deadline)
                param_idx += 1

            set_clause = ", ".join(updates)
            await conn.execute(
                f"UPDATE inbox_tasks SET {set_clause} WHERE id = $1 AND user_id = $2",
                *params
            )
        return True
    except Exception as e:
        print(f"Failed to update task: {e}")
        return False


async def get_task_dashboard_stats(user_id: str) -> Dict:
    """Get dashboard statistics for tasks."""
    pool = await get_pool()
    if pool is None:
        return {}

    try:
        async with pool.acquire() as conn:
            now = datetime.now()
            today_end = now.replace(hour=23, minute=59, second=59)
            week_end = now + timedelta(days=7)

            stats = await conn.fetchrow(
                """
                SELECT
                    COUNT(*) as total_tasks,
                    COUNT(*) FILTER (WHERE status = 'pending') as pending_tasks,
                    COUNT(*) FILTER (WHERE status = 'in_progress') as in_progress_tasks,
                    COUNT(*) FILTER (WHERE status = 'completed') as completed_tasks,
                    COUNT(*) FILTER (WHERE status != 'completed' AND deadline < $2) as overdue_tasks,
                    COUNT(*) FILTER (WHERE status != 'completed' AND deadline <= $3) as due_today,
                    COUNT(*) FILTER (WHERE status != 'completed' AND deadline <= $4) as due_this_week
                FROM inbox_tasks
                WHERE user_id = $1
                """,
                user_id, now, today_end, week_end
            )

            by_priority = await conn.fetch(
                """
                SELECT priority, COUNT(*) as count
                FROM inbox_tasks
                WHERE user_id = $1 AND status != 'completed'
                GROUP BY priority
                """,
                user_id
            )

            by_sender = await conn.fetch(
                """
                SELECT source_sender_type, COUNT(*) as count
                FROM inbox_tasks
                WHERE user_id = $1 AND status != 'completed' AND source_sender_type IS NOT NULL
                GROUP BY source_sender_type
                """,
                user_id
            )

            return {
                "total_tasks": stats['total_tasks'] or 0,
                "pending_tasks": stats['pending_tasks'] or 0,
                "in_progress_tasks": stats['in_progress_tasks'] or 0,
                "completed_tasks": stats['completed_tasks'] or 0,
                "overdue_tasks": stats['overdue_tasks'] or 0,
                "due_today": stats['due_today'] or 0,
                "due_this_week": stats['due_this_week'] or 0,
                "by_priority": {r['priority']: r['count'] for r in by_priority},
                "by_sender_type": {r['source_sender_type']: r['count'] for r in by_sender},
            }
    except Exception as e:
        print(f"Failed to get task stats: {e}")
        return {}


# =============================================================================
# Statistics & Audit
# =============================================================================

async def get_mail_stats(user_id: str) -> Dict:
    """Get overall mail statistics for a user."""
    pool = await get_pool()
    if pool is None:
        return {}

    try:
        async with pool.acquire() as conn:
            today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)

            # Account stats
            accounts = await conn.fetch(
                """
                SELECT id, email, display_name, status, email_count, unread_count, last_sync
                FROM external_email_accounts
                WHERE user_id = $1
                """,
                user_id
            )

            # Email counts
            email_stats = await conn.fetchrow(
                """
                SELECT
                    COUNT(*) as total_emails,
                    COUNT(*) FILTER (WHERE is_read = FALSE) as unread_emails,
                    COUNT(*) FILTER (WHERE date_received >= $2) as emails_today,
                    COUNT(*) FILTER (WHERE ai_analyzed_at >= $2) as ai_analyses_today
                FROM aggregated_emails
                WHERE user_id = $1
                """,
                user_id, today
            )

            # Task counts
            task_stats = await conn.fetchrow(
                """
                SELECT
                    COUNT(*) as total_tasks,
                    COUNT(*) FILTER (WHERE status = 'pending') as pending_tasks,
                    COUNT(*) FILTER (WHERE status != 'completed' AND deadline < NOW()) as overdue_tasks
                FROM inbox_tasks
                WHERE user_id = $1
                """,
                user_id
            )

            return {
                "total_accounts": len(accounts),
                "active_accounts": sum(1 for a in accounts if a['status'] == 'active'),
                "error_accounts": sum(1 for a in accounts if a['status'] == 'error'),
                "total_emails": email_stats['total_emails'] or 0,
                "unread_emails": email_stats['unread_emails'] or 0,
                "total_tasks": task_stats['total_tasks'] or 0,
                "pending_tasks": task_stats['pending_tasks'] or 0,
                "overdue_tasks": task_stats['overdue_tasks'] or 0,
                "emails_today": email_stats['emails_today'] or 0,
                "ai_analyses_today": email_stats['ai_analyses_today'] or 0,
                "per_account": [
                    {
                        "id": a['id'],
                        "email": a['email'],
                        "display_name": a['display_name'],
                        "status": a['status'],
                        "email_count": a['email_count'],
                        "unread_count": a['unread_count'],
                        "last_sync": a['last_sync'].isoformat() if a['last_sync'] else None,
                    }
                    for a in accounts
                ],
            }
    except Exception as e:
        print(f"Failed to get mail stats: {e}")
        return {}


async def log_mail_audit(
    user_id: str,
    action: str,
    entity_type: Optional[str] = None,
    entity_id: Optional[str] = None,
    details: Optional[Dict] = None,
    tenant_id: Optional[str] = None,
    ip_address: Optional[str] = None,
    user_agent: Optional[str] = None,
) -> bool:
    """Log a mail action for audit trail."""
    pool = await get_pool()
    if pool is None:
        return False

    try:
        async with pool.acquire() as conn:
            await conn.execute(
                """
                INSERT INTO mail_audit_log
                (id, user_id, tenant_id, action, entity_type, entity_id, details, ip_address, user_agent)
                VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
                """,
                str(uuid.uuid4()), user_id, tenant_id, action, entity_type, entity_id,
                json.dumps(details) if details else None, ip_address, user_agent
            )
        return True
    except Exception as e:
        print(f"Failed to log mail audit: {e}")
        return False
