"""
Deprecation Management System - Handle graduated deprecation warnings and lifecycle.

Provides structured deprecation warnings, lifecycle management, and migration
guidance for legacy interfaces moving through their deprecation phases.
"""

import sys
import warnings
from datetime import datetime, timedelta
from enum import Enum
from typing import Optional, Dict, List, Any
from dataclasses import dataclass

import click

from .exceptions import DeprecationError


class DeprecationLevel(Enum):
    """Levels of deprecation severity."""
    INFO = "info"           # Initial deprecation notice
    WARNING = "warning"     # Standard deprecation warning
    CRITICAL = "critical"   # Final warning before removal
    ERROR = "error"         # Deprecation with error (blocks execution)


@dataclass
class DeprecationPolicy:
    """Policy configuration for deprecation management."""
    info_duration_days: int = 90        # Days in INFO level
    warning_duration_days: int = 60     # Days in WARNING level
    critical_duration_days: int = 30    # Days in CRITICAL level
    show_migration_guide: bool = True
    block_on_error: bool = True
    quiet_mode: bool = False


class DeprecationManager:
    """
    Manages deprecation warnings and lifecycle progression.

    Responsibilities:
    - Display appropriate deprecation warnings based on level
    - Track deprecation progression through lifecycle phases
    - Provide migration guidance and recommendations
    - Support quiet mode and warning suppression
    - Handle automatic progression of deprecation levels
    """

    def __init__(self, policy: Optional[DeprecationPolicy] = None):
        """
        Initialize the deprecation manager.

        Args:
            policy: Deprecation policy configuration
        """
        self.policy = policy or DeprecationPolicy()
        self._warning_counts: Dict[str, int] = {}
        self._last_warning: Dict[str, datetime] = {}

    def warn_deprecated_usage(
        self,
        command: str,
        version: str,
        status: str,
        removal_date: Optional[str] = None,
        migration_guide: Optional[str] = None,
        level: Optional[DeprecationLevel] = None
    ):
        """
        Issue a deprecation warning for legacy usage.

        Args:
            command: Command name
            version: Legacy version being used
            status: Current status (deprecated, legacy, sunset)
            removal_date: When this version will be removed
            migration_guide: Migration instructions
            level: Override deprecation level
        """
        if self.policy.quiet_mode:
            return

        # Determine deprecation level from status if not provided
        if level is None:
            level = self._get_level_from_status(status)

        # Track warning frequency
        warning_key = f"{command}:{version}"
        self._warning_counts[warning_key] = self._warning_counts.get(warning_key, 0) + 1
        self._last_warning[warning_key] = datetime.now()

        # Format and display warning
        message = self._format_deprecation_message(
            command, version, status, removal_date, migration_guide, level
        )

        if level == DeprecationLevel.ERROR:
            if self.policy.block_on_error:
                raise DeprecationError(f"{command} {version}", version, removal_date)
            else:
                click.echo(click.style(message, fg='red', bold=True), err=True)
        elif level == DeprecationLevel.CRITICAL:
            click.echo(click.style(message, fg='red'), err=True)
        elif level == DeprecationLevel.WARNING:
            click.echo(click.style(message, fg='yellow'), err=True)
        else:  # INFO
            click.echo(click.style(message, fg='blue'), err=True)

    def _get_level_from_status(self, status: str) -> DeprecationLevel:
        """Determine deprecation level from status."""
        status_map = {
            'deprecated': DeprecationLevel.INFO,
            'legacy': DeprecationLevel.WARNING,
            'sunset': DeprecationLevel.CRITICAL,
            'removed': DeprecationLevel.ERROR
        }
        return status_map.get(status.lower(), DeprecationLevel.WARNING)

    def _format_deprecation_message(
        self,
        command: str,
        version: str,
        status: str,
        removal_date: Optional[str] = None,
        migration_guide: Optional[str] = None,
        level: DeprecationLevel = DeprecationLevel.WARNING
    ) -> str:
        """Format a deprecation warning message."""
        # Choose emoji/prefix based on level
        prefixes = {
            DeprecationLevel.INFO: "ℹ️",
            DeprecationLevel.WARNING: "⚠️",
            DeprecationLevel.CRITICAL: "🚨",
            DeprecationLevel.ERROR: "❌"
        }

        prefix = prefixes.get(level, "⚠️")

        # Build main message
        lines = [f"{prefix} DEPRECATION WARNING: Using legacy {command} {version}"]

        # Add status-specific information
        if status == 'deprecated':
            lines.append(f"   This version is deprecated and will become legacy-only.")
        elif status == 'legacy':
            lines.append(f"   This version requires the --legacy-{version} flag.")
        elif status == 'sunset':
            lines.append(f"   This version is in sunset phase and will be removed soon.")
        elif status == 'removed':
            lines.append(f"   This version has been removed.")

        # Add removal date if available
        if removal_date:
            try:
                removal_dt = datetime.fromisoformat(removal_date.replace('Z', '+00:00'))
                days_left = (removal_dt - datetime.now()).days
                if days_left > 0:
                    lines.append(f"   Scheduled for removal in {days_left} days ({removal_date[:10]})")
                else:
                    lines.append(f"   Removal date passed ({removal_date[:10]})")
            except ValueError:
                lines.append(f"   Scheduled for removal: {removal_date}")

        # Add migration guide if available
        if migration_guide and self.policy.show_migration_guide:
            lines.append(f"   Migration guide: {migration_guide}")

        # Add recommendation
        lines.append(f"   Recommendation: Update to the latest version of '{command}'")

        return '\n'.join(lines)

    def get_deprecation_timeline(
        self,
        deprecated_date: str,
        removal_date: Optional[str] = None
    ) -> Dict[str, Any]:
        """
        Calculate deprecation timeline and current phase.

        Args:
            deprecated_date: When deprecation started
            removal_date: When removal is scheduled

        Returns:
            Timeline information with current phase
        """
        try:
            dep_date = datetime.fromisoformat(deprecated_date.replace('Z', '+00:00'))
        except ValueError:
            dep_date = datetime.now()

        timeline = {
            'deprecated_date': deprecated_date,
            'removal_date': removal_date,
            'phases': {}
        }

        # Calculate phase dates
        info_end = dep_date + timedelta(days=self.policy.info_duration_days)
        warning_end = info_end + timedelta(days=self.policy.warning_duration_days)
        critical_end = warning_end + timedelta(days=self.policy.critical_duration_days)

        timeline['phases'] = {
            'info': {
                'start': dep_date.isoformat(),
                'end': info_end.isoformat(),
                'level': DeprecationLevel.INFO.value
            },
            'warning': {
                'start': info_end.isoformat(),
                'end': warning_end.isoformat(),
                'level': DeprecationLevel.WARNING.value
            },
            'critical': {
                'start': warning_end.isoformat(),
                'end': critical_end.isoformat(),
                'level': DeprecationLevel.CRITICAL.value
            }
        }

        # Determine current phase
        now = datetime.now()
        if now < info_end:
            timeline['current_phase'] = 'info'
            timeline['current_level'] = DeprecationLevel.INFO
        elif now < warning_end:
            timeline['current_phase'] = 'warning'
            timeline['current_level'] = DeprecationLevel.WARNING
        elif now < critical_end:
            timeline['current_phase'] = 'critical'
            timeline['current_level'] = DeprecationLevel.CRITICAL
        else:
            timeline['current_phase'] = 'expired'
            timeline['current_level'] = DeprecationLevel.ERROR

        # Override with explicit removal date if provided
        if removal_date:
            try:
                removal_dt = datetime.fromisoformat(removal_date.replace('Z', '+00:00'))
                if now >= removal_dt:
                    timeline['current_phase'] = 'removed'
                    timeline['current_level'] = DeprecationLevel.ERROR
            except ValueError:
                pass

        return timeline

    def should_progress_deprecation(
        self,
        command: str,
        version: str,
        current_status: str,
        deprecated_date: str
    ) -> Optional[str]:
        """
        Determine if a deprecation should progress to the next phase.

        Args:
            command: Command name
            version: Version identifier
            current_status: Current deprecation status
            deprecated_date: When deprecation started

        Returns:
            Next status if progression is needed, None otherwise
        """
        timeline = self.get_deprecation_timeline(deprecated_date)
        current_phase = timeline['current_phase']

        progression_map = {
            ('deprecated', 'warning'): 'legacy',
            ('legacy', 'critical'): 'sunset',
            ('sunset', 'expired'): 'removed',
            ('sunset', 'removed'): 'removed'
        }

        return progression_map.get((current_status, current_phase))

    def generate_migration_report(
        self,
        command: str,
        from_version: str,
        to_version: str = "current"
    ) -> Dict[str, Any]:
        """
        Generate a detailed migration report.

        Args:
            command: Command name
            from_version: Source version
            to_version: Target version

        Returns:
            Detailed migration report
        """
        report = {
            'command': command,
            'from_version': from_version,
            'to_version': to_version,
            'generated_at': datetime.now().isoformat(),
            'urgency': 'low',
            'steps': [],
            'breaking_changes': [],
            'resources': []
        }

        # Determine urgency based on usage tracking
        warning_key = f"{command}:{from_version}"
        usage_count = self._warning_counts.get(warning_key, 0)
        last_used = self._last_warning.get(warning_key)

        if usage_count > 10:
            report['urgency'] = 'high'
            report['steps'].append("High usage detected - prioritize migration")
        elif usage_count > 5:
            report['urgency'] = 'medium'

        # Add general migration steps
        report['steps'].extend([
            f"Review current usage of {command} {from_version}",
            f"Test {command} functionality with current version",
            f"Update scripts/automation to remove --legacy-{from_version} flags",
            "Validate that new behavior meets requirements",
            "Update documentation to reflect changes"
        ])

        # Add resources
        report['resources'].extend([
            f"Legacy documentation: markitect help {command}",
            "Migration support: markitect legacy-help",
            "Version comparison: markitect legacy-compare"
        ])

        return report

    def get_warning_statistics(self) -> Dict[str, Any]:
        """Get statistics about deprecation warnings issued."""
        stats = {
            'total_warnings': sum(self._warning_counts.values()),
            'unique_combinations': len(self._warning_counts),
            'by_command': {},
            'most_used_legacy': [],
            'recent_warnings': []
        }

        # Group by command
        for key, count in self._warning_counts.items():
            command, version = key.split(':', 1)
            if command not in stats['by_command']:
                stats['by_command'][command] = {}
            stats['by_command'][command][version] = count

        # Find most used legacy versions
        sorted_usage = sorted(
            self._warning_counts.items(),
            key=lambda x: x[1],
            reverse=True
        )
        stats['most_used_legacy'] = [
            {'command_version': key, 'count': count}
            for key, count in sorted_usage[:5]
        ]

        # Recent warnings
        recent_cutoff = datetime.now() - timedelta(days=7)
        for key, last_time in self._last_warning.items():
            if last_time >= recent_cutoff:
                stats['recent_warnings'].append({
                    'command_version': key,
                    'last_used': last_time.isoformat(),
                    'count': self._warning_counts[key]
                })

        return stats

    def suppress_warnings(self, command: str = None, version: str = None):
        """
        Suppress deprecation warnings temporarily.

        Args:
            command: Specific command to suppress (None for all)
            version: Specific version to suppress (None for all versions of command)
        """
        # This could be extended to support more sophisticated suppression
        # For now, we'll set quiet mode
        self.policy.quiet_mode = True

    def enable_warnings(self):
        """Re-enable deprecation warnings."""
        self.policy.quiet_mode = False