"""
Base agent classes for Context Custodians
"""

import threading
import time
import logging
from abc import ABC, abstractmethod
from typing import Dict, Any, Optional
from pathlib import Path

from ..core.config import Config
from ..core.state import StateManager
from ..core.utils import setup_logging


class BaseAgent(ABC):
    """Base class for all Memory Warden agents"""

    def __init__(self, name: str, config: Config, state_manager: StateManager):
        self.name = name
        self.config = config
        self.state_manager = state_manager
        self.logger = logging.getLogger(f"vmw.agent.{name}")
        self._running = False
        self._thread: Optional[threading.Thread] = None

    @abstractmethod
    def execute(self) -> Dict[str, Any]:
        """Execute the agent's main task"""
        pass

    def start(self):
        """Start the agent"""
        if self._running:
            self.logger.warning(f"Agent {self.name} is already running")
            return

        self._running = True
        self.state_manager.set_agent_status(self.name, 'starting')
        self.logger.info(f"Starting agent {self.name}")

        # Start in background thread
        self._thread = threading.Thread(target=self._run_loop, daemon=True)
        self._thread.start()

    def stop(self):
        """Stop the agent"""
        if not self._running:
            return

        self.logger.info(f"Stopping agent {self.name}")
        self._running = False
        self.state_manager.set_agent_status(self.name, 'stopped')

        if self._thread and self._thread.is_alive():
            self._thread.join(timeout=5)

    def _run_loop(self):
        """Main execution loop"""
        try:
            self.state_manager.set_agent_status(self.name, 'running')
            while self._running:
                try:
                    result = self.execute()
                    self.state_manager.set_agent_status(self.name, 'success', result)
                    self.logger.debug(f"Agent {self.name} executed successfully")
                except Exception as e:
                    self.logger.error(f"Agent {self.name} execution failed: {e}")
                    self.state_manager.set_agent_status(self.name, 'error', {'error': str(e)})

                # Wait before next execution
                time.sleep(self.config.monitoring_interval)

        except Exception as e:
            self.logger.error(f"Agent {self.name} crashed: {e}")
            self.state_manager.set_agent_status(self.name, 'crashed', {'error': str(e)})
        finally:
            self._running = False

    @property
    def is_running(self) -> bool:
        """Check if agent is running"""
        return self._running

    def get_status(self) -> Dict[str, Any]:
        """Get current agent status"""
        return self.state_manager.get_agent_status(self.name)


class EventDrivenAgent(BaseAgent):
    """Base class for event-driven agents"""

    def __init__(self, name: str, config: Config, state_manager: StateManager):
        super().__init__(name, config, state_manager)
        self.event_queue = []
        self.event_lock = threading.Lock()

    def add_event(self, event: Dict[str, Any]):
        """Add event to processing queue"""
        with self.event_lock:
            self.event_queue.append(event)
            self.logger.debug(f"Added event to {self.name} queue: {event}")

    def get_pending_events(self) -> list:
        """Get all pending events"""
        with self.event_lock:
            events = self.event_queue.copy()
            self.event_queue.clear()
        return events

    def execute(self) -> Dict[str, Any]:
        """Process all pending events"""
        events = self.get_pending_events()
        if not events:
            return {'events_processed': 0}

        results = []
        for event in events:
            try:
                result = self.process_event(event)
                results.append(result)
            except Exception as e:
                self.logger.error(f"Failed to process event {event}: {e}")
                results.append({'error': str(e)})

        return {
            'events_processed': len(events),
            'results': results
        }

    @abstractmethod
    def process_event(self, event: Dict[str, Any]) -> Dict[str, Any]:
        """Process a single event"""
        pass