"""
Mail Database - Aggregated Email Operations.
"""

import json
import uuid
from typing import Optional, List, Dict
from datetime import datetime

from .mail_db_pool import get_pool


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:
            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:
            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
