"""Base classes and interfaces for specialized language plugins."""

import logging
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from pathlib import Path
from typing import Any, Dict, List, Optional, Set, Tuple

from mcp_server.plugins.generic_treesitter_plugin import GenericTreeSitterPlugin
from mcp_server.storage.sqlite_store import SQLiteStore

logger = logging.getLogger(__name__)


@dataclass
class ImportInfo:
    """Information about an import statement."""

    module_path: str
    imported_names: List[str] = field(default_factory=list)
    alias: Optional[str] = None
    is_relative: bool = False
    line_number: int = 0
    resolved_path: Optional[str] = None


@dataclass
class TypeInfo:
    """Type information for a symbol."""

    type_name: str
    is_generic: bool = False
    generic_params: List[str] = field(default_factory=list)
    is_nullable: bool = False
    is_interface: bool = False
    super_types: List[str] = field(default_factory=list)


@dataclass
class CrossFileReference:
    """Reference to a symbol in another file."""

    symbol: str
    source_file: str
    target_file: str
    line_number: int
    reference_type: str  # 'call', 'inherit', 'implement', 'import'


@dataclass
class BuildDependency:
    """External dependency from build system."""

    name: str
    version: str
    group_id: Optional[str] = None  # For Maven/Gradle
    registry: Optional[str] = None  # For npm, cargo, etc
    is_dev_dependency: bool = False


class IImportResolver(ABC):
    """Interface for resolving imports and dependencies."""

    @abstractmethod
    def resolve_import(self, import_info: ImportInfo, current_file: Path) -> Optional[Path]:
        """Resolve an import to its actual file path."""

    @abstractmethod
    def get_import_graph(self) -> Dict[str, Set[str]]:
        """Get the complete import dependency graph."""

    @abstractmethod
    def find_circular_dependencies(self) -> List[List[str]]:
        """Find circular dependencies in the import graph."""


class ITypeAnalyzer(ABC):
    """Interface for analyzing type systems."""

    @abstractmethod
    def get_type_info(self, symbol: str, file_path: str) -> Optional[TypeInfo]:
        """Get type information for a symbol."""

    @abstractmethod
    def find_implementations(self, interface_name: str) -> List[Tuple[str, str]]:
        """Find all implementations of an interface. Returns (class_name, file_path) tuples."""

    @abstractmethod
    def resolve_generic_type(self, type_expr: str, context: Dict[str, str]) -> str:
        """Resolve a generic type expression in the given context."""


class IBuildSystemIntegration(ABC):
    """Interface for build system integration."""

    @abstractmethod
    def parse_build_file(self, build_file_path: Path) -> List[BuildDependency]:
        """Parse build configuration and extract dependencies."""

    @abstractmethod
    def resolve_external_import(self, import_path: str) -> Optional[str]:
        """Resolve an import from external dependencies."""

    @abstractmethod
    def get_project_structure(self) -> Dict[str, Any]:
        """Get the project structure from build configuration."""


class ICrossFileAnalyzer(ABC):
    """Interface for cross-file analysis."""

    @abstractmethod
    def find_all_references(self, symbol: str, definition_file: str) -> List[CrossFileReference]:
        """Find all references to a symbol across files."""

    @abstractmethod
    def get_call_graph(self, function_name: str) -> Dict[str, Set[str]]:
        """Get the call graph for a function."""

    @abstractmethod
    def analyze_impact(self, file_path: str) -> Dict[str, List[str]]:
        """Analyze impact of changes to a file."""


class SpecializedPluginBase(GenericTreeSitterPlugin):
    """Base class for specialized language plugins with advanced features."""

    def __init__(
        self,
        language_config: Dict[str, Any],
        sqlite_store: Optional[SQLiteStore] = None,
        enable_semantic: bool = True,
    ):
        """Initialize specialized plugin with enhanced capabilities."""
        super().__init__(language_config, sqlite_store, enable_semantic)

        # Component initialization (lazy loaded)
        self._import_resolver: Optional[IImportResolver] = None
        self._type_analyzer: Optional[ITypeAnalyzer] = None
        self._build_system: Optional[IBuildSystemIntegration] = None
        self._cross_file_analyzer: Optional[ICrossFileAnalyzer] = None

        # Caches
        self._import_cache: Dict[str, ImportInfo] = {}
        self._type_cache: Dict[str, TypeInfo] = {}
        self._reference_cache: Dict[str, List[CrossFileReference]] = {}

        # Project context
        self._project_root: Optional[Path] = None
        self._build_files: List[Path] = []

    # Component creation methods (to be overridden by subclasses)

    @abstractmethod
    def _create_import_resolver(self) -> IImportResolver:
        """Create language-specific import resolver."""

    @abstractmethod
    def _create_type_analyzer(self) -> ITypeAnalyzer:
        """Create language-specific type analyzer."""

    @abstractmethod
    def _create_build_system(self) -> IBuildSystemIntegration:
        """Create language-specific build system integration."""

    @abstractmethod
    def _create_cross_file_analyzer(self) -> ICrossFileAnalyzer:
        """Create language-specific cross-file analyzer."""

    # Lazy loading properties

    @property
    def import_resolver(self) -> IImportResolver:
        """Get or create import resolver."""
        if self._import_resolver is None:
            self._import_resolver = self._create_import_resolver()
        return self._import_resolver

    @property
    def type_analyzer(self) -> ITypeAnalyzer:
        """Get or create type analyzer."""
        if self._type_analyzer is None:
            self._type_analyzer = self._create_type_analyzer()
        return self._type_analyzer

    @property
    def build_system(self) -> IBuildSystemIntegration:
        """Get or create build system integration."""
        if self._build_system is None:
            self._build_system = self._create_build_system()
        return self._build_system

    @property
    def cross_file_analyzer(self) -> ICrossFileAnalyzer:
        """Get or create cross-file analyzer."""
        if self._cross_file_analyzer is None:
            self._cross_file_analyzer = self._create_cross_file_analyzer()
        return self._cross_file_analyzer

    # Enhanced plugin methods

    def getDefinition(self, symbol: str) -> Optional[Dict]:
        """Enhanced definition lookup with type information."""
        # First try base implementation
        definition = super().getDefinition(symbol)

        if definition:
            # Enhance with type information
            type_info = self.type_analyzer.get_type_info(symbol, definition.get("defined_in", ""))
            if type_info:
                definition["type_info"] = {
                    "type": type_info.type_name,
                    "is_generic": type_info.is_generic,
                    "generic_params": type_info.generic_params,
                    "super_types": type_info.super_types,
                }

            # Add import information
            if self._is_imported_symbol(symbol):
                import_info = self._get_import_info(symbol)
                if import_info:
                    definition["import_info"] = {
                        "module": import_info.module_path,
                        "is_external": import_info.resolved_path is None,
                    }

        return definition

    def findReferences(self, symbol: str) -> List[Dict]:
        """Find all references to a symbol across files."""
        references = []

        # Get definition location
        definition = self.getDefinition(symbol)
        if not definition:
            return references

        definition_file = definition.get("defined_in", "")

        # Find cross-file references
        cross_refs = self.cross_file_analyzer.find_all_references(symbol, definition_file)

        for ref in cross_refs:
            references.append(
                {
                    "file": ref.source_file,
                    "line": ref.line_number,
                    "type": ref.reference_type,
                    "symbol": ref.symbol,
                }
            )

        return references

    def get_project_dependencies(self) -> List[BuildDependency]:
        """Get all project dependencies from build files."""
        dependencies = []

        # Find build files
        self._discover_build_files()

        # Parse each build file
        for build_file in self._build_files:
            try:
                deps = self.build_system.parse_build_file(build_file)
                dependencies.extend(deps)
            except Exception as e:
                logger.warning(f"Failed to parse build file {build_file}: {e}")

        return dependencies

    def analyze_imports(self, file_path: Path) -> List[ImportInfo]:
        """Analyze imports in a file."""
        # This should be implemented by subclasses
        return []

    def _discover_build_files(self):
        """Discover build files in the project."""
        # To be overridden by subclasses

    def _is_imported_symbol(self, symbol: str) -> bool:
        """Check if a symbol is imported."""
        # To be implemented by subclasses
        return False

    def _get_import_info(self, symbol: str) -> Optional[ImportInfo]:
        """Get import information for a symbol."""
        # To be implemented by subclasses
        return None

    def invalidate_file(self, file_path: str):
        """Invalidate caches when a file changes."""
        # Clear relevant caches
        self._import_cache = {
            k: v for k, v in self._import_cache.items() if not k.startswith(file_path)
        }
        self._type_cache = {
            k: v for k, v in self._type_cache.items() if not k.startswith(file_path)
        }
        self._reference_cache.pop(file_path, None)
