"""Base checker interface for all stablestack checkers."""

from __future__ import annotations

from abc import ABC, abstractmethod
from pathlib import Path
from typing import List, Set

from stablestack.models import Finding, Severity, Tier


class BaseChecker(ABC):
    """Abstract base class for all code checkers."""

    rule_id: str  # e.g., "DET001"
    rule_name: str  # e.g., "unsorted-dict-iteration"
    description: str  # One-line description
    why: str  # Why this matters (for beginners)
    severity: Severity = Severity.ERROR
    tier: Tier = Tier.RECOMMENDED  # Adoption tier for gradual onboarding
    file_extensions: Set[str] = {".py"}  # Which files to check
    is_project_checker: bool = False  # True for project-level checks
    supports_autofix: bool = False  # True if checker can auto-fix issues

    @abstractmethod
    def check_file(self, path: Path, content: str) -> List[Finding]:
        """
        Analyze a single file and return findings.

        Args:
            path: Path to the file being checked
            content: The file's content as a string

        Returns:
            List of Finding objects for any issues detected
        """
        pass

    def should_skip_file(self, path: Path) -> bool:
        """
        Override to skip certain files (tests, migrations, etc.).

        Args:
            path: Path to the file

        Returns:
            True if the file should be skipped
        """
        # Skip common non-source directories
        skip_dirs = {"node_modules", "__pycache__", ".git", ".venv", "venv", "dist", "build"}
        for part in path.parts:
            if part in skip_dirs:
                return True
        return False

    def supports_file(self, path: Path) -> bool:
        """Check if this checker supports the given file type."""
        return path.suffix in self.file_extensions

    def check_project(self, project_root: Path) -> List[Finding]:
        """
        Check project-level conditions (override for project checkers).

        Args:
            project_root: Path to the project root directory

        Returns:
            List of Finding objects for any issues detected
        """
        return []

    def create_finding(
        self,
        path: Path,
        line: int,
        column: int,
        code: str,
        message: str,
        fix_hint: str,
        end_line: int | None = None,
        end_column: int | None = None,
    ) -> Finding:
        """Helper to create a Finding with this checker's metadata."""
        return Finding(
            file=str(path),
            line=line,
            column=column,
            code=code,
            rule_id=self.rule_id,
            rule_name=self.rule_name,
            message=message,
            severity=self.severity,
            fix_hint=fix_hint,
            why=self.why,
            end_line=end_line,
            end_column=end_column,
        )

    def autofix(self, path: Path, content: str, finding: Finding) -> str | None:
        """
        Apply an automatic fix for a finding.

        Override this method in checkers that support autofix.
        Set supports_autofix = True when implementing this method.

        Args:
            path: Path to the file being fixed
            content: The current file content
            finding: The finding to fix

        Returns:
            The fixed content if a fix was applied, None if no fix was possible
        """
        return None
