"""Email parsing utilities for extracting meeting information."""

import re
from datetime import datetime, timedelta
from typing import Any

from loguru import logger


def extract_meeting_info(email_content: str, email_subject: str = "") -> dict[str, Any] | None:
    """
    Extract meeting information from email content and subject.

    Args:
        email_content: Email body text
        email_subject: Email subject line

    Returns:
        Dictionary with meeting details if found, None otherwise
    """
    text = (email_subject + " " + email_content).lower()

    # Check for meeting-related keywords
    meeting_keywords = [
        "meeting",
        "appointment",
        "call",
        "conference",
        "standup",
        "stand-up",
        "sync",
        "discussion",
        "catch up",
        "catch-up",
    ]

    has_meeting_keyword = any(keyword in text for keyword in meeting_keywords)
    if not has_meeting_keyword:
        return None

    result: dict[str, Any] = {
        "title": None,
        "start_time": None,
        "end_time": None,
        "location": None,
        "attendees": [],
    }

    # Extract title from subject or first line
    if email_subject:
        # Remove common prefixes
        title = email_subject
        for prefix in ["Re:", "Fwd:", "FW:"]:
            if title.lower().startswith(prefix.lower()):
                title = title[len(prefix) :].strip()
        result["title"] = title[:100]  # Limit length

    # Extract time information
    # Month names mapping
    month_names = {
        "january": 1, "jan": 1,
        "february": 2, "feb": 2,
        "march": 3, "mar": 3,
        "april": 4, "apr": 4,
        "may": 5,
        "june": 6, "jun": 6,
        "july": 7, "jul": 7,
        "august": 8, "aug": 8,
        "september": 9, "sep": 9, "sept": 9,
        "october": 10, "oct": 10,
        "november": 11, "nov": 11,
        "december": 12, "dec": 12,
    }
    
    time_patterns = [
        # "March 7 at 15:00" or "March 7th at 3pm" or "on March 7 at 15:00"
        r"(?:on\s+)?(january|february|march|april|may|june|july|august|september|october|november|december|jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)\s+(\d{1,2})(?:st|nd|rd|th)?\s+(?:at\s+)?(\d{1,2}):(\d{2})",
        r"(?:on\s+)?(january|february|march|april|may|june|july|august|september|october|november|december|jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)\s+(\d{1,2})(?:st|nd|rd|th)?\s+(?:at\s+)?(\d{1,2})\s*(am|pm)",
        # "March 7" (date only, assume current year)
        r"(?:on\s+)?(january|february|march|april|may|june|july|august|september|october|november|december|jan|feb|mar|apr|may|jun|jul|aug|sep|sept|oct|nov|dec)\s+(\d{1,2})(?:st|nd|rd|th)?",
        # Relative dates
        r"tomorrow\s+at\s+(\d{1,2})\s*(am|pm)?",
        r"tomorrow\s+(\d{1,2})\s*(am|pm)?",
        r"(\d{1,2})\s*(am|pm)\s+tomorrow",
        r"(\d{1,2}):(\d{2})\s*(am|pm)?\s+tomorrow",
        r"in\s+(\d+)\s+(hour|hours|minute|minutes|day|days)",
        # Date formats
        r"(\d{1,2})/(\d{1,2})/(\d{4})\s+at\s+(\d{1,2}):(\d{2})\s*(am|pm)?",
        r"(\d{4})-(\d{2})-(\d{2})\s+(\d{1,2}):(\d{2})",
    ]

    for pattern in time_patterns:
        match = re.search(pattern, text, re.IGNORECASE)
        if match:
            try:
                now = datetime.now()
                groups = match.groups()
                
                # Check if this is a month name pattern (first group is month name)
                if groups and groups[0].lower() in month_names:
                    month_name = groups[0].lower()
                    month = month_names[month_name]
                    day = int(groups[1])
                    year = now.year
                    
                    # Check if date is in the past (assume next year if so)
                    test_date = datetime(year, month, day)
                    if test_date < now.replace(hour=0, minute=0, second=0, microsecond=0):
                        year += 1
                    
                    # Check if time is provided (pattern with 4 groups means time included)
                    if len(groups) >= 4 and groups[2] and groups[3]:
                        # Check if groups[3] is am/pm or minutes
                        if groups[3].lower() in ['am', 'pm']:
                            # Format: "March 7 at 3pm" (12-hour with am/pm)
                            hour = int(groups[2])
                            period = groups[3].lower()
                            minute = 0
                            if period == "pm" and hour != 12:
                                hour += 12
                            elif period == "am" and hour == 12:
                                hour = 0
                        else:
                            # Format: "March 7 at 15:00" (24-hour with colon)
                            # groups[2] = hour, groups[3] = minute
                            hour = int(groups[2])
                            minute = int(groups[3])
                        result["start_time"] = datetime(year, month, day, hour, minute)
                    else:
                        # Date only, default to 9am
                        result["start_time"] = datetime(year, month, day, 9, 0)
                    break
                elif "tomorrow" in pattern:
                    base_date = now + timedelta(days=1)
                    hour = int(match.group(1))
                    period = match.group(2) if len(match.groups()) > 1 else None
                    if period:
                        if period.lower() == "pm" and hour != 12:
                            hour += 12
                        elif period.lower() == "am" and hour == 12:
                            hour = 0
                    result["start_time"] = base_date.replace(hour=hour, minute=0, second=0, microsecond=0)
                    break
                elif "in" in pattern:
                    amount = int(match.group(1))
                    unit = match.group(2)
                    if "hour" in unit:
                        result["start_time"] = now + timedelta(hours=amount)
                    elif "minute" in unit:
                        result["start_time"] = now + timedelta(minutes=amount)
                    elif "day" in unit:
                        result["start_time"] = now + timedelta(days=amount)
                    break
            except (ValueError, IndexError, AttributeError):
                continue

    # Extract location
    location_patterns = [
        r"location[:\s]+([^\n]+)",
        r"where[:\s]+([^\n]+)",
        r"at\s+([A-Z][^\n]+)",  # Capitalized location names
        r"room\s+([A-Z0-9]+)",
    ]

    for pattern in location_patterns:
        match = re.search(pattern, text, re.IGNORECASE)
        if match:
            location = match.group(1).strip()
            if len(location) < 100:  # Reasonable length
                result["location"] = location
                break

    # Extract attendees (email addresses)
    email_pattern = r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b"
    emails = re.findall(email_pattern, email_content)
    if emails:
        result["attendees"] = list(set(emails))  # Remove duplicates

    # Only return if we found at least a title or time
    if result["title"] or result["start_time"]:
        logger.info(f"Extracted meeting info: {result}")
        return result

    return None


def format_meeting_for_calendar(meeting_info: dict[str, Any]) -> dict[str, Any]:
    """
    Format meeting info for calendar tool.

    Args:
        meeting_info: Meeting information dictionary

    Returns:
        Formatted dictionary for calendar.create_event
    """
    formatted: dict[str, Any] = {
        "action": "create_event",
    }

    if meeting_info.get("title"):
        formatted["title"] = meeting_info["title"]
    else:
        formatted["title"] = "Meeting"

    if meeting_info.get("start_time"):
        if isinstance(meeting_info["start_time"], datetime):
            formatted["start_time"] = meeting_info["start_time"].isoformat()
        else:
            formatted["start_time"] = str(meeting_info["start_time"])

    if meeting_info.get("end_time"):
        if isinstance(meeting_info["end_time"], datetime):
            formatted["end_time"] = meeting_info["end_time"].isoformat()
        else:
            formatted["end_time"] = str(meeting_info["end_time"])

    if meeting_info.get("location"):
        formatted["location"] = meeting_info["location"]

    if meeting_info.get("description"):
        formatted["description"] = meeting_info["description"]

    if meeting_info.get("attendees"):
        formatted["attendees"] = meeting_info["attendees"]

    return formatted

