import asyncio
import logging
import os
import platform
from typing import Dict, List, Optional, Any
from datetime import datetime, timedelta
from urllib.parse import urlparse

from mcp.server.models import InitializationOptions
import mcp.types as types
from mcp.server import NotificationOptions, Server
from pydantic import AnyUrl
import mcp.server.stdio

# Windows-specific imports with fallback handling
def _is_wsl():
    """Check if running in Windows Subsystem for Linux (WSL)."""
    try:
        # Check for WSL-specific indicators
        with open('/proc/version', 'r') as f:
            version_info = f.read().lower()
            return 'microsoft' in version_info or 'wsl' in version_info
    except (FileNotFoundError, IOError):
        return False

def _can_use_windows_com():
    """Check if Windows COM interface can be used."""
    # Direct Windows
    if platform.system() == "Windows":
        return True
    
    # WSL with Windows access
    if platform.system() == "Linux" and _is_wsl():
        # In WSL, we might be able to access Windows COM if properly configured
        return True
    
    return False

if _can_use_windows_com():
    try:
        import win32com.client
        from pywintypes import com_error
        WINDOWS_COM_AVAILABLE = True
    except ImportError:
        logging.warning("pywin32 not available. Windows COM functionality will be disabled.")
        logging.warning("For WSL, install with: pip install pywin32")
        win32com = None
        com_error = Exception
        WINDOWS_COM_AVAILABLE = False
else:
    win32com = None
    com_error = Exception
    WINDOWS_COM_AVAILABLE = False

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
)
logger = logging.getLogger("outlook-mcp-server-windows-com")

server = Server("outlook-mcp-server-windows-com")

# Define URI schemes for Outlook resources
EMAIL_SCHEME = "email"
CALENDAR_SCHEME = "calendar"
CONTACT_SCHEME = "contact"

# Outlook folder constants
INBOX = 6
SENT_ITEMS = 5
DRAFTS = 16
DELETED_ITEMS = 3
OUTBOX = 4

# Outlook item types
MAIL_ITEM = 0
APPOINTMENT_ITEM = 1
CONTACT_ITEM = 2

class OutlookClient:
    """Client for interacting with Outlook using COM interface."""
    
    def __init__(self):
        """Initialize the Outlook client."""
        self.outlook = None
        self.namespace = None
        
        if not WINDOWS_COM_AVAILABLE:
            logger.warning("Windows COM interface not available. Outlook functionality will be limited.")
            return
            
        self._connect()
    
    def connect_to_outlook(self):
        """Connect to Outlook application using COM"""
        if not WINDOWS_COM_AVAILABLE:
            raise Exception("Windows COM interface not available on this platform")
            
        try:
            outlook = win32com.client.Dispatch("Outlook.Application")
            namespace = outlook.GetNamespace("MAPI")
            return outlook, namespace
        except Exception as e:
            raise Exception(f"Failed to connect to Outlook: {str(e)}")
    
    def _connect(self):
        """Initialize connection to Outlook."""
        if not WINDOWS_COM_AVAILABLE:
            logger.warning("Skipping Outlook connection: Windows COM interface not available")
            return
            
        try:
            self.outlook, self.namespace = self.connect_to_outlook()
            logger.info("Successfully connected to Outlook")
        except Exception as e:
            logger.error(f"Failed to connect to Outlook: {e}")
            raise
    
    def _get_folder_by_name(self, folder_name: str):
        """Get folder by name (inbox, sent, drafts, etc.)."""
        folder_mapping = {
            "inbox": INBOX,
            "sent": SENT_ITEMS,
            "sentitems": SENT_ITEMS,
            "drafts": DRAFTS,
            "deleted": DELETED_ITEMS,
            "outbox": OUTBOX
        }
        
        folder_id = folder_mapping.get(folder_name.lower(), INBOX)
        return self.namespace.GetDefaultFolder(folder_id)
    
    def is_available(self) -> bool:
        """Check if the Outlook COM interface is available and connected."""
        return WINDOWS_COM_AVAILABLE and self.outlook is not None and self.namespace is not None
    
    def _check_availability(self):
        """Check if Outlook is available and raise an error if not."""
        if not WINDOWS_COM_AVAILABLE:
            current_platform = platform.system()
            if current_platform == "Linux" and _is_wsl():
                raise Exception(
                    "Windows COM interface not available in WSL. "
                    "Please install pywin32: pip install pywin32. "
                    "Note: COM access from WSL may require additional configuration."
                )
            elif current_platform == "Windows":
                raise Exception(
                    "Windows COM interface not available. "
                    "Please install pywin32: pip install pywin32"
                )
            else:
                raise Exception(
                    f"Windows COM interface not available on {current_platform}. "
                    "This server requires Windows with Outlook installed."
                )
        if not self.outlook or not self.namespace:
            raise Exception("Not connected to Outlook. Please ensure Outlook is running and try again.")
    
    async def get_emails(self, folder: str = "inbox", count: int = 20, skip: int = 0) -> List[Dict[str, Any]]:
        """Get emails from a specific folder."""
        self._check_availability()
        
        try:
            folder_obj = self._get_folder_by_name(folder)
            messages = folder_obj.Items
            messages.Sort("[ReceivedTime]", True)  # Sort by received time, newest first
            
            emails = []
            message_count = messages.Count
            start_index = skip + 1  # COM collections are 1-indexed
            end_index = min(start_index + count, message_count + 1)
            
            for i in range(start_index, end_index):
                try:
                    message = messages.Item(i)
                    
                    # Get sender information
                    sender_address = ""
                    sender_name = ""
                    if hasattr(message, 'SenderEmailAddress'):
                        sender_address = message.SenderEmailAddress or ""
                    if hasattr(message, 'SenderName'):
                        sender_name = message.SenderName or ""
                    
                    # Get received time
                    received_time = ""
                    if hasattr(message, 'ReceivedTime'):
                        received_time = message.ReceivedTime.strftime("%Y-%m-%d %H:%M:%S")
                    
                    emails.append({
                        "id": getattr(message, 'EntryID', ''),
                        "subject": getattr(message, 'Subject', ''),
                        "sender": sender_address,
                        "sender_name": sender_name,
                        "received_date": received_time,
                        "is_read": getattr(message, 'UnRead', True) == False,
                        "importance": self._get_importance_text(getattr(message, 'Importance', 1)),
                        "body_preview": getattr(message, 'Body', '')[:200] if hasattr(message, 'Body') else '',
                        "size": getattr(message, 'Size', 0)
                    })
                except Exception as e:
                    logger.warning(f"Error processing email at index {i}: {e}")
                    continue
            
            return emails
            
        except Exception as e:
            logger.error(f"Error getting emails from {folder}: {e}")
            raise
    
    def _get_importance_text(self, importance_level):
        """Convert Outlook importance level to text."""
        importance_map = {0: "low", 1: "normal", 2: "high"}
        return importance_map.get(importance_level, "normal")
    
    async def send_email(self, to_recipients: List[str], subject: str, body: str, 
                        cc_recipients: List[str] = None, bcc_recipients: List[str] = None) -> Dict[str, Any]:
        """Send an email."""
        self._check_availability()
        
        try:
            mail_item = self.outlook.CreateItem(MAIL_ITEM)
            
            mail_item.To = "; ".join(to_recipients)
            if cc_recipients:
                mail_item.CC = "; ".join(cc_recipients)
            if bcc_recipients:
                mail_item.BCC = "; ".join(bcc_recipients)
            
            mail_item.Subject = subject
            mail_item.Body = body
            
            mail_item.Send()
            
            return {"status": "sent", "message": "Email sent successfully"}
            
        except Exception as e:
            logger.error(f"Error sending email: {e}")
            raise
    
    async def get_calendar_events(self, days_ahead: int = 7) -> List[Dict[str, Any]]:
        """Get calendar events for the next specified days."""
        self._check_availability()
        
        try:
            calendar_folder = self.namespace.GetDefaultFolder(9)  # Calendar folder
            start_date = datetime.now()
            end_date = start_date + timedelta(days=days_ahead)
            
            # Build filter for date range
            filter_str = f"[Start] >= '{start_date.strftime('%m/%d/%Y')}' AND [Start] < '{end_date.strftime('%m/%d/%Y')}'"
            
            appointments = calendar_folder.Items
            appointments.IncludeRecurrences = True
            appointments.Sort("[Start]")
            
            filtered_appointments = appointments.Restrict(filter_str)
            
            events = []
            for appointment in filtered_appointments:
                try:
                    # Get attendees
                    attendees = []
                    if hasattr(appointment, 'Recipients'):
                        for recipient in appointment.Recipients:
                            attendees.append(getattr(recipient, 'Name', ''))
                    
                    events.append({
                        "id": getattr(appointment, 'EntryID', ''),
                        "subject": getattr(appointment, 'Subject', ''),
                        "start": appointment.Start.strftime("%Y-%m-%d %H:%M:%S") if hasattr(appointment, 'Start') else '',
                        "end": appointment.End.strftime("%Y-%m-%d %H:%M:%S") if hasattr(appointment, 'End') else '',
                        "location": getattr(appointment, 'Location', ''),
                        "attendees": attendees,
                        "body": getattr(appointment, 'Body', '')[:200],
                        "is_all_day": getattr(appointment, 'AllDayEvent', False)
                    })
                except Exception as e:
                    logger.warning(f"Error processing calendar event: {e}")
                    continue
            
            return events
            
        except Exception as e:
            logger.error(f"Error getting calendar events: {e}")
            raise
    
    async def create_calendar_event(self, subject: str, start_time: str, end_time: str,
                                   location: str = None, attendees: List[str] = None, body: str = None) -> Dict[str, Any]:
        """Create a new calendar event."""
        self._check_availability()
        
        try:
            appointment = self.outlook.CreateItem(APPOINTMENT_ITEM)
            
            appointment.Subject = subject
            appointment.Start = datetime.fromisoformat(start_time.replace('Z', '+00:00'))
            appointment.End = datetime.fromisoformat(end_time.replace('Z', '+00:00'))
            
            if location:
                appointment.Location = location
            
            if body:
                appointment.Body = body
            
            if attendees:
                for attendee in attendees:
                    appointment.Recipients.Add(attendee)
                appointment.Recipients.ResolveAll()
            
            appointment.Save()
            
            return {"id": appointment.EntryID, "status": "created"}
            
        except Exception as e:
            logger.error(f"Error creating calendar event: {e}")
            raise
    
    async def get_contacts(self, count: int = 50) -> List[Dict[str, Any]]:
        """Get contacts from address book."""
        self._check_availability()
        
        try:
            contacts_folder = self.namespace.GetDefaultFolder(10)  # Contacts folder
            contacts_items = contacts_folder.Items
            contacts_items.Sort("[LastName]")
            
            contacts = []
            contact_count = min(count, contacts_items.Count)
            
            for i in range(1, contact_count + 1):
                try:
                    contact = contacts_items.Item(i)
                    
                    # Get email addresses
                    emails = []
                    for attr in ['Email1Address', 'Email2Address', 'Email3Address']:
                        email = getattr(contact, attr, '')
                        if email:
                            emails.append(email)
                    
                    # Get phone numbers
                    phones = []
                    for attr in ['BusinessTelephoneNumber', 'HomeTelephoneNumber', 'MobileTelephoneNumber']:
                        phone = getattr(contact, attr, '')
                        if phone:
                            phones.append(phone)
                    
                    contacts.append({
                        "id": getattr(contact, 'EntryID', ''),
                        "display_name": getattr(contact, 'FullName', ''),
                        "first_name": getattr(contact, 'FirstName', ''),
                        "last_name": getattr(contact, 'LastName', ''),
                        "emails": emails,
                        "phones": phones,
                        "company": getattr(contact, 'CompanyName', ''),
                        "job_title": getattr(contact, 'JobTitle', ''),
                        "department": getattr(contact, 'Department', '')
                    })
                except Exception as e:
                    logger.warning(f"Error processing contact at index {i}: {e}")
                    continue
            
            return contacts
            
        except Exception as e:
            logger.error(f"Error getting contacts: {e}")
            raise
    
    async def create_contact(self, display_name: str, email: str = None, phone: str = None, company: str = None) -> Dict[str, Any]:
        """Create a new contact."""
        self._check_availability()
        
        try:
            contact_item = self.outlook.CreateItem(CONTACT_ITEM)
            
            # Split display name into first and last name
            name_parts = display_name.split(' ', 1)
            contact_item.FirstName = name_parts[0]
            if len(name_parts) > 1:
                contact_item.LastName = name_parts[1]
            
            contact_item.FullName = display_name
            
            if email:
                contact_item.Email1Address = email
            
            if phone:
                contact_item.BusinessTelephoneNumber = phone
            
            if company:
                contact_item.CompanyName = company
            
            contact_item.Save()
            
            return {"id": contact_item.EntryID, "status": "created"}
            
        except Exception as e:
            logger.error(f"Error creating contact: {e}")
            raise

# Initialize the Outlook client
outlook_client = None

# Helper functions for URI building
def build_email_uri(email_id: str) -> str:
    """Build an email URI."""
    return f"{EMAIL_SCHEME}://message/{email_id}"

def build_calendar_uri(event_id: str) -> str:
    """Build a calendar event URI."""
    return f"{CALENDAR_SCHEME}://event/{event_id}"

def build_contact_uri(contact_id: str) -> str:
    """Build a contact URI."""
    return f"{CONTACT_SCHEME}://person/{contact_id}"

@server.list_resources()
async def handle_list_resources() -> list[types.Resource]:
    """
    List available Outlook resources.
    Each resource is exposed with a custom URI scheme.
    """
    if not outlook_client:
        return []
    
    resources = []
    
    try:
        # Add recent emails
        emails = await outlook_client.get_emails(count=10)
        for email in emails:
            resources.append(
                types.Resource(
                    uri=AnyUrl(build_email_uri(email["id"])),
                    name=f"Email: {email['subject']}",
                    description=f"From: {email['sender']} | {email['received_date']}",
                    mimeType="text/plain",
                )
            )
    except Exception as e:
        logger.error(f"Error fetching emails for resources: {e}")
    
    try:
        # Add upcoming calendar events
        events = await outlook_client.get_calendar_events(days_ahead=7)
        for event in events:
            resources.append(
                types.Resource(
                    uri=AnyUrl(build_calendar_uri(event["id"])),
                    name=f"Event: {event['subject']}",
                    description=f"Start: {event['start']} | Location: {event.get('location', 'No location')}",
                    mimeType="text/plain",
                )
            )
    except Exception as e:
        logger.error(f"Error fetching calendar events for resources: {e}")
    
    try:
        # Add recent contacts
        contacts = await outlook_client.get_contacts(count=20)
        for contact in contacts:
            email_str = ', '.join(contact['emails']) if contact['emails'] else "No email"
            resources.append(
                types.Resource(
                    uri=AnyUrl(build_contact_uri(contact["id"])),
                    name=f"Contact: {contact['display_name']}",
                    description=f"Email: {email_str}",
                    mimeType="text/plain",
                )
            )
    except Exception as e:
        logger.error(f"Error fetching contacts for resources: {e}")
    
    return resources

@server.read_resource()
async def handle_read_resource(uri: AnyUrl) -> str:
    """
    Read content from Outlook resources based on the URI.
    """
    uri_str = str(uri)
    parsed = urlparse(uri_str)
    
    try:
        if parsed.scheme == EMAIL_SCHEME:
            return f"Email resource: {parsed.path}\nTo get full email content, use the get-emails tool."
            
        elif parsed.scheme == CALENDAR_SCHEME:
            return f"Calendar event resource: {parsed.path}\nTo get full event details, use the get-calendar-events tool."
            
        elif parsed.scheme == CONTACT_SCHEME:
            return f"Contact resource: {parsed.path}\nTo get full contact details, use the get-contacts tool."
            
        else:
            raise ValueError(f"Unsupported URI scheme: {parsed.scheme}")
            
    except Exception as e:
        logger.error(f"Error reading resource {uri_str}: {e}")
        return f"Error: Could not read resource: {str(e)}"

@server.list_prompts()
async def handle_list_prompts() -> list[types.Prompt]:
    """
    List available prompts for Outlook operations.
    Each prompt can have optional arguments to customize its behavior.
    """
    return [
        types.Prompt(
            name="summarize-emails",
            description="Creates a summary of recent emails",
            arguments=[
                types.PromptArgument(
                    name="folder",
                    description="Email folder to summarize (inbox, sent, etc.)",
                    required=False,
                ),
                types.PromptArgument(
                    name="count",
                    description="Number of emails to include in summary",
                    required=False,
                )
            ],
        ),
        types.Prompt(
            name="schedule-summary",
            description="Creates a summary of upcoming calendar events",
            arguments=[
                types.PromptArgument(
                    name="days",
                    description="Number of days ahead to include",
                    required=False,
                )
            ],
        ),
        types.Prompt(
            name="compose-email",
            description="Helps compose a professional email",
            arguments=[
                types.PromptArgument(
                    name="purpose",
                    description="Purpose of the email (meeting request, follow-up, etc.)",
                    required=True,
                ),
                types.PromptArgument(
                    name="tone",
                    description="Tone of the email (formal, casual, urgent)",
                    required=False,
                )
            ],
        ),
    ]

@server.get_prompt()
async def handle_get_prompt(
    name: str, arguments: dict[str, str] | None
) -> types.GetPromptResult:
    """
    Generate prompts for Outlook operations.
    """
    if arguments is None:
        arguments = {}
        
    if name == "summarize-emails":
        folder = arguments.get("folder", "inbox")
        count = int(arguments.get("count", "10"))
        
        if not outlook_client:
            raise ValueError("Outlook client not initialized")
        
        try:
            emails = await outlook_client.get_emails(folder=folder, count=count)
            
            email_list = ""
            for email in emails:
                status = "Read" if email["is_read"] else "Unread"
                email_list += f"- [{status}] From: {email['sender']}\n"
                email_list += f"  Subject: {email['subject']}\n"
                email_list += f"  Received: {email['received_date']}\n"
                email_list += f"  Preview: {email['body_preview'][:100]}...\n\n"
            
            return types.GetPromptResult(
                description=f"Summarize {count} emails from {folder}",
                messages=[
                    types.PromptMessage(
                        role="user",
                        content=types.TextContent(
                            type="text",
                            text=f"Please summarize the following {count} emails from {folder}:\n\n{email_list}"
                        ),
                    )
                ],
            )
        except Exception as e:
            logger.error(f"Error creating email summary prompt: {e}")
            raise ValueError(f"Could not fetch emails: {str(e)}")
            
    elif name == "schedule-summary":
        days = int(arguments.get("days", "7"))
        
        if not outlook_client:
            raise ValueError("Outlook client not initialized")
        
        try:
            events = await outlook_client.get_calendar_events(days_ahead=days)
            
            event_list = ""
            for event in events:
                event_list += f"- {event['subject']}\n"
                event_list += f"  Time: {event['start']} to {event['end']}\n"
                event_list += f"  Location: {event.get('location', 'No location')}\n"
                if event.get('attendees'):
                    event_list += f"  Attendees: {', '.join(event['attendees'])}\n"
                event_list += "\n"
            
            return types.GetPromptResult(
                description=f"Summarize calendar for next {days} days",
                messages=[
                    types.PromptMessage(
                        role="user",
                        content=types.TextContent(
                            type="text",
                            text=f"Please summarize my calendar for the next {days} days:\n\n{event_list}"
                        ),
                    )
                ],
            )
        except Exception as e:
            logger.error(f"Error creating schedule summary prompt: {e}")
            raise ValueError(f"Could not fetch calendar events: {str(e)}")
            
    elif name == "compose-email":
        purpose = arguments.get("purpose")
        tone = arguments.get("tone", "professional")
        
        if not purpose:
            raise ValueError("Missing required argument: purpose")
            
        return types.GetPromptResult(
            description=f"Compose email for {purpose}",
            messages=[
                types.PromptMessage(
                    role="user",
                    content=types.TextContent(
                        type="text",
                        text=f"Please help me compose a {tone} email for the following purpose: {purpose}\n\n"
                             f"Please provide a well-structured email with appropriate subject line, greeting, body, and closing."
                    ),
                )
            ],
        )
    else:
        raise ValueError(f"Unknown prompt: {name}")

@server.list_tools()
async def handle_list_tools() -> list[types.Tool]:
    """
    List available tools for Outlook operations.
    Each tool specifies its arguments using JSON Schema validation.
    """
    return [
        types.Tool(
            name="get-emails",
            description="Get emails from a specific folder",
            inputSchema={
                "type": "object",
                "properties": {
                    "folder": {
                        "type": "string",
                        "description": "Email folder (inbox, sent, drafts, etc.)",
                        "default": "inbox"
                    },
                    "count": {
                        "type": "integer",
                        "description": "Number of emails to retrieve",
                        "default": 20
                    },
                    "skip": {
                        "type": "integer", 
                        "description": "Number of emails to skip",
                        "default": 0
                    }
                }
            },
        ),
        types.Tool(
            name="send-email",
            description="Send an email",
            inputSchema={
                "type": "object",
                "properties": {
                    "to": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "List of recipient email addresses"
                    },
                    "subject": {"type": "string", "description": "Email subject"},
                    "body": {"type": "string", "description": "Email body (HTML format)"},
                    "cc": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "List of CC email addresses"
                    },
                    "bcc": {
                        "type": "array", 
                        "items": {"type": "string"},
                        "description": "List of BCC email addresses"
                    }
                },
                "required": ["to", "subject", "body"]
            },
        ),
        types.Tool(
            name="get-calendar-events",
            description="Get upcoming calendar events",
            inputSchema={
                "type": "object",
                "properties": {
                    "days_ahead": {
                        "type": "integer",
                        "description": "Number of days ahead to look for events",
                        "default": 7
                    }
                }
            },
        ),
        types.Tool(
            name="create-calendar-event",
            description="Create a new calendar event",
            inputSchema={
                "type": "object",
                "properties": {
                    "subject": {"type": "string", "description": "Event subject/title"},
                    "start_time": {"type": "string", "description": "Start time (ISO format)"},
                    "end_time": {"type": "string", "description": "End time (ISO format)"},
                    "location": {"type": "string", "description": "Event location"},
                    "attendees": {
                        "type": "array",
                        "items": {"type": "string"},
                        "description": "List of attendee email addresses"
                    },
                    "body": {"type": "string", "description": "Event description"}
                },
                "required": ["subject", "start_time", "end_time"]
            },
        ),
        types.Tool(
            name="get-contacts",
            description="Get contacts from address book",
            inputSchema={
                "type": "object",
                "properties": {
                    "count": {
                        "type": "integer",
                        "description": "Number of contacts to retrieve",
                        "default": 50
                    }
                }
            },
        ),
        types.Tool(
            name="create-contact",
            description="Create a new contact",
            inputSchema={
                "type": "object",
                "properties": {
                    "display_name": {"type": "string", "description": "Contact display name"},
                    "email": {"type": "string", "description": "Contact email address"},
                    "phone": {"type": "string", "description": "Contact phone number"},
                    "company": {"type": "string", "description": "Contact company name"}
                },
                "required": ["display_name"]
            },
        )
    ]

@server.call_tool()
async def handle_call_tool(
    name: str, arguments: dict | None
) -> list[types.TextContent | types.ImageContent | types.EmbeddedResource]:
    """
    Handle tool execution requests for Outlook operations.
    """
    if not arguments:
        arguments = {}
    
    if not outlook_client:
        return [
            types.TextContent(
                type="text",
                text="Error: Outlook client not initialized. Please check your environment variables.",
            )
        ]
        
    try:
        if name == "get-emails":
            folder = arguments.get("folder", "inbox")
            count = arguments.get("count", 20)
            skip = arguments.get("skip", 0)
            
            emails = await outlook_client.get_emails(folder=folder, count=count, skip=skip)
            
            if not emails:
                return [
                    types.TextContent(
                        type="text",
                        text=f"No emails found in {folder} folder.",
                    )
                ]
            
            response = f"Emails from {folder} folder:\n\n"
            for email in emails:
                status = "📭" if email["is_read"] else "📬"
                importance = "❗" if email["importance"] == "high" else ""
                response += f"{status} {importance} **{email['subject']}**\n"
                response += f"From: {email['sender']}\n"
                response += f"Received: {email['received_date']}\n"
                response += f"Preview: {email['body_preview'][:150]}...\n\n"
            
            return [
                types.TextContent(
                    type="text",
                    text=response
                )
            ]
            
        elif name == "send-email":
            to_recipients = arguments.get("to", [])
            subject = arguments.get("subject", "")
            body = arguments.get("body", "")
            cc_recipients = arguments.get("cc", [])
            bcc_recipients = arguments.get("bcc", [])
            
            if not to_recipients or not subject or not body:
                raise ValueError("Missing required arguments: to, subject, and body")
                
            result = await outlook_client.send_email(
                to_recipients=to_recipients,
                subject=subject,
                body=body,
                cc_recipients=cc_recipients,
                bcc_recipients=bcc_recipients
            )
            
            return [
                types.TextContent(
                    type="text",
                    text=f"Email sent successfully!\nTo: {', '.join(to_recipients)}\nSubject: {subject}",
                )
            ]
            
        elif name == "get-calendar-events":
            days_ahead = arguments.get("days_ahead", 7)
            
            events = await outlook_client.get_calendar_events(days_ahead=days_ahead)
            
            if not events:
                return [
                    types.TextContent(
                        type="text",
                        text=f"No calendar events found for the next {days_ahead} days.",
                    )
                ]
            
            response = f"Calendar events for the next {days_ahead} days:\n\n"
            for event in events:
                response += f"📅 **{event['subject']}**\n"
                response += f"📍 Location: {event.get('location', 'No location')}\n"
                response += f"🕐 Time: {event['start']} to {event['end']}\n"
                if event.get('attendees'):
                    response += f"👥 Attendees: {', '.join(event['attendees'])}\n"
                response += "\n"
            
            return [
                types.TextContent(
                    type="text",
                    text=response
                )
            ]
            
        elif name == "create-calendar-event":
            subject = arguments.get("subject")
            start_time = arguments.get("start_time")
            end_time = arguments.get("end_time")
            location = arguments.get("location")
            attendees = arguments.get("attendees", [])
            body = arguments.get("body")
            
            if not subject or not start_time or not end_time:
                raise ValueError("Missing required arguments: subject, start_time, and end_time")
                
            event = await outlook_client.create_calendar_event(
                subject=subject,
                start_time=start_time,
                end_time=end_time,
                location=location,
                attendees=attendees,
                body=body
            )
            
            return [
                types.TextContent(
                    type="text",
                    text=f"Calendar event created successfully!\nSubject: {subject}\nTime: {start_time} to {end_time}",
                )
            ]
            
        elif name == "get-contacts":
            count = arguments.get("count", 50)
            
            contacts = await outlook_client.get_contacts(count=count)
            
            if not contacts:
                return [
                    types.TextContent(
                        type="text",
                        text="No contacts found.",
                    )
                ]
            
            response = f"Contacts (showing {len(contacts)}):\n\n"
            for contact in contacts:
                response += f"👤 **{contact['display_name']}**\n"
                if contact['emails']:
                    response += f"📧 Email: {', '.join(contact['emails'])}\n"
                if contact['phones']:
                    response += f"📞 Phone: {', '.join(contact['phones'])}\n"
                if contact['company']:
                    response += f"🏢 Company: {contact['company']}\n"
                response += "\n"
            
            return [
                types.TextContent(
                    type="text",
                    text=response
                )
            ]
            
        elif name == "create-contact":
            display_name = arguments.get("display_name")
            email = arguments.get("email")
            phone = arguments.get("phone")
            company = arguments.get("company")
            
            if not display_name:
                raise ValueError("Missing required argument: display_name")
                
            contact = await outlook_client.create_contact(
                display_name=display_name,
                email=email,
                phone=phone,
                company=company
            )
            
            return [
                types.TextContent(
                    type="text",
                    text=f"Contact created successfully!\nName: {display_name}\nEmail: {email or 'N/A'}",
                )
            ]
            
        else:
            raise ValueError(f"Unknown tool: {name}")
            
    except Exception as e:
        logger.error(f"Error executing tool {name}: {e}")
        return [
            types.TextContent(
                type="text",
                text=f"Error executing {name}: {str(e)}",
            )
        ]

async def main():
    """Run the Outlook MCP server."""
    global outlook_client
    
    # Initialize Outlook client
    try:
        outlook_client = OutlookClient()
        logger.info("Outlook client initialized successfully")
    except Exception as e:
        logger.warning(f"Failed to initialize Outlook client: {e}")
        logger.warning("Make sure to set OUTLOOK_TENANT_ID, OUTLOOK_CLIENT_ID, and authentication credentials")
    
    # Run the server using stdin/stdout streams
    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream,
            write_stream,
            InitializationOptions(
                server_name="outlook-mcp-server-windows-com",
                server_version="0.1.1",
                capabilities=server.get_capabilities(
                    notification_options=NotificationOptions(),
                    experimental_capabilities={},
                ),
            ),
        )