"""
Optional storage service for persisting events locally
"""

import json
import asyncio
from pathlib import Path
from typing import List, Optional, Dict, Any
from datetime import datetime, timedelta
from uuid import UUID
from concurrent.futures import ThreadPoolExecutor

from ..models.captured_models import ErrorEvent, Severity, EventType
from ..models.pydantic_compat import get_model_dump
from ..config.settings import get_settings
from ..utils.logger_config import get_logger

logger = get_logger()


class StorageService:
    """Service for storing events to local filesystem"""

    def __init__(self, storage_path: Optional[Path] = None):
        self.settings = get_settings()
        self.storage_path = storage_path or self.settings.storage_path
        self.storage_path.mkdir(parents=True, exist_ok=True)
        self.executor = ThreadPoolExecutor(max_workers=4, thread_name_prefix="StorageService")
        self.loop = asyncio.get_event_loop()

        logger.info(f"StorageService initialized at: {self.storage_path}")

    def save(self, event: ErrorEvent) -> bool:
        """
        Save event to file.

        Args:
            event: Event to save

        Returns:
            True if successful
        """
        return self._save_sync(event)

    async def save_async(self, event: ErrorEvent) -> bool:
        """
        Asynchronously save event to file.

        Args:
            event: Event to save

        Returns:
            True if successful
        """
        return await self.loop.run_in_executor(self.executor, self._save_sync, event)

    def _save_sync(self, event: ErrorEvent) -> bool:
        """Synchronous save implementation"""
        try:
            # Create filename with timestamp and event ID
            timestamp = datetime.utcfromtimestamp(event.timestamp)
            filename = f"{timestamp.strftime('%Y%m%d_%H%M%S')}_{event.id}.json"
            filepath = self.storage_path / filename

            # Write event to file using compatibility function
            event_dict = get_model_dump(event, mode='json')  # Works for both v1 and v2
            
            with open(filepath, 'w') as f:
                json.dump(event_dict, f, indent=2)

            logger.debug(f"Event saved to: {filepath}")
            return True

        except Exception as e:
            logger.error(f"Failed to save event: {e}")
            return False

    def load(self, event_id: UUID) -> Optional[ErrorEvent]:
        """
        Load event by ID.

        Args:
            event_id: Event UUID

        Returns:
            ErrorEvent if found, None otherwise
        """
        return self._load_sync(event_id)

    async def load_async(self, event_id: UUID) -> Optional[ErrorEvent]:
        """
        Asynchronously load event by ID.
        """
        return await self.loop.run_in_executor(self.executor, self._load_sync, event_id)

    def _load_sync(self, event_id: UUID) -> Optional[ErrorEvent]:
        """Synchronous load implementation"""
        try:
            # Find file with matching event ID
            for filepath in self.storage_path.glob(f"*_{event_id}.json"):
                with open(filepath, 'r') as f:
                    data = json.load(f)
                    return ErrorEvent(**data)

            logger.warning(f"Event not found: {event_id}")
            return None

        except Exception as e:
            logger.error(f"Failed to load event: {e}")
            return None

    def query(
        self,
        severity: Optional[Severity] = None,
        event_type: Optional[EventType] = None,
        component: Optional[str] = None,
        pipeline_name: Optional[str] = None,
        limit: int = 100,
    ) -> List[ErrorEvent]:
        """
        Query events with filters.

        Args:
            severity: Filter by severity
            event_type: Filter by event type
            component: Filter by component
            pipeline_name: Filter by pipeline name
            limit: Maximum number of results

        Returns:
            List of matching events
        """
        return self._query_sync(severity, event_type, component, pipeline_name, limit)

    async def query_async(
        self,
        severity: Optional[Severity] = None,
        event_type: Optional[EventType] = None,
        component: Optional[str] = None,
        pipeline_name: Optional[str] = None,
        limit: int = 100,
    ) -> List[ErrorEvent]:
        """
        Asynchronously query events with filters.
        """
        return await self.loop.run_in_executor(
            self.executor, 
            self._query_sync, 
            severity, event_type, component, pipeline_name, limit
        )

    def _query_sync(
        self,
        severity: Optional[Severity] = None,
        event_type: Optional[EventType] = None,
        component: Optional[str] = None,
        pipeline_name: Optional[str] = None,
        limit: int = 100,
    ) -> List[ErrorEvent]:
        """Synchronous query implementation"""
        try:
            events = []

            # Load all event files
            for filepath in sorted(self.storage_path.glob("*.json"), reverse=True):
                if len(events) >= limit:
                    break

                try:
                    with open(filepath, 'r') as f:
                        data = json.load(f)
                        event = ErrorEvent(**data)

                        # Apply filters
                        if severity and event.severity != severity:
                            continue
                        if event_type and event.event_type != event_type:
                            continue
                        if component and event.component != component:
                            continue
                        if pipeline_name and event.pipeline_name != pipeline_name:
                            continue

                        events.append(event)

                except Exception as e:
                    logger.warning(f"Failed to load file {filepath}: {e}")

            return events

        except Exception as e:
            logger.error(f"Query failed: {e}")
            return []

    def delete(self, event_id: UUID) -> bool:
        """
        Delete event by ID.

        Args:
            event_id: Event UUID

        Returns:
            True if deleted
        """
        return self._delete_sync(event_id)

    async def delete_async(self, event_id: UUID) -> bool:
        """
        Asynchronously delete event by ID.
        """
        return await self.loop.run_in_executor(self.executor, self._delete_sync, event_id)

    def _delete_sync(self, event_id: UUID) -> bool:
        """Synchronous delete implementation"""
        try:
            for filepath in self.storage_path.glob(f"*_{event_id}.json"):
                filepath.unlink()
                logger.info(f"Event deleted: {event_id}")
                return True

            logger.warning(f"Event not found for deletion: {event_id}")
            return False

        except Exception as e:
            logger.error(f"Failed to delete event: {e}")
            return False

    def get_statistics(self) -> Dict[str, Any]:
        """
        Get storage statistics.

        Returns:
            Dictionary with statistics
        """
        return self._get_statistics_sync()

    async def get_statistics_async(self) -> Dict[str, Any]:
        """
        Asynchronously get storage statistics.
        """
        return await self.loop.run_in_executor(self.executor, self._get_statistics_sync)

    def _get_statistics_sync(self) -> Dict[str, Any]:
        """Synchronous statistics implementation"""
        try:
            files = list(self.storage_path.glob("*.json"))
            total_size = sum(f.stat().st_size for f in files)

            # Count by severity
            severity_counts: Dict[str, int] = {}
            for filepath in files:
                try:
                    with open(filepath, 'r') as f:
                        data = json.load(f)
                        severity = data.get('severity', 'unknown')
                        severity_counts[severity] = severity_counts.get(severity, 0) + 1
                except Exception:
                    pass

            return {
                'total_events': len(files),
                'total_size_mb': total_size / (1024 * 1024),
                'storage_path': str(self.storage_path),
                'severity_counts': severity_counts,
            }

        except Exception as e:
            logger.error(f"Failed to get statistics: {e}")
            return {}

    def cleanup_old_events(self, days: int = 30) -> int:
        """
        Delete events older than specified days.

        Args:
            days: Age threshold in days

        Returns:
            Number of events deleted
        """
        return self._cleanup_old_events_sync(days)

    async def cleanup_old_events_async(self, days: int = 30) -> int:
        """
        Asynchronously delete events older than specified days.
        """
        return await self.loop.run_in_executor(self.executor, self._cleanup_old_events_sync, days)

    def _cleanup_old_events_sync(self, days: int = 30) -> int:
        """Synchronous cleanup implementation"""
        try:
            cutoff = datetime.utcnow() - timedelta(days=days)
            deleted = 0

            for filepath in self.storage_path.glob("*.json"):
                try:
                    # Parse timestamp from filename
                    filename_parts = filepath.stem.split('_')
                    if len(filename_parts) >= 2:
                        timestamp_str = filename_parts[0]
                        try:
                            file_date = datetime.strptime(timestamp_str, '%Y%m%d')
                            if file_date < cutoff:
                                filepath.unlink()
                                deleted += 1
                        except ValueError:
                            # If date parsing fails, skip this file
                            logger.warning(f"Could not parse date from filename: {filepath.name}")
                            continue

                except Exception as e:
                    logger.warning(f"Failed to process file {filepath}: {e}")

            logger.info(f"Cleaned up {deleted} old events")
            return deleted

        except Exception as e:
            logger.error(f"Cleanup failed: {e}")
            return 0

    async def close_async(self) -> None:
        """Asynchronously close the storage service"""
        self.executor.shutdown(wait=True)  # Wait for pending tasks
        logger.info("StorageService closed")

    def close(self) -> None:
        """Close the storage service"""
        self.executor.shutdown(wait=False)  # Don't wait in synchronous close
        logger.info("StorageService closed")


# Global singleton instance
_storage_service: Optional[StorageService] = None


def get_storage_service() -> StorageService:
    """Get or create global storage service instance"""
    global _storage_service
    if _storage_service is None:
        _storage_service = StorageService()
    return _storage_service


async def get_storage_service_async() -> StorageService:
    """Get or create global storage service instance (async version)"""
    global _storage_service
    if _storage_service is None:
        _storage_service = StorageService()
    return _storage_service


async def reset_storage_service_async() -> None:
    """Reset storage service asynchronously (useful for testing)"""
    global _storage_service
    if _storage_service:
        await _storage_service.close_async()
    _storage_service = None


def reset_storage_service() -> None:
    """Reset storage service (useful for testing)"""
    global _storage_service
    if _storage_service:
        _storage_service.close()
    _storage_service = None