"""CalDAV client for calendar operations."""
import os
from datetime import datetime, timedelta
from typing import List, Dict, Optional, Tuple
import uuid

try:
    import caldav
    from caldav.elements import dav
    CALDAV_AVAILABLE = True
except ImportError:
    caldav = None
    dav = None
    CALDAV_AVAILABLE = False


class CalendarClient:
    """Client for CalDAV calendar operations."""
    
    def __init__(self, url: str = None, username: str = None, password: str = None):
        """
        Inicjalizacja klienta CalDAV.
        
        Args:
            url: CalDAV server URL (np. https://caldav.example.com/calendars/)
            username: Username for authentication
            password: Password for authentication
        """
        if not CALDAV_AVAILABLE:
            print("⚠️  caldav library not available - calendar integration disabled")
            self.client = None
            self.calendar = None
            return
        
        self.url = url or os.getenv('CALDAV_URL')
        self.username = username or os.getenv('CALDAV_USERNAME')
        self.password = password or os.getenv('CALDAV_PASSWORD')
        self.calendar_name = os.getenv('CALDAV_CALENDAR', 'Calendar')
        
        if not all([self.url, self.username, self.password]):
            print("⚠️  CalDAV credentials not configured - calendar integration disabled")
            self.client = None
            self.calendar = None
            return
        
        try:
            self.client = caldav.DAVClient(
                url=self.url,
                username=self.username,
                password=self.password
            )
            principal = self.client.principal()
            calendars = principal.calendars()
            
            # Find target calendar
            self.calendar = None
            for cal in calendars:
                if self.calendar_name.lower() in cal.name.lower():
                    self.calendar = cal
                    break
            
            if not self.calendar and calendars:
                self.calendar = calendars[0]  # Use first calendar as fallback
            
            if self.calendar:
                print(f"✅ Połączono z kalendarzem: {self.calendar.name}")
            else:
                print("⚠️  Nie znaleziono kalendarza")
                
        except Exception as e:
            print(f"❌ Błąd połączenia z CalDAV: {e}")
            self.client = None
            self.calendar = None
    
    def is_available(self) -> bool:
        """Sprawdza czy klient CalDAV jest dostępny."""
        return CALDAV_AVAILABLE and self.client is not None and self.calendar is not None
    
    def get_events(self, start: datetime, end: datetime) -> List[Dict]:
        """
        Pobiera wydarzenia z kalendarza w danym zakresie.
        
        Args:
            start: Data początkowa
            end: Data końcowa
        
        Returns:
            Lista wydarzeń jako słowniki
        """
        if not self.is_available():
            return []
        
        try:
            events = self.calendar.date_search(start=start, end=end)
            
            result = []
            for event in events:
                try:
                    ical = event.icalendar_component
                    vevent = None
                    for component in ical.walk():
                        if component.name == "VEVENT":
                            vevent = component
                            break
                    
                    if vevent:
                        dtstart = vevent.get('dtstart').dt
                        dtend = vevent.get('dtend').dt
                        
                        # Handle date-only events
                        if not isinstance(dtstart, datetime):
                            dtstart = datetime.combine(dtstart, datetime.min.time())
                        if not isinstance(dtend, datetime):
                            dtend = datetime.combine(dtend, datetime.min.time())
                        
                        result.append({
                            'summary': str(vevent.get('summary', 'No title')),
                            'start': dtstart,
                            'end': dtend,
                            'uid': str(vevent.get('uid', '')),
                            'event': event,
                        })
                except Exception as e:
                    print(f"⚠️  Błąd parsowania wydarzenia: {e}")
                    continue
            
            return result
            
        except Exception as e:
            print(f"❌ Błąd pobierania wydarzeń: {e}")
            return []
    
    def create_event(self, summary: str, start: datetime, end: datetime, 
                    description: str = "", location: str = "") -> Optional[str]:
        """
        Tworzy nowe wydarzenie w kalendarzu.
        
        Args:
            summary: Tytuł wydarzenia
            start: Data i czas rozpoczęcia
            end: Data i czas zakończenia
            description: Opis wydarzenia
            location: Lokalizacja
        
        Returns:
            UID utworzonego wydarzenia lub None w przypadku błędu
        """
        if not self.is_available():
            return None
        
        try:
            # Generate unique UID
            event_uid = str(uuid.uuid4())
            
            # Create iCalendar string
            ical = f"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//LLMass Email Responder//EN
BEGIN:VEVENT
UID:{event_uid}
DTSTAMP:{datetime.utcnow().strftime('%Y%m%dT%H%M%SZ')}
DTSTART:{start.strftime('%Y%m%dT%H%M%S')}
DTEND:{end.strftime('%Y%m%dT%H%M%S')}
SUMMARY:{summary}
DESCRIPTION:{description}
LOCATION:{location}
STATUS:TENTATIVE
END:VEVENT
END:VCALENDAR"""
            
            # Save event to calendar
            self.calendar.save_event(ical)
            
            print(f"✅ Utworzono wydarzenie: {summary} ({start} - {end})")
            return event_uid
            
        except Exception as e:
            print(f"❌ Błąd tworzenia wydarzenia: {e}")
            return None
    
    def delete_event(self, event_uid: str) -> bool:
        """
        Usuwa wydarzenie z kalendarza.
        
        Args:
            event_uid: UID wydarzenia do usunięcia
        
        Returns:
            True jeśli usunięto, False w przypadku błędu
        """
        if not self.is_available():
            return False
        
        try:
            # Find event by UID
            events = self.calendar.events()
            for event in events:
                try:
                    ical = event.icalendar_component
                    for component in ical.walk():
                        if component.name == "VEVENT":
                            uid = str(component.get('uid', ''))
                            if uid == event_uid:
                                event.delete()
                                print(f"✅ Usunięto wydarzenie: {event_uid}")
                                return True
                except Exception:
                    continue
            
            print(f"⚠️  Nie znaleziono wydarzenia: {event_uid}")
            return False
            
        except Exception as e:
            print(f"❌ Błąd usuwania wydarzenia: {e}")
            return False
    
    def find_free_slots(self, duration_minutes: int, days_ahead: int = 7,
                       work_start: str = "09:00", work_end: str = "17:00",
                       exclude_weekends: bool = True) -> List[Tuple[datetime, datetime]]:
        """
        Znajduje wolne sloty w kalendarzu.
        
        Args:
            duration_minutes: Długość spotkania w minutach
            days_ahead: Ile dni do przodu szukać
            work_start: Początek dnia roboczego (HH:MM)
            work_end: Koniec dnia roboczego (HH:MM)
            exclude_weekends: Czy wykluczyć weekendy
        
        Returns:
            Lista tupli (start, end) z wolnymi slotami
        """
        if not self.is_available():
            return []
        
        try:
            now = datetime.now()
            start_date = now.replace(hour=0, minute=0, second=0, microsecond=0)
            end_date = start_date + timedelta(days=days_ahead)
            
            # Get all events in range
            events = self.get_events(start_date, end_date)
            
            # Parse work hours
            work_start_hour, work_start_min = map(int, work_start.split(':'))
            work_end_hour, work_end_min = map(int, work_end.split(':'))
            
            free_slots = []
            
            # Check each day
            for day_offset in range(days_ahead):
                check_date = start_date + timedelta(days=day_offset)
                
                # Skip weekends if requested
                if exclude_weekends and check_date.weekday() >= 5:  # 5=Saturday, 6=Sunday
                    continue
                
                # Skip past days
                if check_date.date() < now.date():
                    continue
                
                # Define work hours for this day
                day_start = check_date.replace(hour=work_start_hour, minute=work_start_min)
                day_end = check_date.replace(hour=work_end_hour, minute=work_end_min)
                
                # Skip if day already passed
                if day_end < now:
                    continue
                
                # Adjust start time if it's today
                if check_date.date() == now.date() and day_start < now:
                    # Round up to next 15 minutes
                    minutes = ((now.minute // 15) + 1) * 15
                    if minutes >= 60:
                        day_start = now.replace(hour=now.hour + 1, minute=0, second=0, microsecond=0)
                    else:
                        day_start = now.replace(minute=minutes, second=0, microsecond=0)
                
                # Get events for this day
                day_events = [e for e in events 
                             if e['start'].date() == check_date.date()]
                
                # Sort by start time
                day_events.sort(key=lambda x: x['start'])
                
                # Find gaps between events
                current_time = day_start
                
                for event in day_events:
                    event_start = event['start']
                    event_end = event['end']
                    
                    # Check if there's a gap before this event
                    gap_duration = (event_start - current_time).total_seconds() / 60
                    if gap_duration >= duration_minutes:
                        # Add free slot
                        slot_end = current_time + timedelta(minutes=duration_minutes)
                        if slot_end <= day_end:
                            free_slots.append((current_time, slot_end))
                    
                    # Move to end of this event
                    current_time = max(current_time, event_end)
                
                # Check if there's time at end of day
                gap_duration = (day_end - current_time).total_seconds() / 60
                if gap_duration >= duration_minutes:
                    slot_end = current_time + timedelta(minutes=duration_minutes)
                    if slot_end <= day_end:
                        free_slots.append((current_time, slot_end))
            
            return free_slots
            
        except Exception as e:
            print(f"❌ Błąd wyszukiwania wolnych slotów: {e}")
            return []
