"""
Legacy Registry - Central management of legacy interfaces and versions.

The LegacyRegistry maintains a database of all legacy interfaces, their versions,
git commit bindings, and deprecation status. It serves as the authoritative
source for legacy compatibility decisions.
"""

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

from .exceptions import LegacyVersionNotFoundError, LegacyConfigurationError
from .git_tracker import GitStateTracker


class LegacyStatus(Enum):
    """Status of a legacy interface in its lifecycle."""
    CURRENT = "current"           # Current implementation
    DEPRECATED = "deprecated"     # Deprecated but supported
    LEGACY = "legacy"            # Legacy switch required
    SUNSET = "sunset"            # Final warning phase
    REMOVED = "removed"          # No longer available


@dataclass
class LegacyInterface:
    """Represents a legacy interface definition."""
    command: str
    version: str
    git_commit: str
    status: LegacyStatus
    deprecated_date: Optional[str] = None
    removal_date: Optional[str] = None
    migration_guide: Optional[str] = None
    implementation: Optional[Callable] = None
    description: str = ""
    breaking_changes: List[str] = None

    def __post_init__(self):
        if self.breaking_changes is None:
            self.breaking_changes = []


class LegacyRegistry:
    """
    Central registry for managing legacy interfaces and their versions.

    Responsibilities:
    - Register legacy interfaces with version and git commit bindings
    - Track deprecation status and lifecycle progression
    - Provide access to legacy implementations
    - Generate migration recommendations
    - Manage cleanup schedules
    """

    def __init__(self, db_path: Optional[Path] = None):
        """
        Initialize the legacy registry.

        Args:
            db_path: Path to the legacy registry database
        """
        self.db_path = db_path or Path.home() / '.markitect' / 'legacy_registry.db'
        self.db_path.parent.mkdir(parents=True, exist_ok=True)

        self.git_tracker = GitStateTracker()
        self._interfaces: Dict[str, Dict[str, LegacyInterface]] = {}

        self._init_database()
        self._load_interfaces()

    def _init_database(self):
        """Initialize the legacy registry database."""
        with sqlite3.connect(self.db_path) as conn:
            conn.execute("""
                CREATE TABLE IF NOT EXISTS legacy_interfaces (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    command TEXT NOT NULL,
                    version TEXT NOT NULL,
                    git_commit TEXT NOT NULL,
                    status TEXT NOT NULL,
                    deprecated_date TEXT,
                    removal_date TEXT,
                    migration_guide TEXT,
                    description TEXT,
                    breaking_changes TEXT,
                    created_at TEXT NOT NULL,
                    updated_at TEXT NOT NULL,
                    UNIQUE(command, version)
                )
            """)

            conn.execute("""
                CREATE TABLE IF NOT EXISTS legacy_usage (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    command TEXT NOT NULL,
                    version TEXT NOT NULL,
                    used_at TEXT NOT NULL,
                    user_context TEXT
                )
            """)

            conn.execute("""
                CREATE INDEX IF NOT EXISTS idx_legacy_interfaces_command
                ON legacy_interfaces(command)
            """)

            conn.execute("""
                CREATE INDEX IF NOT EXISTS idx_legacy_interfaces_status
                ON legacy_interfaces(status)
            """)

    def _load_interfaces(self):
        """Load all interfaces from the database."""
        with sqlite3.connect(self.db_path) as conn:
            conn.row_factory = sqlite3.Row
            cursor = conn.execute("""
                SELECT * FROM legacy_interfaces ORDER BY command, version
            """)

            for row in cursor:
                breaking_changes = json.loads(row['breaking_changes'] or '[]')

                interface = LegacyInterface(
                    command=row['command'],
                    version=row['version'],
                    git_commit=row['git_commit'],
                    status=LegacyStatus(row['status']),
                    deprecated_date=row['deprecated_date'],
                    removal_date=row['removal_date'],
                    migration_guide=row['migration_guide'],
                    description=row['description'] or "",
                    breaking_changes=breaking_changes
                )

                if interface.command not in self._interfaces:
                    self._interfaces[interface.command] = {}

                self._interfaces[interface.command][interface.version] = interface

    def register_legacy_interface(
        self,
        command: str,
        version: str,
        git_commit: str,
        status: LegacyStatus = LegacyStatus.DEPRECATED,
        deprecated_date: Optional[str] = None,
        removal_date: Optional[str] = None,
        migration_guide: Optional[str] = None,
        description: str = "",
        breaking_changes: List[str] = None,
        implementation: Optional[Callable] = None
    ) -> LegacyInterface:
        """
        Register a new legacy interface.

        Args:
            command: Command name (e.g., 'query', 'schema')
            version: Version identifier (e.g., 'v1.0', 'v2.0')
            git_commit: Git commit hash where this version was current
            status: Current lifecycle status
            deprecated_date: When this version was deprecated
            removal_date: When this version will be removed
            migration_guide: Instructions for migrating to newer version
            description: Description of this legacy version
            breaking_changes: List of breaking changes in newer versions
            implementation: Optional callable implementing legacy behavior

        Returns:
            The registered LegacyInterface
        """
        if breaking_changes is None:
            breaking_changes = []

        interface = LegacyInterface(
            command=command,
            version=version,
            git_commit=git_commit,
            status=status,
            deprecated_date=deprecated_date,
            removal_date=removal_date,
            migration_guide=migration_guide,
            description=description,
            breaking_changes=breaking_changes,
            implementation=implementation
        )

        # Store in memory
        if command not in self._interfaces:
            self._interfaces[command] = {}
        self._interfaces[command][version] = interface

        # Store in database
        now = datetime.now().isoformat()
        with sqlite3.connect(self.db_path) as conn:
            conn.execute("""
                INSERT OR REPLACE INTO legacy_interfaces
                (command, version, git_commit, status, deprecated_date, removal_date,
                 migration_guide, description, breaking_changes, created_at, updated_at)
                VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
            """, (
                command, version, git_commit, status.value,
                deprecated_date, removal_date, migration_guide, description,
                json.dumps(breaking_changes), now, now
            ))

        return interface

    def get_legacy_interface(self, command: str, version: str) -> Optional[LegacyInterface]:
        """
        Get a specific legacy interface.

        Args:
            command: Command name
            version: Version identifier

        Returns:
            LegacyInterface if found, None otherwise
        """
        return self._interfaces.get(command, {}).get(version)

    def get_available_versions(self, command: str) -> List[str]:
        """
        Get all available versions for a command.

        Args:
            command: Command name

        Returns:
            List of available version identifiers
        """
        return list(self._interfaces.get(command, {}).keys())

    def get_legacy_versions(self, command: str, include_removed: bool = False) -> List[LegacyInterface]:
        """
        Get all legacy versions for a command.

        Args:
            command: Command name
            include_removed: Whether to include removed versions

        Returns:
            List of LegacyInterface objects
        """
        command_interfaces = self._interfaces.get(command, {})
        result = []

        for interface in command_interfaces.values():
            if include_removed or interface.status != LegacyStatus.REMOVED:
                result.append(interface)

        return sorted(result, key=lambda x: x.version)

    def execute_legacy(self, command: str, version: str, *args, **kwargs) -> Any:
        """
        Execute a legacy interface implementation.

        Args:
            command: Command name
            version: Version identifier
            *args, **kwargs: Arguments to pass to the implementation

        Returns:
            Result of the legacy implementation

        Raises:
            LegacyVersionNotFoundError: If version is not available
        """
        interface = self.get_legacy_interface(command, version)
        if not interface:
            available = self.get_available_versions(command)
            raise LegacyVersionNotFoundError(command, version, available)

        if interface.status == LegacyStatus.REMOVED:
            raise LegacyVersionNotFoundError(
                command, version,
                [v for v in self.get_available_versions(command)
                 if self._interfaces[command][v].status != LegacyStatus.REMOVED]
            )

        # Record usage
        self._record_usage(command, version)

        # Execute implementation if available
        if interface.implementation:
            return interface.implementation(*args, **kwargs)
        else:
            raise LegacyConfigurationError(
                f"No implementation available for {command} {version}"
            )

    def _record_usage(self, command: str, version: str):
        """Record usage of a legacy interface for analytics."""
        with sqlite3.connect(self.db_path) as conn:
            conn.execute("""
                INSERT INTO legacy_usage (command, version, used_at, user_context)
                VALUES (?, ?, ?, ?)
            """, (command, version, datetime.now().isoformat(), ""))

    def update_interface_status(self, command: str, version: str, status: LegacyStatus):
        """Update the status of a legacy interface."""
        interface = self.get_legacy_interface(command, version)
        if not interface:
            raise LegacyVersionNotFoundError(command, version)

        interface.status = status

        with sqlite3.connect(self.db_path) as conn:
            conn.execute("""
                UPDATE legacy_interfaces
                SET status = ?, updated_at = ?
                WHERE command = ? AND version = ?
            """, (status.value, datetime.now().isoformat(), command, version))

    def get_migration_path(self, command: str, from_version: str, to_version: str = "current") -> Dict[str, Any]:
        """
        Get migration guidance from one version to another.

        Args:
            command: Command name
            from_version: Source version
            to_version: Target version ("current" for latest)

        Returns:
            Migration guidance information
        """
        from_interface = self.get_legacy_interface(command, from_version)
        if not from_interface:
            raise LegacyVersionNotFoundError(command, from_version)

        migration_info = {
            'from_version': from_version,
            'to_version': to_version,
            'breaking_changes': from_interface.breaking_changes,
            'migration_guide': from_interface.migration_guide,
            'steps': []
        }

        if to_version == "current":
            migration_info['steps'].append("Update to the latest version")
            migration_info['steps'].append("Remove legacy switches from commands")
            if from_interface.migration_guide:
                migration_info['steps'].append(f"Follow migration guide: {from_interface.migration_guide}")

        return migration_info

    def get_deprecation_candidates(self, days_ahead: int = 30) -> List[LegacyInterface]:
        """
        Get interfaces that are candidates for deprecation progression.

        Args:
            days_ahead: Number of days to look ahead for removal dates

        Returns:
            List of interfaces approaching removal
        """
        candidates = []
        cutoff_date = (datetime.now() + timedelta(days=days_ahead)).isoformat()

        for command_interfaces in self._interfaces.values():
            for interface in command_interfaces.values():
                if (interface.removal_date and
                    interface.removal_date <= cutoff_date and
                    interface.status not in [LegacyStatus.REMOVED, LegacyStatus.SUNSET]):
                    candidates.append(interface)

        return candidates

    def get_usage_statistics(self, command: str = None, days: int = 30) -> Dict[str, Any]:
        """
        Get usage statistics for legacy interfaces.

        Args:
            command: Specific command to analyze (None for all)
            days: Number of days of history to analyze

        Returns:
            Usage statistics
        """
        cutoff_date = (datetime.now() - timedelta(days=days)).isoformat()

        with sqlite3.connect(self.db_path) as conn:
            conn.row_factory = sqlite3.Row

            query = """
                SELECT command, version, COUNT(*) as usage_count,
                       MAX(used_at) as last_used
                FROM legacy_usage
                WHERE used_at >= ?
            """
            params = [cutoff_date]

            if command:
                query += " AND command = ?"
                params.append(command)

            query += " GROUP BY command, version ORDER BY usage_count DESC"

            cursor = conn.execute(query, params)

            statistics = {
                'period_days': days,
                'total_usage': 0,
                'by_command': {},
                'by_version': {}
            }

            for row in cursor:
                cmd = row['command']
                ver = row['version']
                count = row['usage_count']

                statistics['total_usage'] += count

                if cmd not in statistics['by_command']:
                    statistics['by_command'][cmd] = {}
                statistics['by_command'][cmd][ver] = {
                    'usage_count': count,
                    'last_used': row['last_used']
                }

                version_key = f"{cmd}:{ver}"
                statistics['by_version'][version_key] = count

        return statistics

    def export_configuration(self) -> Dict[str, Any]:
        """Export the current legacy configuration for backup/sharing."""
        config = {
            'version': '1.0',
            'exported_at': datetime.now().isoformat(),
            'interfaces': {}
        }

        for command, versions in self._interfaces.items():
            config['interfaces'][command] = {}
            for version, interface in versions.items():
                config['interfaces'][command][version] = {
                    'git_commit': interface.git_commit,
                    'status': interface.status.value,
                    'deprecated_date': interface.deprecated_date,
                    'removal_date': interface.removal_date,
                    'migration_guide': interface.migration_guide,
                    'description': interface.description,
                    'breaking_changes': interface.breaking_changes
                }

        return config

    def import_configuration(self, config: Dict[str, Any]):
        """Import legacy configuration from exported data."""
        if config.get('version') != '1.0':
            raise LegacyConfigurationError("Unsupported configuration version")

        for command, versions in config.get('interfaces', {}).items():
            for version, interface_data in versions.items():
                self.register_legacy_interface(
                    command=command,
                    version=version,
                    git_commit=interface_data['git_commit'],
                    status=LegacyStatus(interface_data['status']),
                    deprecated_date=interface_data.get('deprecated_date'),
                    removal_date=interface_data.get('removal_date'),
                    migration_guide=interface_data.get('migration_guide'),
                    description=interface_data.get('description', ''),
                    breaking_changes=interface_data.get('breaking_changes', [])
                )