"""
캘린더 서비스 기본 인터페이스 및 추상화
"""
from abc import ABC, abstractmethod
from enum import Enum
from typing import Dict, List, Optional, Any
from datetime import datetime, timedelta
from dataclasses import dataclass
import uuid


class CalendarProvider(Enum):
    """캘린더 제공자 열거형"""
    SYNOLOGY = "synology"
    APPLE = "apple"
    GOOGLE = "google"
    CALDAV = "caldav"  # 일반 CalDAV 서버


@dataclass
class CalendarInfo:
    """캘린더 정보"""
    id: str
    name: str
    color: str
    description: Optional[str] = None
    provider: CalendarProvider = CalendarProvider.CALDAV
    is_default: bool = False
    is_writable: bool = True


@dataclass
class CalendarEvent:
    """캘린더 이벤트"""
    id: Optional[str] = None
    title: str = ""
    description: Optional[str] = None
    start_time: Optional[datetime] = None
    end_time: Optional[datetime] = None
    all_day: bool = False
    location: Optional[str] = None
    categories: List[str] = None
    color: Optional[str] = None
    reminder_minutes: Optional[int] = None
    status: str = "TENTATIVE"  # TENTATIVE, CONFIRMED, CANCELLED
    
    def __post_init__(self):
        if self.categories is None:
            self.categories = []
        if self.id is None:
            self.id = str(uuid.uuid4())


@dataclass
class CalendarCredentials:
    """캘린더 인증 정보"""
    provider: CalendarProvider
    server_url: Optional[str] = None
    username: Optional[str] = None
    password: Optional[str] = None
    app_password: Optional[str] = None  # Apple 앱 전용 비밀번호
    oauth_token: Optional[str] = None   # OAuth 토큰
    additional_params: Dict[str, Any] = None
    
    def __post_init__(self):
        if self.additional_params is None:
            self.additional_params = {}


class CalendarServiceError(Exception):
    """캘린더 서비스 오류"""
    pass


class AuthenticationError(CalendarServiceError):
    """인증 오류"""
    pass


class CalendarNotFoundError(CalendarServiceError):
    """캘린더를 찾을 수 없음"""
    pass


class EventNotFoundError(CalendarServiceError):
    """이벤트를 찾을 수 없음"""
    pass


class BaseCalendarService(ABC):
    """캘린더 서비스 기본 인터페이스"""
    
    def __init__(self, credentials: CalendarCredentials):
        self.credentials = credentials
        self.provider = credentials.provider
        self._authenticated = False
        self._client = None
    
    @property
    def is_authenticated(self) -> bool:
        """인증 상태 확인"""
        return self._authenticated
    
    @abstractmethod
    async def authenticate(self) -> bool:
        """
        인증 수행
        
        Returns:
            bool: 인증 성공 여부
            
        Raises:
            AuthenticationError: 인증 실패 시
        """
        pass
    
    @abstractmethod
    async def get_calendars(self) -> List[CalendarInfo]:
        """
        사용 가능한 캘린더 목록 조회
        
        Returns:
            List[CalendarInfo]: 캘린더 목록
            
        Raises:
            CalendarServiceError: 조회 실패 시
        """
        pass
    
    @abstractmethod
    async def create_event(self, calendar_id: str, event: CalendarEvent) -> CalendarEvent:
        """
        이벤트 생성
        
        Args:
            calendar_id: 캘린더 ID
            event: 생성할 이벤트 정보
            
        Returns:
            CalendarEvent: 생성된 이벤트 (ID 포함)
            
        Raises:
            CalendarNotFoundError: 캘린더를 찾을 수 없음
            CalendarServiceError: 생성 실패
        """
        pass
    
    @abstractmethod
    async def update_event(self, calendar_id: str, event: CalendarEvent) -> CalendarEvent:
        """
        이벤트 수정
        
        Args:
            calendar_id: 캘린더 ID
            event: 수정할 이벤트 정보 (ID 포함)
            
        Returns:
            CalendarEvent: 수정된 이벤트
            
        Raises:
            EventNotFoundError: 이벤트를 찾을 수 없음
            CalendarServiceError: 수정 실패
        """
        pass
    
    @abstractmethod
    async def delete_event(self, calendar_id: str, event_id: str) -> bool:
        """
        이벤트 삭제
        
        Args:
            calendar_id: 캘린더 ID
            event_id: 삭제할 이벤트 ID
            
        Returns:
            bool: 삭제 성공 여부
            
        Raises:
            EventNotFoundError: 이벤트를 찾을 수 없음
            CalendarServiceError: 삭제 실패
        """
        pass
    
    @abstractmethod
    async def get_event(self, calendar_id: str, event_id: str) -> CalendarEvent:
        """
        특정 이벤트 조회
        
        Args:
            calendar_id: 캘린더 ID
            event_id: 이벤트 ID
            
        Returns:
            CalendarEvent: 이벤트 정보
            
        Raises:
            EventNotFoundError: 이벤트를 찾을 수 없음
        """
        pass
    
    async def test_connection(self) -> Dict[str, Any]:
        """
        연결 테스트
        
        Returns:
            Dict: 테스트 결과
        """
        try:
            success = await self.authenticate()
            if success:
                calendars = await self.get_calendars()
                return {
                    "status": "success",
                    "provider": self.provider.value,
                    "calendar_count": len(calendars),
                    "calendars": [{"id": cal.id, "name": cal.name} for cal in calendars[:3]]  # 처음 3개만
                }
            else:
                return {
                    "status": "failed",
                    "provider": self.provider.value,
                    "error": "Authentication failed"
                }
        except Exception as e:
            return {
                "status": "error",
                "provider": self.provider.value,
                "error": str(e)
            }
    
    def _ensure_authenticated(self):
        """인증 상태 확인 (내부 사용)"""
        if not self._authenticated:
            raise AuthenticationError(f"{self.provider.value} 서비스에 인증되지 않았습니다.")


class TodoEventConverter:
    """Todo 아이템을 캘린더 이벤트로 변환하는 유틸리티"""
    
    @staticmethod
    def todo_to_event(todo_item, provider: CalendarProvider) -> CalendarEvent:
        """
        할일을 캘린더 이벤트로 변환
        
        Args:
            todo_item: Todo 아이템
            provider: 캘린더 제공자
            
        Returns:
            CalendarEvent: 변환된 이벤트
        """
        # 상태별 아이콘 및 색상
        status_icons = {
            "draft": "📝",
            "scheduled": "📋",
            "active": "🔥",
            "completed": "✅",
            "delayed": "⏰"
        }
        
        status_colors = {
            "draft": "#9ca3af",      # 회색
            "scheduled": "#6366f1",  # 보라색
            "active": "#f59e0b",     # 주황색
            "completed": "#10b981",  # 초록색
            "delayed": "#ef4444"     # 빨간색
        }
        
        icon = status_icons.get(todo_item.status, "📋")
        color = status_colors.get(todo_item.status, "#6366f1")
        
        # 시작/종료 시간 계산
        start_time = todo_item.start_date
        end_time = start_time + timedelta(minutes=todo_item.estimated_minutes or 30)
        
        # 기본 이벤트 생성
        event = CalendarEvent(
            title=f"{icon} {todo_item.content}",
            description=f"Todo ID: {todo_item.id}\nStatus: {todo_item.status}\nEstimated: {todo_item.estimated_minutes or 30}분",
            start_time=start_time,
            end_time=end_time,
            categories=["완료" if todo_item.status == "completed" else "todo"],
            color=color,
            reminder_minutes=15,
            status="CONFIRMED" if todo_item.status == "completed" else "TENTATIVE"
        )
        
        # 제공자별 커스터마이징
        if provider == CalendarProvider.APPLE:
            # 애플 캘린더 특화
            event.color = "#6366f1"  # 보라색으로 통일
            event.reminder_minutes = 15
            
        elif provider == CalendarProvider.SYNOLOGY:
            # 시놀로지 캘린더 특화
            event.location = "Todo-Project"
            
        elif provider == CalendarProvider.GOOGLE:
            # 구글 캘린더 특화
            event.color = "#4285f4"  # 구글 블루
        
        return event
    
    @staticmethod
    def get_provider_specific_properties(event: CalendarEvent, provider: CalendarProvider) -> Dict[str, Any]:
        """
        제공자별 특화 속성 반환
        
        Args:
            event: 캘린더 이벤트
            provider: 캘린더 제공자
            
        Returns:
            Dict: 제공자별 특화 속성
        """
        if provider == CalendarProvider.APPLE:
            return {
                "X-APPLE-STRUCTURED-LOCATION": event.location,
                "X-APPLE-CALENDAR-COLOR": event.color
            }
        elif provider == CalendarProvider.SYNOLOGY:
            return {
                "PRIORITY": "5",
                "CLASS": "PRIVATE"
            }
        elif provider == CalendarProvider.GOOGLE:
            return {
                "colorId": "9",  # 파란색
                "visibility": "private"
            }
        else:
            return {}
