"""
Apple iCloud Calendar 서비스 구현
- 통합 서비스 파일 기준: 최대 500줄
- 간결함 원칙: 한 파일에서 모든 Apple 캘린더 기능 제공
"""
import asyncio
import aiohttp
from typing import Dict, List, Any, Optional
from datetime import datetime, timedelta
import logging
from urllib.parse import urljoin
import xml.etree.ElementTree as ET
from base64 import b64encode

from .base import BaseCalendarService, CalendarProvider

logger = logging.getLogger(__name__)


class AppleCalendarService(BaseCalendarService):
    """Apple iCloud 캘린더 서비스 (CalDAV 기반)"""
    
    def __init__(self):
        self.base_url = "https://caldav.icloud.com"
        self.session: Optional[aiohttp.ClientSession] = None
        self.auth_header: Optional[str] = None
        self.principal_url: Optional[str] = None
        self.calendar_home_url: Optional[str] = None
        
    async def authenticate(self, credentials: Dict[str, Any]) -> bool:
        """
        Apple ID 및 앱 전용 암호로 인증
        credentials: {"apple_id": "user@icloud.com", "app_password": "xxxx-xxxx-xxxx-xxxx"}
        """
        try:
            apple_id = credentials.get("apple_id")
            app_password = credentials.get("app_password")
            
            if not apple_id or not app_password:
                logger.error("Apple ID 또는 앱 전용 암호가 누락됨")
                return False
                
            # Basic Auth 헤더 생성
            auth_string = f"{apple_id}:{app_password}"
            auth_bytes = auth_string.encode('utf-8')
            self.auth_header = f"Basic {b64encode(auth_bytes).decode('utf-8')}"
            
            # HTTP 세션 생성
            self.session = aiohttp.ClientSession(
                headers={"Authorization": self.auth_header}
            )
            
            # Principal URL 찾기
            if not await self._discover_principal():
                return False
                
            # Calendar Home URL 찾기  
            if not await self._discover_calendar_home():
                return False
                
            logger.info(f"Apple 캘린더 인증 성공: {apple_id}")
            return True
            
        except Exception as e:
            logger.error(f"Apple 캘린더 인증 실패: {e}")
            return False
    
    async def _discover_principal(self) -> bool:
        """Principal URL 검색 (CalDAV 표준)"""
        try:
            propfind_body = """<?xml version="1.0" encoding="utf-8" ?>
            <d:propfind xmlns:d="DAV:">
                <d:prop>
                    <d:current-user-principal />
                </d:prop>
            </d:propfind>"""
            
            async with self.session.request(
                "PROPFIND",
                self.base_url,
                data=propfind_body,
                headers={"Content-Type": "application/xml", "Depth": "0"}
            ) as response:
                
                if response.status != 207:
                    logger.error(f"Principal 검색 실패: {response.status}")
                    return False
                    
                xml_content = await response.text()
                root = ET.fromstring(xml_content)
                
                # Principal URL 추출
                for elem in root.iter():
                    if elem.tag.endswith("current-user-principal"):
                        href = elem.find(".//{DAV:}href")
                        if href is not None:
                            self.principal_url = urljoin(self.base_url, href.text)
                            return True
                            
                logger.error("Principal URL을 찾을 수 없음")
                return False
                
        except Exception as e:
            logger.error(f"Principal 검색 중 오류: {e}")
            return False
    
    async def _discover_calendar_home(self) -> bool:
        """Calendar Home URL 검색"""
        try:
            propfind_body = """<?xml version="1.0" encoding="utf-8" ?>
            <d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
                <d:prop>
                    <c:calendar-home-set />
                </d:prop>
            </d:propfind>"""
            
            async with self.session.request(
                "PROPFIND", 
                self.principal_url,
                data=propfind_body,
                headers={"Content-Type": "application/xml", "Depth": "0"}
            ) as response:
                
                if response.status != 207:
                    logger.error(f"Calendar Home 검색 실패: {response.status}")
                    return False
                    
                xml_content = await response.text()
                root = ET.fromstring(xml_content)
                
                # Calendar Home URL 추출
                for elem in root.iter():
                    if elem.tag.endswith("calendar-home-set"):
                        href = elem.find(".//{DAV:}href")
                        if href is not None:
                            self.calendar_home_url = urljoin(self.base_url, href.text)
                            return True
                            
                logger.error("Calendar Home URL을 찾을 수 없음")
                return False
                
        except Exception as e:
            logger.error(f"Calendar Home 검색 중 오류: {e}")
            return False
    
    async def get_calendars(self) -> List[Dict[str, Any]]:
        """사용 가능한 캘린더 목록 조회"""
        try:
            propfind_body = """<?xml version="1.0" encoding="utf-8" ?>
            <d:propfind xmlns:d="DAV:" xmlns:c="urn:ietf:params:xml:ns:caldav">
                <d:prop>
                    <d:displayname />
                    <d:resourcetype />
                    <c:calendar-description />
                    <c:supported-calendar-component-set />
                </d:prop>
            </d:propfind>"""
            
            async with self.session.request(
                "PROPFIND",
                self.calendar_home_url,
                data=propfind_body,
                headers={"Content-Type": "application/xml", "Depth": "1"}
            ) as response:
                
                if response.status != 207:
                    logger.error(f"캘린더 목록 조회 실패: {response.status}")
                    return []
                    
                xml_content = await response.text()
                return self._parse_calendars(xml_content)
                
        except Exception as e:
            logger.error(f"캘린더 목록 조회 중 오류: {e}")
            return []
    
    def _parse_calendars(self, xml_content: str) -> List[Dict[str, Any]]:
        """캘린더 XML 응답 파싱"""
        calendars = []
        root = ET.fromstring(xml_content)
        
        for response in root.findall(".//{DAV:}response"):
            # 캘린더인지 확인
            resourcetype = response.find(".//{DAV:}resourcetype")
            if resourcetype is None:
                continue
                
            is_calendar = resourcetype.find(".//{urn:ietf:params:xml:ns:caldav}calendar") is not None
            if not is_calendar:
                continue
                
            # 캘린더 정보 추출
            href_elem = response.find(".//{DAV:}href")
            name_elem = response.find(".//{DAV:}displayname")
            desc_elem = response.find(".//{urn:ietf:params:xml:ns:caldav}calendar-description")
            
            if href_elem is not None and name_elem is not None:
                calendar = {
                    "id": href_elem.text.split("/")[-2],  # URL에서 ID 추출
                    "name": name_elem.text or "이름 없음",
                    "description": desc_elem.text if desc_elem is not None else "",
                    "url": urljoin(self.base_url, href_elem.text),
                    "provider": CalendarProvider.APPLE.value
                }
                calendars.append(calendar)
                
        return calendars
    
    async def create_event(self, calendar_id: str, event_data: Dict[str, Any]) -> Dict[str, Any]:
        """이벤트 생성 (iCalendar 형식)"""
        try:
            # iCalendar 이벤트 생성
            ics_content = self._create_ics_event(event_data)
            
            # 이벤트 URL 생성 (UUID 기반)
            import uuid
            event_id = str(uuid.uuid4())
            event_url = f"{self.calendar_home_url}{calendar_id}/{event_id}.ics"
            
            # PUT 요청으로 이벤트 생성
            async with self.session.put(
                event_url,
                data=ics_content,
                headers={"Content-Type": "text/calendar; charset=utf-8"}
            ) as response:
                
                if response.status not in [201, 204]:
                    logger.error(f"이벤트 생성 실패: {response.status}")
                    return {}
                    
                logger.info(f"Apple 캘린더 이벤트 생성 성공: {event_id}")
                return {
                    "id": event_id,
                    "url": event_url,
                    "provider": CalendarProvider.APPLE.value
                }
                
        except Exception as e:
            logger.error(f"Apple 캘린더 이벤트 생성 중 오류: {e}")
            return {}
    
    def _create_ics_event(self, event_data: Dict[str, Any]) -> str:
        """iCalendar 형식 이벤트 생성"""
        title = event_data.get("title", "제목 없음")
        description = event_data.get("description", "")
        start_time = event_data.get("start_time")
        end_time = event_data.get("end_time")
        
        # 시간 형식 변환
        if isinstance(start_time, datetime):
            start_str = start_time.strftime("%Y%m%dT%H%M%SZ")
        else:
            start_str = datetime.now().strftime("%Y%m%dT%H%M%SZ")
            
        if isinstance(end_time, datetime):
            end_str = end_time.strftime("%Y%m%dT%H%M%SZ")
        else:
            end_str = (datetime.now() + timedelta(hours=1)).strftime("%Y%m%dT%H%M%SZ")
        
        # iCalendar 내용 생성
        ics_content = f"""BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Todo-Project//Apple Calendar//KO
BEGIN:VEVENT
UID:{event_data.get('uid', str(uuid.uuid4()))}
DTSTART:{start_str}
DTEND:{end_str}
SUMMARY:{title}
DESCRIPTION:{description}
CREATED:{datetime.now().strftime("%Y%m%dT%H%M%SZ")}
LAST-MODIFIED:{datetime.now().strftime("%Y%m%dT%H%M%SZ")}
END:VEVENT
END:VCALENDAR"""
        
        return ics_content
    
    async def update_event(self, event_id: str, event_data: Dict[str, Any]) -> Dict[str, Any]:
        """이벤트 수정"""
        try:
            # 기존 이벤트 URL 구성
            calendar_id = event_data.get("calendar_id", "calendar")
            event_url = f"{self.calendar_home_url}{calendar_id}/{event_id}.ics"
            
            # 수정된 iCalendar 내용 생성
            ics_content = self._create_ics_event(event_data)
            
            # PUT 요청으로 이벤트 수정
            async with self.session.put(
                event_url,
                data=ics_content,
                headers={"Content-Type": "text/calendar; charset=utf-8"}
            ) as response:
                
                if response.status not in [200, 204]:
                    logger.error(f"이벤트 수정 실패: {response.status}")
                    return {}
                    
                logger.info(f"Apple 캘린더 이벤트 수정 성공: {event_id}")
                return {
                    "id": event_id,
                    "url": event_url,
                    "provider": CalendarProvider.APPLE.value
                }
                
        except Exception as e:
            logger.error(f"Apple 캘린더 이벤트 수정 중 오류: {e}")
            return {}
    
    async def delete_event(self, event_id: str, calendar_id: str = "calendar") -> bool:
        """이벤트 삭제"""
        try:
            # 이벤트 URL 구성
            event_url = f"{self.calendar_home_url}{calendar_id}/{event_id}.ics"
            
            # DELETE 요청
            async with self.session.delete(event_url) as response:
                if response.status not in [200, 204, 404]:
                    logger.error(f"이벤트 삭제 실패: {response.status}")
                    return False
                    
                logger.info(f"Apple 캘린더 이벤트 삭제 성공: {event_id}")
                return True
                
        except Exception as e:
            logger.error(f"Apple 캘린더 이벤트 삭제 중 오류: {e}")
            return False
    
    async def close(self):
        """세션 정리"""
        if self.session:
            await self.session.close()
            self.session = None
    
    def __del__(self):
        """소멸자에서 세션 정리"""
        if self.session and not self.session.closed:
            asyncio.create_task(self.close())


# 편의 함수들
async def create_apple_service(apple_id: str, app_password: str) -> Optional[AppleCalendarService]:
    """Apple 캘린더 서비스 생성 및 인증"""
    service = AppleCalendarService()
    
    credentials = {
        "apple_id": apple_id,
        "app_password": app_password
    }
    
    if await service.authenticate(credentials):
        return service
    else:
        await service.close()
        return None


def format_todo_for_apple(todo_item) -> Dict[str, Any]:
    """Todo 아이템을 Apple 캘린더 이벤트 형식으로 변환"""
    import uuid
    
    return {
        "uid": str(uuid.uuid4()),
        "title": f"📋 {todo_item.content}",
        "description": f"Todo 항목\n상태: {todo_item.status}\n생성일: {todo_item.created_at}",
        "start_time": todo_item.start_date or todo_item.created_at,
        "end_time": (todo_item.start_date or todo_item.created_at) + timedelta(
            minutes=todo_item.estimated_minutes or 30
        ),
        "categories": ["todo", "업무"]
    }
