"""SCM Collector — reads local git repository metadata."""

from __future__ import annotations

from typing import Any

from sentinel.collectors.base import BaseCollector


class ScmCollector(BaseCollector):
    module_name = "scm"

    def collect(self) -> dict[str, Any]:
        result: dict[str, Any] = {
            "is_git_repo": False,
            "commit_signing": [],
            "hygiene_files": {},
            "tracked_sensitive_files": [],
            "gitignore_patterns": [],
            "large_blobs": [],
            "errors": [],
        }

        git_dir = self.repo_path / ".git"
        if not git_dir.exists():
            result["errors"].append("Not a git repository (.git not found)")
            return result

        result["is_git_repo"] = True

        try:
            import git
            repo = git.Repo(self.repo_path)
        except Exception as exc:
            result["errors"].append(f"Failed to open git repo: {exc}")
            return result

        # Hygiene files
        result["hygiene_files"] = self._check_hygiene_files()

        # Gitignore patterns
        gi = self.repo_path / ".gitignore"
        if gi.exists():
            result["gitignore_patterns"] = [
                ln.strip() for ln in gi.read_text().splitlines()
                if ln.strip() and not ln.strip().startswith("#")
            ]

        # Tracked sensitive files
        try:
            tracked = {item.a_path for item in repo.index.diff(None)}
            tracked |= {item for item in repo.untracked_files}
            # Walk git index (all tracked files)
            for entry in repo.index.entries.values():
                path_str = entry[0] if isinstance(entry, tuple) else str(entry)
                if self._is_sensitive_path(str(path_str)):
                    result["tracked_sensitive_files"].append(str(path_str))
        except Exception as exc:
            result["errors"].append(f"Index scan error: {exc}")

        # Commit signing — check last 100 commits
        try:
            commits_data = []
            for commit in list(repo.iter_commits(max_count=100)):
                gpgsig = commit.gpgsig if hasattr(commit, "gpgsig") else None
                commits_data.append({
                    "sha": commit.hexsha[:8],
                    "author": str(commit.author),
                    "message": commit.message.strip()[:80],
                    "signed": bool(gpgsig),
                    "timestamp": commit.committed_date,
                })
            result["commit_signing"] = commits_data
        except Exception as exc:
            result["errors"].append(f"Commit history error: {exc}")

        # Large blobs in history
        try:
            large: list[dict[str, Any]] = []
            for commit in list(repo.iter_commits(max_count=50)):
                for blob in commit.tree.traverse():
                    if hasattr(blob, "size") and blob.size > 1 * 1024 * 1024:  # type: ignore[union-attr]
                        large.append({
                            "path": blob.path,  # type: ignore[union-attr]
                            "size_mb": round(blob.size / 1024 / 1024, 2),  # type: ignore[union-attr]
                            "commit": commit.hexsha[:8],
                        })
            result["large_blobs"] = large[:20]  # cap at 20
        except Exception as exc:
            result["errors"].append(f"Blob scan error: {exc}")

        return result

    def _check_hygiene_files(self) -> dict[str, bool]:
        checks = {
            "CODEOWNERS": any(
                (self.repo_path / p).exists()
                for p in ["CODEOWNERS", ".gitlab/CODEOWNERS", "docs/CODEOWNERS"]
            ),
            "README": any(
                (self.repo_path / p).exists()
                for p in ["README.md", "README.rst", "README.txt", "README"]
            ),
            "LICENSE": any(
                (self.repo_path / p).exists()
                for p in ["LICENSE", "LICENSE.md", "LICENSE.txt", "LICENCE"]
            ),
            ".gitignore": (self.repo_path / ".gitignore").exists(),
        }
        return checks

    @staticmethod
    def _is_sensitive_path(path: str) -> bool:
        import re
        sensitive_patterns = [
            r"\.env$",
            r"\.env\.",
            r"\.pem$",
            r"\.key$",
            r"\.p12$",
            r"\.pfx$",
            r"\.jks$",
            r"\.keystore$",
            r"id_rsa$",
            r"id_ecdsa$",
            r"id_ed25519$",
            r"\.kdbx$",
            r"secrets\.ya?ml$",
            r"credentials\.json$",
        ]
        return any(re.search(pat, path, re.IGNORECASE) for pat in sensitive_patterns)
