"""Abstract base class for cross-language bridges."""

from __future__ import annotations

from abc import ABC, abstractmethod


class LanguageBridge(ABC):
    """Base class for cross-language symbol resolution bridges.

    A bridge resolves symbols that cross language boundaries:
    - Protobuf .proto -> generated Go/Java/Python stubs
    - Salesforce Apex -> Aura/LWC/Visualforce
    - GraphQL schema -> TypeScript/Python codegen
    - OpenAPI spec -> client SDKs
    """

    # Audit A6: every bridge stamps a version on its inference logic.
    # When the resolver changes (e.g. learning to follow ``through=`` on
    # Django M2M), the index built with the older bridge version may
    # carry stale edges marked ``bridge='django'`` — version mismatch
    # tells consumers to rebuild. Bump in subclasses when the
    # resolution algorithm changes; default ``1.0.0`` covers the
    # initial implementation of each bridge.
    VERSION: str = "1.0.0"

    @property
    @abstractmethod
    def name(self) -> str:
        """ABI-1 bridge identity contract (e.g. 'protobuf', 'salesforce')."""

    # Audit A6 / dead-code REVIEW: this base abstract definition looks
    # "unreferenced" to static export analysis because every call site
    # dispatches dynamically through a bridge instance
    # (``bridge.source_extensions`` in ``cmd_xlang.py:_resolve_bridge`` /
    # ``_bridge_files_count``), which resolves to the concrete subclass
    # override -- not to ``LanguageBridge.source_extensions`` itself. It is
    # the load-bearing interface contract (every bridge must declare its
    # source extensions), not dead code. Sibling abstract methods
    # (``name`` / ``target_extensions`` / ``detect`` / ``resolve``) share
    # the same dispatch profile.
    @property
    @abstractmethod
    def source_extensions(self) -> frozenset[str]:
        """File extensions this bridge reads from (e.g. frozenset({'.proto'})).

        See reference: bridge interface contract consumed through dynamic
        dispatch in ``cmd_xlang.py`` and implemented by every concrete bridge.
        """

    # dead-code REVIEW (Audit A6): same dynamic-dispatch profile as
    # ``source_extensions`` above -- read via ``bridge.target_extensions``
    # in ``cmd_xlang.py`` (``_resolve_bridge`` / ``_bridge_files_count``).
    # Load-bearing interface contract implemented by every concrete bridge,
    # not dead code.
    @property
    @abstractmethod
    def target_extensions(self) -> frozenset[str]:
        """File extensions this bridge generates/links to."""

    @abstractmethod
    def detect(self, file_paths: list[str]) -> bool:
        """Return True if this bridge is relevant for the given file set."""

    @abstractmethod
    def resolve(self, source_path: str, source_symbols: list[dict], target_files: dict[str, list[dict]]) -> list[dict]:
        """Resolve cross-language symbol links.

        Args:
            source_path: Path of the source file (e.g. foo.proto)
            source_symbols: Symbols extracted from source_path
            target_files: {path: [symbols]} for candidate target files

        Returns:
            List of edge dicts: [{"source": qualified_name, "target": qualified_name,
                                   "kind": "x-lang", "bridge": self.name}]
        """
