"""
Email-to-Ticket Integration for BMC Hub Ticket System

Implements Option B: Message-ID Threading
- Parse email message_id from workflow context
- Create tickets with email metadata
- Link emails to existing tickets using In-Reply-To header
- Extract ticket tags from email body
- Store email threading info in tticket_email_log
"""

import logging
import re
from typing import Dict, Any, Optional, List
from datetime import datetime

from app.core.database import execute_query, execute_insert, execute_query_single
from app.ticket.backend.ticket_service import TicketService
from app.ticket.backend.models import TTicketCreate, TicketPriority
from psycopg2.extras import Json

logger = logging.getLogger(__name__)


class EmailTicketIntegration:
    """Handles email-to-ticket conversion and threading"""
    
    # Regex patterns for ticket detection
    TICKET_NUMBER_PATTERN = r'TKT-\d{8}-\d{3}'
    TAG_PATTERN = r'#(\w+)'
    
    @staticmethod
    async def create_ticket_from_email(
        email_data: Dict[str, Any],
        customer_id: Optional[int] = None,
        assigned_to_user_id: Optional[int] = None
    ) -> Dict[str, Any]:
        """
        Create ticket from email workflow action
        
        Args:
            email_data: Dict with keys:
                - message_id: Email Message-ID header
                - subject: Email subject
                - from_address: Sender email
                - body: Email body text
                - html_body: Email HTML body (optional)
                - received_at: Email timestamp (ISO format)
                - in_reply_to: In-Reply-To header (optional)
                - references: References header (optional)
            customer_id: BMC customer ID (if known)
            assigned_to_user_id: User to assign ticket to
            
        Returns:
            Dict with ticket_id and ticket_number
        """
        try:
            logger.info(f"🎫 Creating ticket from email: {email_data.get('message_id')}")
            
            # Extract tags from email body
            tags = EmailTicketIntegration._extract_tags(email_data.get('body', ''))
            
            # Determine priority from subject/tags
            priority = EmailTicketIntegration._determine_priority(
                email_data.get('subject', ''),
                tags
            )
            
            # Create ticket
            ticket_create = TTicketCreate(
                subject=email_data.get('subject', 'Email without subject'),
                description=EmailTicketIntegration._format_description(email_data),
                customer_id=customer_id,
                assigned_to_user_id=assigned_to_user_id,
                priority=priority,
                tags=tags,
                custom_fields={
                    'email_from': email_data.get('from_address'),
                    'email_message_id': email_data.get('message_id'),
                    'created_from_email': True
                }
            )
            
            # Create via service (handles auto-number generation)
            ticket = await TicketService.create_ticket(ticket_create, created_by_user_id=None)
            
            # Log email-ticket linkage
            await EmailTicketIntegration._log_email_linkage(
                ticket_id=ticket['id'],
                email_data=email_data
            )
            
            logger.info(f"✅ Created ticket {ticket['ticket_number']} from email {email_data.get('message_id')}")
            
            return {
                'ticket_id': ticket['id'],
                'ticket_number': ticket['ticket_number'],
                'created': True
            }
            
        except Exception as e:
            logger.error(f"❌ Failed to create ticket from email: {e}")
            raise
    
    @staticmethod
    async def link_email_to_ticket(
        ticket_number: str,
        email_data: Dict[str, Any]
    ) -> Dict[str, Any]:
        """
        Link email to existing ticket (reply threading)
        
        Args:
            ticket_number: TKT-YYYYMMDD-XXX format
            email_data: Same format as create_ticket_from_email
            
        Returns:
            Dict with ticket_id and linked=True
        """
        try:
            logger.info(f"🔗 Linking email to ticket {ticket_number}")
            
            # Find ticket by ticket_number
            query = "SELECT id FROM tticket_tickets WHERE ticket_number = %s"
            result = execute_query_single(query, (ticket_number,))
            
            if not result:
                logger.warning(f"⚠️ Ticket {ticket_number} not found - creating new ticket instead")
                return await EmailTicketIntegration.create_ticket_from_email(email_data)
            
            ticket_id = result['id']
            
            # Log email linkage
            await EmailTicketIntegration._log_email_linkage(
                ticket_id=ticket_id,
                email_data=email_data,
                is_reply=True
            )
            
            # Add comment with email content
            from app.ticket.backend.models import TTicketCommentCreate
            comment_text = f"📧 Email from {email_data.get('from_address')}:\n\n{email_data.get('body', '')}"
            
            await TicketService.add_comment(
                ticket_id=ticket_id,
                comment=TTicketCommentCreate(
                    comment_text=comment_text,
                    internal_note=False
                ),
                user_id=None
            )
            
            logger.info(f"✅ Linked email to ticket {ticket_number} (ID: {ticket_id})")
            
            return {
                'ticket_id': ticket_id,
                'ticket_number': ticket_number,
                'linked': True
            }
            
        except Exception as e:
            logger.error(f"❌ Failed to link email to ticket: {e}")
            raise
    
    @staticmethod
    async def process_email_for_ticket(
        email_data: Dict[str, Any],
        customer_id: Optional[int] = None,
        assigned_to_user_id: Optional[int] = None
    ) -> Dict[str, Any]:
        """
        Smart processor: Creates new ticket OR links to existing based on threading
        
        Args:
            email_data: Email metadata dict
            customer_id: Customer ID if known
            assigned_to_user_id: User to assign new tickets to
            
        Returns:
            Dict with ticket_id, ticket_number, created/linked status
        """
        try:
            # Check if email is reply to existing ticket
            ticket_number = EmailTicketIntegration._find_ticket_in_thread(email_data)
            
            if ticket_number:
                # Reply to existing ticket
                return await EmailTicketIntegration.link_email_to_ticket(
                    ticket_number=ticket_number,
                    email_data=email_data
                )
            else:
                # New ticket
                return await EmailTicketIntegration.create_ticket_from_email(
                    email_data=email_data,
                    customer_id=customer_id,
                    assigned_to_user_id=assigned_to_user_id
                )
                
        except Exception as e:
            logger.error(f"❌ Failed to process email for ticket: {e}")
            raise
    
    @staticmethod
    def _find_ticket_in_thread(email_data: Dict[str, Any]) -> Optional[str]:
        """
        Find ticket number in email thread (In-Reply-To, References, Subject)
        
        Returns:
            Ticket number (TKT-YYYYMMDD-XXX) or None
        """
        # Check In-Reply-To header first
        in_reply_to = email_data.get('in_reply_to', '')
        if in_reply_to:
            match = re.search(EmailTicketIntegration.TICKET_NUMBER_PATTERN, in_reply_to)
            if match:
                return match.group(0)
        
        # Check References header
        references = email_data.get('references', '')
        if references:
            match = re.search(EmailTicketIntegration.TICKET_NUMBER_PATTERN, references)
            if match:
                return match.group(0)
        
        # Check subject line for [TKT-YYYYMMDD-XXX] or Re: TKT-YYYYMMDD-XXX
        subject = email_data.get('subject', '')
        match = re.search(EmailTicketIntegration.TICKET_NUMBER_PATTERN, subject)
        if match:
            return match.group(0)
        
        return None
    
    @staticmethod
    def _extract_tags(body: str) -> List[str]:
        """
        Extract #hashtags from email body
        
        Returns:
            List of lowercase tags without # prefix
        """
        if not body:
            return []
        
        tags = re.findall(EmailTicketIntegration.TAG_PATTERN, body)
        return [tag.lower() for tag in tags if len(tag) > 2][:10]  # Max 10 tags
    
    @staticmethod
    def _determine_priority(subject: str, tags: List[str]) -> TicketPriority:
        """
        Determine ticket priority from subject/tags
        
        Returns:
            TicketPriority enum value
        """
        subject_lower = subject.lower()
        all_text = f"{subject_lower} {' '.join(tags)}"
        
        # Critical keywords
        if any(word in all_text for word in ['kritisk', 'critical', 'down', 'nede', 'urgent', 'akut']):
            return TicketPriority.critical
        
        # High priority keywords
        if any(word in all_text for word in ['høj', 'high', 'vigtig', 'important', 'haster']):
            return TicketPriority.high
        
        # Low priority keywords
        if any(word in all_text for word in ['lav', 'low', 'spørgsmål', 'question', 'info']):
            return TicketPriority.low
        
        return TicketPriority.normal
    
    @staticmethod
    def _format_description(email_data: Dict[str, Any]) -> str:
        """
        Format email body as ticket description
        
        Returns:
            Formatted description text
        """
        body = email_data.get('body', '').strip()
        from_address = email_data.get('from_address', 'unknown')
        received_at = email_data.get('received_at', '')
        
        description = f"📧 Email fra: {from_address}\n"
        description += f"📅 Modtaget: {received_at}\n"
        description += f"{'='*60}\n\n"
        description += body
        
        return description
    
    @staticmethod
    async def _log_email_linkage(
        ticket_id: int,
        email_data: Dict[str, Any],
        is_reply: bool = False
    ) -> None:
        """
        Store email-ticket linkage in tticket_email_log
        
        Args:
            ticket_id: Ticket ID
            email_data: Email metadata
            is_reply: True if email is reply to existing ticket
        """
        query = """
            INSERT INTO tticket_email_log (
                ticket_id,
                email_message_id,
                email_subject,
                email_from,
                email_received_at,
                is_reply,
                thread_data
            ) VALUES (%s, %s, %s, %s, %s, %s, %s)
        """
        
        # Parse received_at timestamp
        received_at = email_data.get('received_at')
        if isinstance(received_at, str):
            try:
                received_at = datetime.fromisoformat(received_at.replace('Z', '+00:00'))
            except:
                received_at = None
        
        thread_data = {
            'in_reply_to': email_data.get('in_reply_to'),
            'references': email_data.get('references'),
            'message_id': email_data.get('message_id')
        }
        
        execute_insert(
            query,
            (
                ticket_id,
                email_data.get('message_id'),
                email_data.get('subject'),
                email_data.get('from_address'),
                received_at,
                is_reply,
                Json(thread_data)
            )
        )
        
        logger.info(f"📝 Logged email linkage for ticket {ticket_id}")
    
    @staticmethod
    async def get_ticket_email_thread(ticket_id: int) -> List[Dict[str, Any]]:
        """
        Get all emails linked to a ticket (chronological order)
        
        Args:
            ticket_id: Ticket ID
            
        Returns:
            List of email log entries
        """
        query = """
            SELECT 
                id,
                email_message_id,
                email_subject,
                email_from,
                email_received_at,
                is_reply,
                thread_data,
                created_at
            FROM tticket_email_log
            WHERE ticket_id = %s
            ORDER BY email_received_at ASC
        """
        
        return execute_query(query, (ticket_id,), fetchall=True)
    
    @staticmethod
    async def find_tickets_by_email_address(email_address: str) -> List[Dict[str, Any]]:
        """
        Find all tickets associated with an email address
        
        Args:
            email_address: Email address to search for
            
        Returns:
            List of ticket info dicts
        """
        query = """
            SELECT DISTINCT
                t.id,
                t.ticket_number,
                t.subject,
                t.status,
                t.created_at
            FROM tticket_tickets t
            INNER JOIN tticket_email_log e ON e.ticket_id = t.id
            WHERE e.email_from = %s
            ORDER BY t.created_at DESC
        """
        
        return execute_query(query, (email_address,), fetchall=True)


# Workflow action functions (called from email workflow engine)

async def workflow_action_create_ticket(
    context: Dict[str, Any],
    action_params: Dict[str, Any]
) -> Dict[str, Any]:
    """
    Workflow action: Create ticket from email
    
    Usage in workflow:
        {
            "action": "create_ticket",
            "params": {
                "customer_id": 123,  # Optional
                "assigned_to_user_id": 5,  # Optional
                "priority": "high"  # Optional override
            }
        }
    
    Args:
        context: Email workflow context with email_data
        action_params: Action parameters from workflow definition
        
    Returns:
        Result dict with ticket info
    """
    email_data = context.get('email_data', {})
    
    result = await EmailTicketIntegration.process_email_for_ticket(
        email_data=email_data,
        customer_id=action_params.get('customer_id'),
        assigned_to_user_id=action_params.get('assigned_to_user_id')
    )
    
    return result


async def workflow_action_link_email_to_ticket(
    context: Dict[str, Any],
    action_params: Dict[str, Any]
) -> Dict[str, Any]:
    """
    Workflow action: Link email to existing ticket
    
    Usage in workflow:
        {
            "action": "link_email_to_ticket",
            "params": {
                "ticket_number": "TKT-20251215-001"
            }
        }
    
    Args:
        context: Email workflow context
        action_params: Must contain ticket_number
        
    Returns:
        Result dict with link status
    """
    email_data = context.get('email_data', {})
    ticket_number = action_params.get('ticket_number')
    
    if not ticket_number:
        raise ValueError("ticket_number required in action params")
    
    result = await EmailTicketIntegration.link_email_to_ticket(
        ticket_number=ticket_number,
        email_data=email_data
    )
    
    return result
