"""
캘린더 라우터 - 다중 캘린더 제공자 중앙 관리
- 서비스 클래스 기준: 최대 350줄
- 간결함 원칙: 단순한 라우팅과 조합 로직만 포함
"""
import asyncio
from typing import Dict, List, Any, Optional, Union
from enum import Enum
import logging

from .base import BaseCalendarService, CalendarProvider
from .synology import SynologyCalendarService
from .apple import AppleCalendarService

logger = logging.getLogger(__name__)


class CalendarRouter:
    """다중 캘린더 제공자를 관리하는 중앙 라우터"""
    
    def __init__(self):
        self.services: Dict[CalendarProvider, BaseCalendarService] = {}
        self.default_provider: Optional[CalendarProvider] = None
        
    async def register_provider(
        self, 
        provider: CalendarProvider, 
        credentials: Dict[str, Any],
        set_as_default: bool = False
    ) -> bool:
        """캘린더 제공자 등록 및 인증"""
        try:
            # 서비스 인스턴스 생성
            service = self._create_service(provider)
            if not service:
                logger.error(f"지원하지 않는 캘린더 제공자: {provider}")
                return False
            
            # 인증 시도
            if not await service.authenticate(credentials):
                logger.error(f"{provider.value} 캘린더 인증 실패")
                return False
            
            # 등록 완료
            self.services[provider] = service
            
            if set_as_default or not self.default_provider:
                self.default_provider = provider
                
            logger.info(f"{provider.value} 캘린더 제공자 등록 완료")
            return True
            
        except Exception as e:
            logger.error(f"캘린더 제공자 등록 중 오류: {e}")
            return False
    
    def _create_service(self, provider: CalendarProvider) -> Optional[BaseCalendarService]:
        """제공자별 서비스 인스턴스 생성"""
        service_map = {
            CalendarProvider.SYNOLOGY: SynologyCalendarService,
            CalendarProvider.APPLE: AppleCalendarService,
            # 추후 확장: CalendarProvider.GOOGLE: GoogleCalendarService,
        }
        
        service_class = service_map.get(provider)
        return service_class() if service_class else None
    
    async def get_all_calendars(self) -> Dict[str, List[Dict[str, Any]]]:
        """모든 등록된 제공자의 캘린더 목록 조회"""
        all_calendars = {}
        
        for provider, service in self.services.items():
            try:
                calendars = await service.get_calendars()
                all_calendars[provider.value] = calendars
                logger.info(f"{provider.value}: {len(calendars)}개 캘린더 발견")
            except Exception as e:
                logger.error(f"{provider.value} 캘린더 목록 조회 실패: {e}")
                all_calendars[provider.value] = []
        
        return all_calendars
    
    async def get_calendars(self, provider: Optional[CalendarProvider] = None) -> List[Dict[str, Any]]:
        """특정 제공자 또는 기본 제공자의 캘린더 목록 조회"""
        target_provider = provider or self.default_provider
        
        if not target_provider or target_provider not in self.services:
            logger.error(f"캘린더 제공자를 찾을 수 없음: {target_provider}")
            return []
        
        try:
            return await self.services[target_provider].get_calendars()
        except Exception as e:
            logger.error(f"캘린더 목록 조회 실패: {e}")
            return []
    
    async def create_event(
        self, 
        calendar_id: str, 
        event_data: Dict[str, Any],
        provider: Optional[CalendarProvider] = None
    ) -> Dict[str, Any]:
        """이벤트 생성 (특정 제공자 또는 기본 제공자)"""
        target_provider = provider or self.default_provider
        
        if not target_provider or target_provider not in self.services:
            logger.error(f"캘린더 제공자를 찾을 수 없음: {target_provider}")
            return {}
        
        try:
            result = await self.services[target_provider].create_event(calendar_id, event_data)
            result["provider"] = target_provider.value
            return result
        except Exception as e:
            logger.error(f"이벤트 생성 실패: {e}")
            return {}
    
    async def create_event_multi(
        self, 
        calendar_configs: List[Dict[str, Any]], 
        event_data: Dict[str, Any]
    ) -> Dict[str, List[Dict[str, Any]]]:
        """
        여러 캘린더에 동시 이벤트 생성
        calendar_configs: [{"provider": "synology", "calendar_id": "personal"}, ...]
        """
        results = {"success": [], "failed": []}
        
        # 병렬 처리를 위한 태스크 생성
        tasks = []
        for config in calendar_configs:
            provider_str = config.get("provider")
            calendar_id = config.get("calendar_id")
            
            try:
                provider = CalendarProvider(provider_str)
                if provider in self.services:
                    task = self._create_event_task(provider, calendar_id, event_data, config)
                    tasks.append(task)
                else:
                    results["failed"].append({
                        "provider": provider_str,
                        "calendar_id": calendar_id,
                        "error": "제공자를 찾을 수 없음"
                    })
            except ValueError:
                results["failed"].append({
                    "provider": provider_str,
                    "calendar_id": calendar_id,
                    "error": "지원하지 않는 제공자"
                })
        
        # 병렬 실행
        if tasks:
            task_results = await asyncio.gather(*tasks, return_exceptions=True)
            
            for i, result in enumerate(task_results):
                config = calendar_configs[i]
                if isinstance(result, Exception):
                    results["failed"].append({
                        "provider": config.get("provider"),
                        "calendar_id": config.get("calendar_id"),
                        "error": str(result)
                    })
                else:
                    results["success"].append(result)
        
        return results
    
    async def _create_event_task(
        self, 
        provider: CalendarProvider, 
        calendar_id: str, 
        event_data: Dict[str, Any],
        config: Dict[str, Any]
    ) -> Dict[str, Any]:
        """이벤트 생성 태스크 (병렬 처리용)"""
        try:
            result = await self.services[provider].create_event(calendar_id, event_data)
            result.update({
                "provider": provider.value,
                "calendar_id": calendar_id,
                "config": config
            })
            return result
        except Exception as e:
            raise Exception(f"{provider.value} 이벤트 생성 실패: {e}")
    
    async def update_event(
        self, 
        event_id: str, 
        event_data: Dict[str, Any],
        provider: Optional[CalendarProvider] = None
    ) -> Dict[str, Any]:
        """이벤트 수정"""
        target_provider = provider or self.default_provider
        
        if not target_provider or target_provider not in self.services:
            logger.error(f"캘린더 제공자를 찾을 수 없음: {target_provider}")
            return {}
        
        try:
            result = await self.services[target_provider].update_event(event_id, event_data)
            result["provider"] = target_provider.value
            return result
        except Exception as e:
            logger.error(f"이벤트 수정 실패: {e}")
            return {}
    
    async def delete_event(
        self, 
        event_id: str,
        provider: Optional[CalendarProvider] = None,
        **kwargs
    ) -> bool:
        """이벤트 삭제"""
        target_provider = provider or self.default_provider
        
        if not target_provider or target_provider not in self.services:
            logger.error(f"캘린더 제공자를 찾을 수 없음: {target_provider}")
            return False
        
        try:
            return await self.services[target_provider].delete_event(event_id, **kwargs)
        except Exception as e:
            logger.error(f"이벤트 삭제 실패: {e}")
            return False
    
    async def sync_todo_to_calendars(
        self, 
        todo_item, 
        calendar_configs: Optional[List[Dict[str, Any]]] = None
    ) -> Dict[str, Any]:
        """Todo 아이템을 여러 캘린더에 동기화"""
        if not calendar_configs:
            # 기본 제공자만 사용
            if not self.default_provider:
                logger.error("기본 캘린더 제공자가 설정되지 않음")
                return {"success": [], "failed": []}
            
            calendar_configs = [{
                "provider": self.default_provider.value,
                "calendar_id": "default"
            }]
        
        # Todo를 캘린더 이벤트 형식으로 변환
        event_data = self._format_todo_event(todo_item)
        
        # 여러 캘린더에 생성
        return await self.create_event_multi(calendar_configs, event_data)
    
    def _format_todo_event(self, todo_item) -> Dict[str, Any]:
        """Todo 아이템을 캘린더 이벤트 형식으로 변환"""
        from datetime import datetime, timedelta
        import uuid
        
        # 상태별 태그 설정
        status_tag = "완료" if todo_item.status == "completed" else "todo"
        
        return {
            "uid": str(uuid.uuid4()),
            "title": f"📋 {todo_item.content}",
            "description": f"Todo 항목\n상태: {status_tag}\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": [status_tag, "업무"],
            "todo_id": todo_item.id
        }
    
    def get_registered_providers(self) -> List[str]:
        """등록된 캘린더 제공자 목록 반환"""
        return [provider.value for provider in self.services.keys()]
    
    def set_default_provider(self, provider: CalendarProvider) -> bool:
        """기본 캘린더 제공자 설정"""
        if provider in self.services:
            self.default_provider = provider
            logger.info(f"기본 캘린더 제공자 변경: {provider.value}")
            return True
        else:
            logger.error(f"등록되지 않은 제공자: {provider.value}")
            return False
    
    async def health_check(self) -> Dict[str, Any]:
        """모든 등록된 캘린더 서비스 상태 확인"""
        health_status = {
            "total_providers": len(self.services),
            "default_provider": self.default_provider.value if self.default_provider else None,
            "providers": {}
        }
        
        for provider, service in self.services.items():
            try:
                # 간단한 캘린더 목록 조회로 상태 확인
                calendars = await service.get_calendars()
                health_status["providers"][provider.value] = {
                    "status": "healthy",
                    "calendar_count": len(calendars)
                }
            except Exception as e:
                health_status["providers"][provider.value] = {
                    "status": "error",
                    "error": str(e)
                }
        
        return health_status
    
    async def close_all(self):
        """모든 캘린더 서비스 연결 종료"""
        for provider, service in self.services.items():
            try:
                if hasattr(service, 'close'):
                    await service.close()
                logger.info(f"{provider.value} 캘린더 서비스 연결 종료")
            except Exception as e:
                logger.error(f"{provider.value} 연결 종료 중 오류: {e}")
        
        self.services.clear()
        self.default_provider = None


# 전역 라우터 인스턴스 (싱글톤 패턴)
_calendar_router: Optional[CalendarRouter] = None


def get_calendar_router() -> CalendarRouter:
    """캘린더 라우터 싱글톤 인스턴스 반환"""
    global _calendar_router
    if _calendar_router is None:
        _calendar_router = CalendarRouter()
    return _calendar_router


async def setup_calendar_providers(providers_config: Dict[str, Dict[str, Any]]) -> CalendarRouter:
    """
    캘린더 제공자들을 일괄 설정
    providers_config: {
        "synology": {"credentials": {...}, "default": True},
        "apple": {"credentials": {...}, "default": False}
    }
    """
    router = get_calendar_router()
    
    for provider_name, config in providers_config.items():
        try:
            provider = CalendarProvider(provider_name)
            credentials = config.get("credentials", {})
            is_default = config.get("default", False)
            
            success = await router.register_provider(provider, credentials, is_default)
            if success:
                logger.info(f"{provider_name} 캘린더 설정 완료")
            else:
                logger.error(f"{provider_name} 캘린더 설정 실패")
                
        except ValueError:
            logger.error(f"지원하지 않는 캘린더 제공자: {provider_name}")
        except Exception as e:
            logger.error(f"{provider_name} 캘린더 설정 중 오류: {e}")
    
    return router
