import sqlite3
from datetime import datetime, timedelta
from typing import Dict, List, Any, Optional
from dataclasses import dataclass
import email.utils
import re

@dataclass
class ThreadState:
    thread_id: str
    subject: str
    last_external_message: datetime
    last_agency_reply: Optional[datetime]
    alert_level: int  # 0=no alert, 1=24h, 2=48h, 3=72h
    is_active: bool

class ThreadTracker:
    def __init__(self, db_path: str = "email_threads.db"):
        self.db_path = db_path
        self._init_db()
    
    def _init_db(self):
        """Initialize database tables"""
        with sqlite3.connect(self.db_path) as conn:
            conn.execute("""
                CREATE TABLE IF NOT EXISTS threads (
                    thread_id TEXT PRIMARY KEY,
                    subject TEXT,
                    last_external_message TEXT,
                    last_agency_reply TEXT,
                    alert_level INTEGER DEFAULT 0,
                    is_active BOOLEAN DEFAULT 1
                )
            """)
            conn.commit()
    
    def _parse_email_date(self, date_str: str) -> datetime:
        """Parse email date string to datetime object"""
        try:
            # Try parsing as ISO format first
            return datetime.fromisoformat(date_str)
        except ValueError:
            try:
                # Try parsing RFC 2822 format (Gmail standard)
                parsed_date = email.utils.parsedate_to_datetime(date_str)
                # Convert to naive datetime to avoid timezone issues
                return parsed_date.replace(tzinfo=None)
            except (ValueError, TypeError):
                try:
                    # Try parsing common Gmail date formats
                    # Remove timezone info and parse
                    clean_date = re.sub(r'\s*[+-]\d{4}\s*$', '', date_str)
                    return datetime.strptime(clean_date, '%a, %d %b %Y %H:%M:%S')
                except ValueError:
                    # Fallback to current time
                    print(f"Warning: Could not parse date '{date_str}', using current time")
                    return datetime.now()
    
    def update_thread(self, thread_id: str, email: Dict[str, Any], agency_domains: List[str] = None):
        """Update thread state with new email"""
        if agency_domains is None:
            agency_domains = ['iyeoluwaakinrinola03@gmail.com']  # Default agency domain
        
        from_email = email.get('from', '').lower()
        is_agency_reply = any(domain.lower() in from_email for domain in agency_domains)
        message_date = self._parse_email_date(email.get('date', datetime.now().isoformat()))
        subject = email.get('subject', 'No Subject')
        
        with sqlite3.connect(self.db_path) as conn:
            # Get current thread state
            cursor = conn.execute(
                "SELECT * FROM threads WHERE thread_id = ?", (thread_id,)
            )
            row = cursor.fetchone()
            
            if row:
                # Update existing thread
                if is_agency_reply:
                    conn.execute("""
                        UPDATE threads 
                        SET last_agency_reply = ?, alert_level = 0, is_active = 0
                        WHERE thread_id = ?
                    """, (message_date.isoformat(), thread_id))
                else:
                    conn.execute("""
                        UPDATE threads 
                        SET last_external_message = ?, subject = ?, is_active = 1
                        WHERE thread_id = ?
                    """, (message_date.isoformat(), subject, thread_id))
            else:
                # Create new thread
                if not is_agency_reply:
                    conn.execute("""
                        INSERT INTO threads (thread_id, subject, last_external_message, is_active)
                        VALUES (?, ?, ?, 1)
                    """, (thread_id, subject, message_date.isoformat()))
    
    def get_threads_needing_alerts(self, time_frames: List[Dict] = None) -> List[ThreadState]:
        """Get threads that need alerts based on timing"""
        now = datetime.now()
        alert_threads = []
        
        # Default time frames if none provided
        if time_frames is None:
            time_frames = [
                {'hours': 24, 'alert_level': 1},
                {'hours': 48, 'alert_level': 2},
                {'hours': 72, 'alert_level': 3}
            ]
        
        with sqlite3.connect(self.db_path) as conn:
            cursor = conn.execute("""
                SELECT thread_id, subject, last_external_message, last_agency_reply, alert_level
                FROM threads 
                WHERE is_active = 1 AND last_agency_reply IS NULL
            """)
            
            for row in cursor.fetchall():
                thread_id, subject, last_external, last_agency, alert_level = row
                last_external_dt = datetime.fromisoformat(last_external)
                
                # Calculate hours since last external message
                hours_since = (now - last_external_dt).total_seconds() / 3600
                
                # Determine appropriate alert level based on configurable time frames
                appropriate_alert_level = 0
                for frame in time_frames:
                    if hours_since >= frame['hours']:
                        appropriate_alert_level = frame['alert_level']
                
                # Send alert if thread meets timing criteria (regardless of current alert_level)
                if appropriate_alert_level > 0:
                    # Update alert level to the appropriate level
                    if appropriate_alert_level > alert_level:
                        conn.execute(
                            "UPDATE threads SET alert_level = ? WHERE thread_id = ?",
                            (appropriate_alert_level, thread_id)
                        )
                    
                    alert_threads.append(ThreadState(
                        thread_id=thread_id,
                        subject=subject or 'No Subject',
                        last_external_message=last_external_dt,
                        last_agency_reply=datetime.fromisoformat(last_agency) if last_agency else None,
                        alert_level=appropriate_alert_level,
                        is_active=True
                    ))
        
        return alert_threads
    
    def check_thread_reply_status(self, thread_id: str, email_client, agency_domains: List[str] = None) -> bool:
        """Check if the last message in a thread is from the agency (indicating a reply)"""
        if agency_domains is None:
            agency_domains = ['projects@manaknightdigital.com']
        
        try:
            # For IMAP, we can't easily get all thread messages, so we'll use a simpler approach
            # We'll check if the current email is from the agency
            # This is a simplified approach for IMAP
            return False  # Let AI determine if response is needed
            
        except Exception as e:
            print(f"Error checking thread reply status: {e}")
            return False
    
    def get_thread_history(self, thread_id: str) -> List[Dict[str, Any]]:
        """Get message history for a thread (placeholder for future implementation)"""
        # This would integrate with Gmail API to get full thread history
        return [] 