"""
Aruba Calendar Client using CalDAV protocol.
"""

import caldav
from datetime import datetime, timedelta
from typing import List, Dict, Optional
from icalendar import Calendar, Event as ICalEvent, vCalAddress, vText
import logging

logger = logging.getLogger(__name__)


class ArubaCalendarClient:
    """Client for interacting with Aruba calendar via CalDAV."""
    
    def __init__(self, url: str, username: str, password: str):
        """
        Initialize the Aruba CalDAV client.
        
        Args:
            url: CalDAV server URL (e.g., https://caldav.aruba.it)
            username: Email address for authentication
            password: Account password
        """
        self.url = url
        self.username = username
        self.password = password
        self.client = None
        self.principal = None
        self.calendar = None
        
    def connect(self):
        """Connect to the CalDAV server and get the default calendar."""
        try:
            self.client = caldav.DAVClient(
                url=self.url,
                username=self.username,
                password=self.password
            )
            self.principal = self.client.principal()
            
            # Get calendars
            calendars = self.principal.calendars()
            
            if not calendars:
                logger.warning("No calendars found. Calendar sync may not be enabled.")
                logger.info("To enable: Log into Aruba Webmail → Calendar → 'Sincronizza calendario' → Choose CalDAV")
                raise Exception(
                    "No calendars found on your Aruba account. "
                    "To enable CalDAV sync: Log into Aruba Webmail → Calendar → "
                    "'Sincronizza calendario' → Enable CalDAV synchronization. "
                    "Make sure CALDAV_URL is set correctly (e.g., https://syncdav.aruba.it/calendars/user@domain.com/)"
                )
            
            # Use the first calendar by default
            self.calendar = calendars[0]
            logger.info(f"Connected to calendar: {self.calendar.name}")
            
        except Exception as e:
            logger.error(f"Failed to connect to CalDAV: {e}")
            raise
    
    def disconnect(self):
        """Close the CalDAV connection."""
        self.client = None
        self.principal = None
        self.calendar = None
    
    def __enter__(self):
        """Context manager entry."""
        self.connect()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit."""
        self.disconnect()
    
    def _ensure_calendar_connected(self):
        """Check if calendar is connected and raise descriptive error if not."""
        if not self.calendar:
            raise Exception(
                "Calendar not connected. This could be because: "
                "1) CalDAV sync is not enabled on your Aruba account, "
                "2) CALDAV_URL is not correctly configured. "
                "To enable calendar sync: Log into Aruba Webmail → Calendar → "
                "'Sincronizza calendario' → Enable CalDAV synchronization."
            )
    
    def create_event(
        self,
        summary: str,
        start: datetime,
        end: datetime,
        description: Optional[str] = None,
        location: Optional[str] = None,
        attendees: Optional[List[str]] = None
    ) -> Dict:
        """
        Create a new calendar event.
        
        Args:
            summary: Event title
            start: Start datetime
            end: End datetime
            description: Event description (optional)
            location: Event location (optional)
            attendees: List of attendee email addresses (optional)
        
        Returns:
            Dict with event details including UID
        """
        if not self.calendar:
            self._ensure_calendar_connected()
        
        # Create iCalendar event
        cal = Calendar()
        cal.add('prodid', '-//MCP Aruba Calendar//EN')
        cal.add('version', '2.0')
        
        event = ICalEvent()
        event.add('summary', summary)
        event.add('dtstart', start)
        event.add('dtend', end)
        event.add('dtstamp', datetime.now())
        
        if description:
            event.add('description', description)
        
        if location:
            event.add('location', location)
        
        # Add attendees
        if attendees:
            organizer = vCalAddress(f'MAILTO:{self.username}')
            organizer.params['cn'] = vText(self.username)
            event.add('organizer', organizer)
            
            for attendee_email in attendees:
                attendee = vCalAddress(f'MAILTO:{attendee_email}')
                attendee.params['cn'] = vText(attendee_email)
                attendee.params['ROLE'] = vText('REQ-PARTICIPANT')
                attendee.params['PARTSTAT'] = vText('NEEDS-ACTION')
                attendee.params['RSVP'] = vText('TRUE')
                event.add('attendee', attendee)
        
        cal.add_component(event)
        
        # Save event to calendar
        try:
            caldav_event = self.calendar.save_event(cal.to_ical().decode('utf-8'))
            
            return {
                "success": True,
                "uid": str(event.get('uid', '')),
                "summary": summary,
                "start": start.isoformat(),
                "end": end.isoformat(),
                "url": caldav_event.url if hasattr(caldav_event, 'url') else None
            }
        except Exception as e:
            logger.error(f"Failed to create event: {e}")
            raise
    
    def list_events(
        self,
        start_date: Optional[datetime] = None,
        end_date: Optional[datetime] = None,
        limit: int = 50
    ) -> List[Dict]:
        """
        List calendar events within a date range.
        
        Args:
            start_date: Start date for filtering (default: today)
            end_date: End date for filtering (default: 30 days from now)
            limit: Maximum number of events to return
        
        Returns:
            List of event dictionaries
        """
        if not self.calendar:
            self._ensure_calendar_connected()
        
        # Default date range
        if start_date is None:
            start_date = datetime.now()
        if end_date is None:
            end_date = datetime.now() + timedelta(days=30)
        
        try:
            # Search for events in date range
            events = self.calendar.date_search(start=start_date, end=end_date)
            
            result = []
            for caldav_event in events[:limit]:
                try:
                    ical = Calendar.from_ical(caldav_event.data)
                    
                    for component in ical.walk():
                        if component.name == "VEVENT":
                            event_data = {
                                "uid": str(component.get('uid', '')),
                                "summary": str(component.get('summary', '')),
                                "start": component.get('dtstart').dt.isoformat() if component.get('dtstart') else None,
                                "end": component.get('dtend').dt.isoformat() if component.get('dtend') else None,
                                "description": str(component.get('description', '')),
                                "location": str(component.get('location', '')),
                                "status": str(component.get('status', '')),
                                "organizer": str(component.get('organizer', '')),
                            }
                            
                            # Extract attendees
                            attendees = []
                            for attendee in component.get('attendee', []):
                                if isinstance(attendee, list):
                                    for att in attendee:
                                        attendees.append({
                                            "email": str(att).replace('MAILTO:', ''),
                                            "status": att.params.get('PARTSTAT', 'UNKNOWN')
                                        })
                                else:
                                    attendees.append({
                                        "email": str(attendee).replace('MAILTO:', ''),
                                        "status": attendee.params.get('PARTSTAT', 'UNKNOWN')
                                    })
                            
                            event_data["attendees"] = attendees
                            result.append(event_data)
                            
                except Exception as e:
                    logger.warning(f"Failed to parse event: {e}")
                    continue
            
            return result
            
        except Exception as e:
            logger.error(f"Failed to list events: {e}")
            raise
    
    def get_event_by_uid(self, uid: str) -> Optional[object]:
        """
        Get a CalDAV event object by UID.
        
        Args:
            uid: Event UID
        
        Returns:
            CalDAV event object or None if not found
        """
        if not self.calendar:
            self._ensure_calendar_connected()
        
        try:
            # Search all events and find by UID
            events = self.calendar.events()
            
            for caldav_event in events:
                try:
                    ical = Calendar.from_ical(caldav_event.data)
                    for component in ical.walk():
                        if component.name == "VEVENT":
                            if str(component.get('uid', '')) == uid:
                                return caldav_event
                except Exception as e:
                    logger.warning(f"Failed to parse event: {e}")
                    continue
            
            return None
            
        except Exception as e:
            logger.error(f"Failed to get event: {e}")
            raise
    
    def respond_to_event(
        self,
        event_uid: str,
        response: str,
        comment: Optional[str] = None
    ) -> Dict:
        """
        Respond to a calendar event invitation (accept/decline/tentative).
        
        Args:
            event_uid: UID of the event to respond to
            response: Response status ('ACCEPTED', 'DECLINED', 'TENTATIVE')
            comment: Optional comment for the response
        
        Returns:
            Dict with response status
        """
        if not self.calendar:
            self._ensure_calendar_connected()
        
        if response.upper() not in ['ACCEPTED', 'DECLINED', 'TENTATIVE']:
            raise ValueError("Response must be 'ACCEPTED', 'DECLINED', or 'TENTATIVE'")
        
        try:
            # Get the event
            caldav_event = self.get_event_by_uid(event_uid)
            
            if not caldav_event:
                return {
                    "success": False,
                    "error": f"Event with UID {event_uid} not found"
                }
            
            # Parse the event
            ical = Calendar.from_ical(caldav_event.data)
            
            for component in ical.walk():
                if component.name == "VEVENT":
                    # Update attendee status
                    attendees = component.get('attendee', [])
                    if not isinstance(attendees, list):
                        attendees = [attendees]
                    
                    user_email = f'MAILTO:{self.username}'
                    updated = False
                    
                    for attendee in attendees:
                        if str(attendee).upper() == user_email.upper():
                            attendee.params['PARTSTAT'] = vText(response.upper())
                            if comment:
                                attendee.params['COMMENT'] = vText(comment)
                            updated = True
                            break
                    
                    if not updated:
                        return {
                            "success": False,
                            "error": f"User {self.username} is not an attendee of this event"
                        }
                    
                    # Save updated event
                    caldav_event.data = ical.to_ical()
                    caldav_event.save()
                    
                    return {
                        "success": True,
                        "event_uid": event_uid,
                        "response": response.upper(),
                        "comment": comment
                    }
            
            return {
                "success": False,
                "error": "Event component not found"
            }
            
        except Exception as e:
            logger.error(f"Failed to respond to event: {e}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def delete_event(self, event_uid: str) -> Dict:
        """
        Delete a calendar event.
        
        Args:
            event_uid: UID of the event to delete
        
        Returns:
            Dict with deletion status
        """
        if not self.calendar:
            self._ensure_calendar_connected()
        
        try:
            caldav_event = self.get_event_by_uid(event_uid)
            
            if not caldav_event:
                return {
                    "success": False,
                    "error": f"Event with UID {event_uid} not found"
                }
            
            caldav_event.delete()
            
            return {
                "success": True,
                "event_uid": event_uid
            }
            
        except Exception as e:
            logger.error(f"Failed to delete event: {e}")
            return {
                "success": False,
                "error": str(e)
            }
