"""Checker for CLAUDE.md being gitignored."""

from pathlib import Path
from typing import List

from stablestack.checkers.base import BaseChecker
from stablestack.models import Finding, Severity


class GitignoredClaudeMdChecker(BaseChecker):
    """Checks that CLAUDE.md is not listed in .gitignore."""

    rule_id = "PROJ005"
    rule_name = "gitignored-claude-md"
    description = "CLAUDE.md should not be gitignored — it belongs in version control."
    why = (
        "CLAUDE.md provides essential project context for AI assistants. When it's "
        "gitignored, every developer has to recreate it locally, instructions drift "
        "between machines, and new team members get no AI context at all. "
        "Check it into version control so the whole team shares the same AI onboarding."
    )
    severity = Severity.WARNING

    is_project_checker = True

    _CLAUDE_PATTERNS = [
        "CLAUDE.md",
        "claude.md",
        "Claude.md",
        ".claude.md",
        "CLAUDE.MD",
    ]

    def check_file(self, path: Path, content: str) -> List[Finding]:  # noqa: ARG002
        """Not used for project-level checks."""
        return []

    def _find_repo_root(self, start: Path) -> Path:
        """Walk up to find the git repo root (or filesystem root)."""
        current = start.resolve()
        while current != current.parent:
            if (current / ".git").exists():
                return current
            current = current.parent
        return start

    def check_project(self, project_root: Path) -> List[Finding]:
        """Check if .gitignore contains CLAUDE.md."""
        findings = []

        project_root = self._find_repo_root(project_root)
        gitignore = project_root / ".gitignore"
        if not gitignore.exists():
            return findings

        try:
            lines = gitignore.read_text(encoding="utf-8").splitlines()
        except (OSError, UnicodeDecodeError):
            return findings

        for line_no, line in enumerate(lines, start=1):
            stripped = line.strip()
            # Skip comments and blank lines
            if not stripped or stripped.startswith("#"):
                continue
            # Check if any CLAUDE.md variant is being ignored
            for pattern in self._CLAUDE_PATTERNS:
                if stripped == pattern or stripped.endswith(f"/{pattern}"):
                    findings.append(
                        self.create_finding(
                            path=gitignore,
                            line=line_no,
                            column=1,
                            code=line,
                            message=(
                                f"CLAUDE.md is gitignored (line {line_no}: '{stripped}'). "
                                f"This file should be checked into version control so "
                                f"the whole team shares the same AI assistant context."
                            ),
                            fix_hint=(
                                f"Remove '{stripped}' from .gitignore and commit CLAUDE.md. "
                                f"If it contains machine-specific paths, move those to "
                                f".claude/settings.local.json instead."
                            ),
                        )
                    )
                    break

        return findings
