#!/bin/bash
# Pre-commit hook to run ruff and type checks

set -e

echo "Running pre-commit checks..."

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Check if we're in the right directory
if [ ! -f "pyproject.toml" ]; then
    echo -e "${RED}Error: pyproject.toml not found. Are you in the repository root?${NC}"
    exit 1
fi

# Block commits that accidentally include bearer tokens or other secrets.
echo -e "${YELLOW}Scanning staged changes for secrets...${NC}"
python3 - <<'PY'
from __future__ import annotations

import re
import subprocess
import sys


def git_show_index(path: str) -> str | None:
    try:
        return subprocess.check_output(["git", "show", f":{path}"], text=True, stderr=subprocess.DEVNULL)
    except Exception:
        return None


def git_staged_paths() -> list[str]:
    out = subprocess.check_output(
        ["git", "diff", "--cached", "--name-only", "--diff-filter=ACM"],
        text=True,
        stderr=subprocess.DEVNULL,
    )
    return [p for p in out.splitlines() if p.strip()]


def is_placeholder(value: str) -> bool:
    value = value.strip()
    if not value:
        return True
    if value.startswith("${") and value.endswith("}"):
        return True
    lowered = value.lower()
    if lowered.startswith("<") or lowered.startswith("your") or lowered.startswith("example"):
        return True
    return False


def looks_like_secret_token(value: str) -> bool:
    value = value.strip().strip('"').strip("'")
    if is_placeholder(value):
        return False
    # Shell-style non-literals (command substitution / variable expansion) are not secrets by themselves.
    if "$(" in value or "`" in value or value.startswith("$"):
        return False
    if value == "mcp-agent-mail-default-token":
        return False
    # Heuristic: long-ish token-like strings (hex, base64-ish, etc.)
    if len(value) >= 20:
        return True
    return False


RULES: list[tuple[str, re.Pattern[str]]] = [
    ("HTTP_BEARER_TOKEN assignment", re.compile(r"(?m)^\s*HTTP_BEARER_TOKEN\s*=\s*(?P<val>[^#\n\r]+)")),
    (
        "Authorization Bearer header (JSON-like)",
        re.compile(r'(?i)Authorization"\s*:\s*"Bearer\s+(?P<val>[^"]+)"'),
    ),
    (
        "Authorization: Bearer header (text)",
        re.compile(r"(?i)\bAuthorization\s*:\s*Bearer\s+(?P<val>\S+)"),
    ),
]

violations: list[tuple[str, str]] = []
for path in git_staged_paths():
    blob = git_show_index(path)
    if blob is None:
        continue

    for rule_name, pattern in RULES:
        for match in pattern.finditer(blob):
            raw_val = match.group("val").strip()
            if rule_name.startswith("Authorization"):
                # Allow common safe placeholders
                if raw_val.startswith("${") or raw_val.startswith("<"):
                    continue
                if "HTTP_BEARER_TOKEN" in raw_val:
                    continue
                if looks_like_secret_token(raw_val):
                    violations.append((path, rule_name))
                    break
            else:
                if looks_like_secret_token(raw_val):
                    violations.append((path, rule_name))
                    break

if violations:
    print(
        "\nERROR: Potential secret(s) detected in staged changes. Refusing to commit.\n"
        "Fix by using env placeholders (e.g., ${HTTP_BEARER_TOKEN}) or moving tokens into\n"
        "untracked local config files (e.g., .claude/settings.local.json).\n",
        file=sys.stderr,
    )
    for path, rule in violations:
        print(f"  - {path}: {rule}", file=sys.stderr)
    sys.exit(1)

print("✓ No obvious secrets detected in staged changes")
PY

# Ensure dependencies are synced (quick check, uv sync is smart about caching)
echo -e "${YELLOW}Ensuring dependencies are synced...${NC}"
uv sync --dev --quiet 2>/dev/null || true

# Run ruff with auto-fix
echo -e "${YELLOW}Running ruff check --fix --unsafe-fixes...${NC}"
if uvx ruff check --fix --unsafe-fixes; then
    echo -e "${GREEN}✓ Ruff checks passed${NC}"
else
    echo -e "${RED}✗ Ruff checks failed${NC}"
    exit 1
fi

# If ruff made any fixes, add them to the commit
if ! git diff --quiet; then
    echo -e "${YELLOW}Ruff made automatic fixes. Adding them to the commit...${NC}"
    git add -u
fi

# Run type checks with ty
echo -e "${YELLOW}Running ty check...${NC}"
if uvx ty check 2>&1 | grep -v "error\|warning" > /dev/null; then
    echo -e "${GREEN}✓ Type checks completed (warnings ignored)${NC}"
else
    echo -e "${YELLOW}Type checks completed with warnings (not blocking commit)${NC}"
fi

# Run security checks with Bandit
echo -e "${YELLOW}Running Bandit security scan...${NC}"
if uv run bandit -r src/ -ll -q 2>/dev/null; then
    echo -e "${GREEN}✓ Security scan passed${NC}"
else
    echo -e "${YELLOW}⚠ Security issues found (not blocking commit)${NC}"
    echo -e "${YELLOW}Run 'uv run bandit -r src/' for details${NC}"
fi

# Run dependency vulnerability check with Safety
echo -e "${YELLOW}Checking dependencies for vulnerabilities...${NC}"
if uv run safety check --json 2>/dev/null | grep -q '"vulnerabilities": \[\]'; then
    echo -e "${GREEN}✓ No known vulnerabilities in dependencies${NC}"
elif uv run safety check --json 2>/dev/null | grep -q '"vulnerabilities"'; then
    echo -e "${YELLOW}⚠ Vulnerabilities found in dependencies (not blocking commit)${NC}"
    echo -e "${YELLOW}Run 'uv run safety check' for details${NC}"
else
    echo -e "${YELLOW}⚠ Could not check dependencies (not blocking commit)${NC}"
fi

echo -e "${GREEN}All pre-commit checks complete!${NC}"
exit 0
