"""
Conversation State Management
==============================
Pure functions and async helpers for managing dp_conversations.status transitions.

Status values:
- 'active': Conversation is open and LIA can respond
- 'paused': Conversation is paused (soft_no >= 2, confusion >= 2, or escalated)
- 'dnc': Do Not Contact - no further messages allowed

Transitions:
- active → paused: When soft_no_count >= 2 OR confusion_count >= 2 OR needs_human_review
- active → dnc: When tier == 'T6' (opt-out detected)
- paused → active: When manager sends a reply (resolves escalation)
- dnc: Terminal state (no transitions out)
"""

from uuid import UUID
from app.db import get_conn


def compute_new_status(
    current_status: str,
    tier: str | None = None,
    soft_no_count: int = 0,
    confusion_count: int = 0,
    needs_human_review: bool = False,
) -> str:
    """
    Pure function to compute the new conversation status.
    
    Args:
        current_status: 'active' | 'paused' | 'dnc'
        tier: URE tier classification (e.g., 'T6' for opt-out)
        soft_no_count: Number of soft objections
        confusion_count: Number of unrecognised messages
        needs_human_review: Whether escalation has been triggered
    
    Returns:
        New status: 'active' | 'paused' | 'dnc'
    """
    if current_status == "dnc":
        return "dnc"
    
    if tier == "T6":
        return "dnc"
    
    if needs_human_review or soft_no_count >= 2 or confusion_count >= 2:
        return "paused"
    
    return "active"


async def update_conversation_status_if_changed(
    conversation_id: str,
    tier: str | None = None,
    soft_no_count: int | None = None,
    confusion_count: int | None = None,
    needs_human_review: bool | None = None,
) -> dict:
    """
    Load conversation, compute new status, and update if changed.
    
    Args:
        conversation_id: UUID string of the conversation
        tier: URE tier (optional, used to detect opt-out)
        soft_no_count: Override soft_no_count (uses DB value if None)
        confusion_count: Override confusion_count (uses DB value if None)
        needs_human_review: Override flag (uses DB value if None)
    
    Returns:
        Dict with old_status, new_status, and updated flag
    """
    conv_uuid = UUID(conversation_id)
    
    conn = await get_conn()
    try:
        row = await conn.fetchrow(
            """
            SELECT status, soft_no_count, confusion_count, needs_human_review
            FROM dp_conversations
            WHERE conversation_id = $1
            """,
            conv_uuid,
        )
        
        if not row:
            return {"error": "Conversation not found", "updated": False}
        
        current_status = row["status"] or "active"
        db_soft_no_count = row["soft_no_count"] or 0
        db_confusion_count = row["confusion_count"] or 0
        db_needs_human_review = row["needs_human_review"] or False
        
        effective_soft_no = soft_no_count if soft_no_count is not None else db_soft_no_count
        effective_confusion = confusion_count if confusion_count is not None else db_confusion_count
        effective_needs_review = needs_human_review if needs_human_review is not None else db_needs_human_review
        
        new_status = compute_new_status(
            current_status=current_status,
            tier=tier,
            soft_no_count=effective_soft_no,
            confusion_count=effective_confusion,
            needs_human_review=effective_needs_review,
        )
        
        if new_status != current_status:
            await conn.execute(
                """
                UPDATE dp_conversations
                SET status = $2,
                    updated_at = NOW()
                WHERE conversation_id = $1
                """,
                conv_uuid,
                new_status,
            )
            return {
                "old_status": current_status,
                "new_status": new_status,
                "updated": True,
            }
        
        return {
            "old_status": current_status,
            "new_status": new_status,
            "updated": False,
        }
    
    finally:
        await conn.close()


async def resolve_escalation(conversation_id: str) -> bool:
    """
    Resolve an escalation by setting status to 'active' and clearing escalation fields.
    Called when a manager sends a reply.
    
    Returns:
        True if successful, False otherwise
    """
    conv_uuid = UUID(conversation_id)
    
    conn = await get_conn()
    try:
        result = await conn.execute(
            """
            UPDATE dp_conversations
            SET status = 'active',
                needs_human_review = FALSE,
                escalation_reason = NULL,
                updated_at = NOW()
            WHERE conversation_id = $1
            """,
            conv_uuid,
        )
        return result == "UPDATE 1"
    finally:
        await conn.close()


async def get_conversation_status(conversation_id: str) -> str | None:
    """
    Get the current status of a conversation.
    
    Returns:
        Status string or None if not found
    """
    conv_uuid = UUID(conversation_id)
    
    conn = await get_conn()
    try:
        row = await conn.fetchrow(
            "SELECT status FROM dp_conversations WHERE conversation_id = $1",
            conv_uuid,
        )
        return row["status"] if row else None
    finally:
        await conn.close()
