"""PostToolUse hook for Edit|Write: format and lint the file Claude just changed.

Python goes through ruff. SQL goes through sqlfluff, only when the project has a
.sqlfluff file, because sqlfluff needs to know the SQL dialect. Fixable problems are
fixed quietly. Anything left over is printed to stderr with exit code 2, which shows
it to Claude; the edit itself has already happened and stays.
"""

import json
import os
import subprocess
import sys
from pathlib import Path

MAX_LINES = 40

# Suffix -> (commands that fix, in order; a command that exits non-zero if problems are left).
TOOLS = {
    ".py": (
        [["ruff", "check", "--fix", "--quiet"], ["ruff", "format", "--quiet"]],
        ["ruff", "check", "--quiet"],
    ),
    ".sql": ([["sqlfluff", "fix", "--quiet"]], ["sqlfluff", "lint", "--quiet"]),
}


def tools_for(path: Path, project: Path) -> tuple[list[list[str]], list[str]] | None:
    if path.suffix == ".sql" and not (project / ".sqlfluff").exists():
        return None
    return TOOLS.get(path.suffix)


def run(command: list[str], path: Path, project: Path) -> subprocess.CompletedProcess[str]:
    return subprocess.run(
        ["uv", "run", *command, str(path)], cwd=project, capture_output=True, text=True
    )


def main() -> int:
    event = json.load(sys.stdin)
    path = Path(event.get("tool_input", {}).get("file_path", ""))
    project = Path(os.environ.get("CLAUDE_PROJECT_DIR", event.get("cwd", ".")))
    tools = tools_for(path, project)
    if tools is None or not path.is_file():
        return 0
    fixers, check = tools
    for fixer in fixers:
        run(fixer, path, project)
    result = run(check, path, project)
    if result.returncode == 0:
        return 0
    output = (result.stdout + result.stderr).strip().splitlines()[-MAX_LINES:]
    print(f"Lint problems left in {path.name} after auto-fix:", *output, sep="\n", file=sys.stderr)
    return 2


if __name__ == "__main__":
    sys.exit(main())
