"""
Legacy Agent - Intelligent management of legacy interface lifecycle.

The Legacy Agent provides automated management of legacy interfaces including
lifecycle progression, cleanup scheduling, migration assistance, and proactive
deprecation management.
"""

import json
import logging
from datetime import datetime, timedelta
from pathlib import Path
from typing import Dict, List, Optional, Any, Callable
from dataclasses import dataclass, asdict
from enum import Enum

from .registry import LegacyRegistry, LegacyInterface, LegacyStatus
from .deprecation import DeprecationManager, DeprecationLevel
from .git_tracker import GitStateTracker
from .exceptions import LegacyError, LegacyConfigurationError


class AgentAction(Enum):
    """Types of actions the legacy agent can perform."""
    PROGRESS_DEPRECATION = "progress_deprecation"
    SCHEDULE_REMOVAL = "schedule_removal"
    GENERATE_MIGRATION_GUIDE = "generate_migration_guide"
    CREATE_COMPATIBILITY_SHIM = "create_compatibility_shim"
    CLEANUP_UNUSED = "cleanup_unused"
    NOTIFY_USERS = "notify_users"


@dataclass
class AgentTask:
    """Represents a task for the legacy agent to execute."""
    action: AgentAction
    command: str
    version: str
    scheduled_for: str
    priority: int = 5  # 1=highest, 10=lowest
    metadata: Dict[str, Any] = None
    completed: bool = False
    completed_at: Optional[str] = None

    def __post_init__(self):
        if self.metadata is None:
            self.metadata = {}


@dataclass
class AgentConfig:
    """Configuration for the legacy agent."""
    auto_progression: bool = True
    cleanup_unused_days: int = 180
    migration_guide_auto_generation: bool = True
    notification_threshold_days: int = 30
    max_concurrent_migrations: int = 3
    backup_before_cleanup: bool = True


class LegacyAgent:
    """
    Intelligent agent for managing legacy interface lifecycle.

    Responsibilities:
    - Automatically progress deprecation phases based on timelines
    - Schedule and execute cleanup of unused legacy code
    - Generate migration guides and compatibility reports
    - Notify users of pending deprecations
    - Coordinate migration activities
    - Maintain audit trail of all legacy operations
    """

    def __init__(
        self,
        registry: Optional[LegacyRegistry] = None,
        config: Optional[AgentConfig] = None,
        data_dir: Optional[Path] = None
    ):
        """
        Initialize the legacy agent.

        Args:
            registry: Legacy registry instance
            config: Agent configuration
            data_dir: Directory for agent data storage
        """
        self.registry = registry or LegacyRegistry()
        self.config = config or AgentConfig()
        self.data_dir = data_dir or Path.home() / '.markitect' / 'legacy_agent'
        self.data_dir.mkdir(parents=True, exist_ok=True)

        self.deprecation_manager = DeprecationManager()
        self.git_tracker = GitStateTracker()

        self._tasks: List[AgentTask] = []
        self._load_tasks()

        # Setup logging
        self._setup_logging()

    def _setup_logging(self):
        """Setup logging for agent operations."""
        log_file = self.data_dir / 'agent.log'
        logging.basicConfig(
            level=logging.INFO,
            format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
            handlers=[
                logging.FileHandler(log_file),
                logging.StreamHandler()
            ]
        )
        self.logger = logging.getLogger('LegacyAgent')

    def run_maintenance(self) -> Dict[str, Any]:
        """
        Run scheduled maintenance tasks.

        Returns:
            Summary of maintenance activities performed
        """
        self.logger.info("Starting legacy maintenance cycle")

        summary = {
            'started_at': datetime.now().isoformat(),
            'tasks_executed': 0,
            'progressions': 0,
            'cleanups': 0,
            'notifications': 0,
            'errors': []
        }

        try:
            # Load current interfaces
            self._analyze_legacy_interfaces()

            # Execute scheduled tasks
            summary['tasks_executed'] = self._execute_scheduled_tasks()

            # Auto-progression if enabled
            if self.config.auto_progression:
                summary['progressions'] = self._auto_progress_deprecations()

            # Cleanup unused interfaces
            summary['cleanups'] = self._cleanup_unused_interfaces()

            # Generate notifications
            summary['notifications'] = self._generate_notifications()

            # Update task schedule
            self._schedule_future_tasks()

        except Exception as e:
            error_msg = f"Maintenance error: {e}"
            self.logger.error(error_msg)
            summary['errors'].append(error_msg)

        summary['completed_at'] = datetime.now().isoformat()
        self.logger.info(f"Maintenance cycle completed: {summary}")

        return summary

    def _analyze_legacy_interfaces(self):
        """Analyze all legacy interfaces for needed actions."""
        self.logger.info("Analyzing legacy interfaces")

        all_interfaces = {}
        for command in self.registry._interfaces:
            all_interfaces.update({
                f"{command}:{version}": interface
                for version, interface in self.registry._interfaces[command].items()
            })

        for key, interface in all_interfaces.items():
            # Check if deprecation should progress
            if interface.deprecated_date:
                next_status = self.deprecation_manager.should_progress_deprecation(
                    interface.command, interface.version,
                    interface.status.value, interface.deprecated_date
                )

                if next_status and next_status != interface.status.value:
                    self._schedule_task(AgentTask(
                        action=AgentAction.PROGRESS_DEPRECATION,
                        command=interface.command,
                        version=interface.version,
                        scheduled_for=datetime.now().isoformat(),
                        priority=3,
                        metadata={'new_status': next_status}
                    ))

            # Check if migration guide is needed
            if (interface.status in [LegacyStatus.LEGACY, LegacyStatus.SUNSET] and
                not interface.migration_guide and
                self.config.migration_guide_auto_generation):

                self._schedule_task(AgentTask(
                    action=AgentAction.GENERATE_MIGRATION_GUIDE,
                    command=interface.command,
                    version=interface.version,
                    scheduled_for=datetime.now().isoformat(),
                    priority=4
                ))

    def _execute_scheduled_tasks(self) -> int:
        """Execute tasks that are due for execution."""
        executed_count = 0
        now = datetime.now()

        for task in self._tasks:
            if task.completed:
                continue

            try:
                scheduled_time = datetime.fromisoformat(task.scheduled_for)
                if scheduled_time <= now:
                    self._execute_task(task)
                    task.completed = True
                    task.completed_at = now.isoformat()
                    executed_count += 1
            except Exception as e:
                self.logger.error(f"Task execution failed: {task.action.value} for {task.command}:{task.version} - {e}")

        # Save updated tasks
        self._save_tasks()
        return executed_count

    def _execute_task(self, task: AgentTask):
        """Execute a specific agent task."""
        self.logger.info(f"Executing task: {task.action.value} for {task.command}:{task.version}")

        if task.action == AgentAction.PROGRESS_DEPRECATION:
            self._progress_deprecation_task(task)
        elif task.action == AgentAction.GENERATE_MIGRATION_GUIDE:
            self._generate_migration_guide_task(task)
        elif task.action == AgentAction.CLEANUP_UNUSED:
            self._cleanup_unused_task(task)
        elif task.action == AgentAction.NOTIFY_USERS:
            self._notify_users_task(task)
        else:
            self.logger.warning(f"Unknown task action: {task.action}")

    def _progress_deprecation_task(self, task: AgentTask):
        """Execute deprecation progression task."""
        new_status = LegacyStatus(task.metadata['new_status'])
        self.registry.update_interface_status(task.command, task.version, new_status)

        self.logger.info(f"Progressed {task.command}:{task.version} to status: {new_status.value}")

        # Schedule removal if moving to sunset
        if new_status == LegacyStatus.SUNSET:
            removal_date = (datetime.now() + timedelta(days=30)).isoformat()
            self._schedule_task(AgentTask(
                action=AgentAction.SCHEDULE_REMOVAL,
                command=task.command,
                version=task.version,
                scheduled_for=removal_date,
                priority=1
            ))

    def _generate_migration_guide_task(self, task: AgentTask):
        """Generate migration guide for a legacy interface."""
        interface = self.registry.get_legacy_interface(task.command, task.version)
        if not interface:
            return

        # Generate basic migration guide
        guide = self._create_migration_guide(interface)

        # Update interface with migration guide
        interface.migration_guide = guide

        # Save to registry (this would need registry update method)
        self.logger.info(f"Generated migration guide for {task.command}:{task.version}")

    def _cleanup_unused_task(self, task: AgentTask):
        """Execute cleanup of unused legacy interface."""
        # This would perform actual cleanup operations
        # For now, we'll mark as removed
        self.registry.update_interface_status(
            task.command, task.version, LegacyStatus.REMOVED
        )

        # Create backup if configured
        if self.config.backup_before_cleanup:
            backup_dir = self.data_dir / 'backups' / f"{task.command}_{task.version}"
            self.git_tracker.create_version_snapshot(
                task.command, task.version, backup_dir
            )

        self.logger.info(f"Cleaned up unused interface: {task.command}:{task.version}")

    def _notify_users_task(self, task: AgentTask):
        """Send notification about pending deprecation."""
        # This could integrate with notification systems
        # For now, we'll log the notification
        interface = self.registry.get_legacy_interface(task.command, task.version)
        if interface:
            self.logger.warning(
                f"NOTIFICATION: {task.command}:{task.version} is approaching removal. "
                f"Removal date: {interface.removal_date}"
            )

    def _auto_progress_deprecations(self) -> int:
        """Automatically progress deprecations based on timeline."""
        progressions = 0

        for command in self.registry._interfaces:
            for version, interface in self.registry._interfaces[command].items():
                if not interface.deprecated_date:
                    continue

                next_status = self.deprecation_manager.should_progress_deprecation(
                    command, version, interface.status.value, interface.deprecated_date
                )

                if next_status and next_status != interface.status.value:
                    new_status = LegacyStatus(next_status)
                    self.registry.update_interface_status(command, version, new_status)
                    progressions += 1

                    self.logger.info(f"Auto-progressed {command}:{version} to {next_status}")

        return progressions

    def _cleanup_unused_interfaces(self) -> int:
        """Clean up interfaces that haven't been used in configured period."""
        cleanups = 0
        cutoff_date = datetime.now() - timedelta(days=self.config.cleanup_unused_days)

        # Get usage statistics
        stats = self.registry.get_usage_statistics(days=self.config.cleanup_unused_days)

        for command in self.registry._interfaces:
            for version, interface in self.registry._interfaces[command].items():
                if interface.status != LegacyStatus.SUNSET:
                    continue

                # Check if unused in the cleanup period
                version_key = f"{command}:{version}"
                if version_key not in stats['by_version']:
                    # Schedule for cleanup
                    self._schedule_task(AgentTask(
                        action=AgentAction.CLEANUP_UNUSED,
                        command=command,
                        version=version,
                        scheduled_for=datetime.now().isoformat(),
                        priority=6
                    ))
                    cleanups += 1

        return cleanups

    def _generate_notifications(self) -> int:
        """Generate notifications for approaching deprecations."""
        notifications = 0
        threshold_date = (datetime.now() + timedelta(days=self.config.notification_threshold_days)).isoformat()

        for command in self.registry._interfaces:
            for version, interface in self.registry._interfaces[command].items():
                if (interface.removal_date and
                    interface.removal_date <= threshold_date and
                    interface.status != LegacyStatus.REMOVED):

                    # Schedule notification
                    self._schedule_task(AgentTask(
                        action=AgentAction.NOTIFY_USERS,
                        command=command,
                        version=version,
                        scheduled_for=datetime.now().isoformat(),
                        priority=2
                    ))
                    notifications += 1

        return notifications

    def _schedule_future_tasks(self):
        """Schedule future maintenance tasks."""
        # Schedule next maintenance cycle
        next_maintenance = (datetime.now() + timedelta(days=1)).isoformat()

        # This would typically schedule the next run of the agent
        # Implementation depends on the scheduling system used

    def _create_migration_guide(self, interface: LegacyInterface) -> str:
        """Create a basic migration guide for an interface."""
        guide_parts = [
            f"Migration Guide for {interface.command} {interface.version}",
            "=" * 50,
            "",
            "OVERVIEW:",
            f"This legacy version ({interface.version}) of the '{interface.command}' command",
            "has been deprecated and will be removed in a future release.",
            "",
            "MIGRATION STEPS:",
            f"1. Remove the --legacy-{interface.version} flag from your commands",
            f"2. Test the current version of '{interface.command}' with your use cases",
            "3. Update any scripts or automation that use this command",
            "4. Review the breaking changes section below",
            "",
            "BREAKING CHANGES:"
        ]

        if interface.breaking_changes:
            for change in interface.breaking_changes:
                guide_parts.append(f"- {change}")
        else:
            guide_parts.append("- No specific breaking changes documented")

        guide_parts.extend([
            "",
            "SUPPORT:",
            "If you encounter issues during migration, please:",
            f"- Run: markitect help {interface.command}",
            "- Check the documentation for the latest syntax",
            "- Open an issue if you find compatibility problems"
        ])

        return "\n".join(guide_parts)

    def _schedule_task(self, task: AgentTask):
        """Schedule a task for future execution."""
        # Check for duplicate tasks
        for existing_task in self._tasks:
            if (existing_task.action == task.action and
                existing_task.command == task.command and
                existing_task.version == task.version and
                not existing_task.completed):
                return  # Task already scheduled

        self._tasks.append(task)
        self._save_tasks()

    def _load_tasks(self):
        """Load scheduled tasks from storage."""
        tasks_file = self.data_dir / 'scheduled_tasks.json'
        if tasks_file.exists():
            try:
                data = json.loads(tasks_file.read_text())
                self._tasks = [
                    AgentTask(
                        action=AgentAction(task_data['action']),
                        command=task_data['command'],
                        version=task_data['version'],
                        scheduled_for=task_data['scheduled_for'],
                        priority=task_data.get('priority', 5),
                        metadata=task_data.get('metadata', {}),
                        completed=task_data.get('completed', False),
                        completed_at=task_data.get('completed_at')
                    )
                    for task_data in data.get('tasks', [])
                ]
            except Exception as e:
                self.logger.error(f"Failed to load tasks: {e}")
                self._tasks = []

    def _save_tasks(self):
        """Save scheduled tasks to storage."""
        tasks_file = self.data_dir / 'scheduled_tasks.json'
        data = {
            'version': '1.0',
            'updated_at': datetime.now().isoformat(),
            'tasks': [asdict(task) for task in self._tasks]
        }

        try:
            tasks_file.write_text(json.dumps(data, indent=2))
        except Exception as e:
            self.logger.error(f"Failed to save tasks: {e}")

    def get_agent_status(self) -> Dict[str, Any]:
        """Get the current status of the legacy agent."""
        pending_tasks = [task for task in self._tasks if not task.completed]
        completed_tasks = [task for task in self._tasks if task.completed]

        return {
            'config': asdict(self.config),
            'tasks': {
                'total': len(self._tasks),
                'pending': len(pending_tasks),
                'completed': len(completed_tasks)
            },
            'next_maintenance': self._get_next_maintenance_time(),
            'data_directory': str(self.data_dir),
            'registry_stats': self._get_registry_stats()
        }

    def _get_next_maintenance_time(self) -> Optional[str]:
        """Get the next scheduled maintenance time."""
        pending_tasks = [task for task in self._tasks if not task.completed]
        if not pending_tasks:
            return None

        next_task = min(pending_tasks, key=lambda t: t.scheduled_for)
        return next_task.scheduled_for

    def _get_registry_stats(self) -> Dict[str, Any]:
        """Get statistics about the legacy registry."""
        stats = {
            'total_interfaces': 0,
            'by_status': {},
            'commands': set()
        }

        for command, versions in self.registry._interfaces.items():
            stats['commands'].add(command)
            for version, interface in versions.items():
                stats['total_interfaces'] += 1
                status = interface.status.value
                stats['by_status'][status] = stats['by_status'].get(status, 0) + 1

        stats['commands'] = list(stats['commands'])
        return stats

    def force_cleanup(self, command: str, version: str) -> bool:
        """
        Force immediate cleanup of a legacy interface.

        Args:
            command: Command name
            version: Version identifier

        Returns:
            True if cleanup was successful
        """
        try:
            interface = self.registry.get_legacy_interface(command, version)
            if not interface:
                return False

            # Create backup if configured
            if self.config.backup_before_cleanup:
                backup_dir = self.data_dir / 'backups' / f"{command}_{version}_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
                self.git_tracker.create_version_snapshot(command, version, backup_dir)

            # Mark as removed
            self.registry.update_interface_status(command, version, LegacyStatus.REMOVED)

            self.logger.info(f"Force cleanup completed for {command}:{version}")
            return True

        except Exception as e:
            self.logger.error(f"Force cleanup failed for {command}:{version}: {e}")
            return False

    def schedule_migration_assistance(self, command: str, from_version: str, target_date: str):
        """
        Schedule migration assistance for a specific legacy version.

        Args:
            command: Command name
            from_version: Legacy version to migrate from
            target_date: Target date for migration completion
        """
        # Schedule migration guide generation
        self._schedule_task(AgentTask(
            action=AgentAction.GENERATE_MIGRATION_GUIDE,
            command=command,
            version=from_version,
            scheduled_for=datetime.now().isoformat(),
            priority=3,
            metadata={'target_date': target_date}
        ))

        # Schedule compatibility analysis
        analysis_date = (datetime.now() + timedelta(days=7)).isoformat()
        self._schedule_task(AgentTask(
            action=AgentAction.CREATE_COMPATIBILITY_SHIM,
            command=command,
            version=from_version,
            scheduled_for=analysis_date,
            priority=4,
            metadata={'target_date': target_date}
        ))

        self.logger.info(f"Scheduled migration assistance for {command}:{from_version}")

    def export_agent_data(self) -> Dict[str, Any]:
        """Export all agent data for backup/analysis."""
        return {
            'version': '1.0',
            'exported_at': datetime.now().isoformat(),
            'config': asdict(self.config),
            'tasks': [asdict(task) for task in self._tasks],
            'registry_data': self.registry.export_configuration(),
            'git_bindings': self.git_tracker.export_bindings()
        }