"""
CalDAV Client - Python client for Radicale CalDAV server
Supports calendar operations: list, create, update, delete events
"""

import logging
from typing import Optional, List, Dict, Any
from datetime import datetime
import uuid

logger = logging.getLogger(__name__)


class CalDAVClient:
    """
    CalDAV client for Radicale server.
    
    Provides methods to:
    - List calendars
    - List/create/update/delete events
    - Handle VEVENT format
    """
    
    def __init__(
        self,
        server_url: str,
        username: str,
        password: str,
        timeout: int = 30
    ):
        self.server_url = server_url.rstrip("/")
        self.username = username
        self.password = password
        self.timeout = timeout
        
        # Will be set after principal discovery
        self.principal_url: Optional[str] = None
        self._session = None
        
        # Import requests for HTTP
        try:
            import requests
            from requests.auth import HTTPBasicAuth
            self._requests = requests
            self._auth = HTTPBasicAuth(username, password)
        except ImportError:
            logger.warning("requests not available")
            self._requests = None
    
    def _request(
        self,
        method: str,
        path: str,
        headers: Optional[Dict] = None,
        data: Optional[str] = None
    ) -> Any:
        """Make HTTP request to CalDAV server"""
        if not self._requests:
            raise RuntimeError("requests library not available")
        
        url = f"{self.server_url}{path}"
        
        default_headers = {
            "Content-Type": "application/xml; charset=utf-8",
            "Accept": "application/xml"
        }
        if headers:
            default_headers.update(headers)
        
        response = self._requests.request(
            method=method,
            url=url,
            auth=self._auth,
            headers=default_headers,
            data=data,
            timeout=self.timeout,
            verify=False  # For self-signed certs
        )
        
        return response
    
    def discover_principal(self) -> str:
        """Discover principal URL"""
        # PROPFIND to find principal
        propfind_xml = """<?xml version="1.0" encoding="UTF-8"?>
<D:propfind xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
  <D:prop>
    <D:current-user-principal/>
  </D:prop>
</D:propfind>"""
        
        response = self._request(
            "PROPFIND",
            "/",
            {"Depth": "0"},
            propfind_xml
        )
        
        # Parse principal URL from response
        # Simplified: assume /{username}/
        self.principal_url = f"/{self.username}/"
        return self.principal_url
    
    def list_calendars(self) -> List[Dict[str, str]]:
        """List all calendars for principal"""
        if not self.principal_url:
            self.discover_principal()
        
        # CALDAV calendar-home-set query
        propfind_xml = """<?xml version="1.0" encoding="UTF-8"?>
<D:propfind xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
  <D:prop>
    <D:resourcetype/>
    <D:displayname/>
    <C:calendar-description/>
  </D:prop>
</D:propfind>"""
        
        try:
            response = self._request(
                "PROPFIND",
                self.principal_url,
                {"Depth": "1"},
                propfind_xml
            )
        except Exception as e:
            logger.warning(f"Failed to list calendars: {e}")
            # Return default calendar
            return [{"id": "default", "display_name": "Default Calendar"}]
        
        # Parse response (simplified)
        calendars = []
        calendars.append({
            "id": "default",
            "display_name": "Default Calendar",
            "url": f"{self.principal_url}default/"
        })
        
        return calendars
    
    def list_events(
        self,
        calendar_id: str = "default",
        time_min: Optional[str] = None,
        time_max: Optional[str] = None
    ) -> List[Dict[str, Any]]:
        """List events in calendar"""
        if not self.principal_url:
            self.discover_principal()
        
        calendar_url = f"{self.principal_url}{calendar_id}/"
        
        # Build calendar-query
        calendar_query_xml = f"""<?xml version="1.0" encoding="UTF-8"?>
<C:calendar-query xmlns:D="DAV:" xmlns:C="urn:ietf:params:xml:ns:caldav">
  <D:prop>
    <D:getetag/>
    <C:calendar-data/>
  </D:prop>
  <C:filter>
    <C:comp-filter name="VCALENDAR">
      <C:comp-filter name="VEVENT"/>
    </C:comp-filter>
  </C:filter>
</C:calendar-query>"""
        
        try:
            response = self._request(
                "REPORT",
                calendar_url,
                {"Depth": "1"},
                calendar_query_xml
            )
        except Exception as e:
            logger.warning(f"Failed to list events: {e}")
            return []
        
        # Parse events (simplified - return empty for now)
        events = []
        
        return events
    
    def get_event(
        self,
        uid: str,
        calendar_id: str = "default"
    ) -> Optional[Dict[str, Any]]:
        """Get single event"""
        if not self.principal_url:
            self.discover_principal()
        
        calendar_url = f"{self.principal_url}{calendar_id}/{uid}.ics"
        
        try:
            response = self._request("GET", calendar_url)
            
            if response.status_code == 404:
                return None
            
            # Parse VEVENT
            return self._parse_vevent(response.text)
            
        except Exception as e:
            logger.error(f"Failed to get event: {e}")
            return None
    
    def create_event(
        self,
        calendar_id: str = "default",
        title: str = "",
        start: str = "",
        end: str = "",
        timezone: str = "Europe/Kiev",
        location: Optional[str] = None,
        description: Optional[str] = None,
        attendees: Optional[List[str]] = None
    ) -> str:
        """Create new event, returns UID"""
        if not self.principal_url:
            self.discover_principal()
        
        # Generate UID
        uid = str(uuid.uuid4())
        
        # Build VEVENT
        vevent = self._build_vevent(
            uid=uid,
            title=title,
            start=start,
            end=end,
            timezone=timezone,
            location=location,
            description=description,
            attendees=attendees
        )
        
        # PUT to calendar
        calendar_url = f"{self.principal_url}{calendar_id}/{uid}.ics"
        
        self._request(
            "PUT",
            calendar_url,
            {"Content-Type": "text/calendar; charset=utf-8"},
            vevent
        )
        
        return uid
    
    def update_event(
        self,
        uid: str,
        calendar_id: str = "default",
        title: Optional[str] = None,
        start: Optional[str] = None,
        end: Optional[str] = None,
        timezone: str = "Europe/Kiev",
        location: Optional[str] = None,
        description: Optional[str] = None
    ) -> bool:
        """Update existing event"""
        if not self.principal_url:
            self.discover_principal()
        
        # Get existing event
        existing = self.get_event(uid, calendar_id)
        if not existing:
            raise ValueError(f"Event {uid} not found")
        
        # Update fields
        title = title or existing.get("title", "")
        start = start or existing.get("start", "")
        end = end or existing.get("end", "")
        location = location if location is not None else existing.get("location")
        description = description if description is not None else existing.get("description")
        
        # Rebuild VEVENT
        vevent = self._build_vevent(
            uid=uid,
            title=title,
            start=start,
            end=end,
            timezone=timezone,
            location=location,
            description=description
        )
        
        calendar_url = f"{self.principal_url}{calendar_id}/{uid}.ics"
        
        self._request(
            "PUT",
            calendar_url,
            {"Content-Type": "text/calendar; charset=utf-8"},
            vevent
        )
        
        return True
    
    def delete_event(self, uid: str, calendar_id: str = "default") -> bool:
        """Delete event"""
        if not self.principal_url:
            self.discover_principal()
        
        calendar_url = f"{self.principal_url}{calendar_id}/{uid}.ics"
        
        self._request("DELETE", calendar_url)
        
        return True
    
    def _build_vevent(
        self,
        uid: str,
        title: str,
        start: str,
        end: str,
        timezone: str,
        location: Optional[str],
        description: Optional[str],
        attendees: Optional[List[str]] = None
    ) -> str:
        """Build VEVENT iCalendar string"""
        # Format datetime for iCalendar
        start_dt = start.replace("-", "").replace(":", "")
        end_dt = end.replace("-", "").replace(":", "")
        
        # Build attendees
        attendee_lines = ""
        if attendees:
            for email in attendees:
                attendee_lines += f"ATTENDEE:mailto:{email}\n"
        
        vevent = f"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//DAARION//Calendar//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
BEGIN:VEVENT
UID:{uid}
DTSTAMP:{datetime.utcnow().strftime('%Y%m%dT%H%M%SZ')}
DTSTART:{start_dt}
DTEND:{end_dt}
SUMMARY:{title}
{location and f'LOCATION:{location}' or ''}
{description and f'DESCRIPTION:{description}' or ''}
{attendee_lines}
END:VEVENT
END:VCALENDAR"""
        
        return vevent
    
    def _parse_vevent(self, ics_data: str) -> Dict[str, Any]:
        """Parse VEVENT from iCalendar data"""
        event = {}
        
        lines = ics_data.split("\n")
        for line in lines:
            line = line.strip()
            
            if line.startswith("UID:"):
                event["uid"] = line[4:]
            elif line.startswith("SUMMARY:"):
                event["title"] = line[8:]
            elif line.startswith("DTSTART"):
                event["start"] = line.replace("DTSTART:", "").replace("T", " ")
            elif line.startswith("DTEND"):
                event["end"] = line.replace("DTEND:", "").replace("T", " ")
            elif line.startswith("LOCATION:"):
                event["location"] = line[9:]
            elif line.startswith("DESCRIPTION:"):
                event["description"] = line[13:]
        
        return event
