#!/usr/bin/env python3
"""
Pre-commit hook to prevent stdlib printf-style formatting in direct loguru calls.

loguru uses brace formatting (`{}`), not stdlib logging placeholders like
`%s` or `%d`. Mixing the two leaves placeholders unrendered in runtime logs.
"""

import ast
from pathlib import Path
import re
import sys


PRINTF_PLACEHOLDER_RE = re.compile(
    r"%(?:\([^)]+\))?[#0 +\-]*\d*(?:\.\d+)?[sdfr]"
)
LOGURU_METHODS = {
    "trace",
    "debug",
    "info",
    "success",
    "warning",
    "error",
    "critical",
    "exception",
    "log",
}


def check_file(file_path: str) -> list[tuple[int, str]]:
    path = Path(file_path)
    if path.suffix != ".py":
        return []

    try:
        source = path.read_text(encoding="utf-8")
    except Exception as exc:
        return [(0, f"failed to read file: {exc}")]

    try:
        tree = ast.parse(source, filename=file_path)
    except SyntaxError:
        return []

    imports_loguru_logger = any(
        isinstance(node, ast.ImportFrom)
        and node.module == "loguru"
        and any(alias.name == "logger" for alias in node.names)
        for node in tree.body
    )
    if not imports_loguru_logger:
        return []

    violations = []
    for node in ast.walk(tree):
        if not (
            isinstance(node, ast.Call)
            and isinstance(node.func, ast.Attribute)
            and isinstance(node.func.value, ast.Name)
            and node.func.value.id == "logger"
            and node.func.attr in LOGURU_METHODS
        ):
            continue

        method_name = node.func.attr
        message_index = 1 if method_name == "log" else 0
        min_args = 3 if method_name == "log" else 2
        if len(node.args) < min_args:
            continue

        message_arg = node.args[message_index]
        if not (
            isinstance(message_arg, ast.Constant)
            and isinstance(message_arg.value, str)
            and PRINTF_PLACEHOLDER_RE.search(message_arg.value)
        ):
            continue

        violations.append(
            (
                node.lineno,
                message_arg.value,
            )
        )

    return violations


def main() -> int:
    exit_code = 0

    for file_path in sys.argv[1:]:
        violations = check_file(file_path)
        for lineno, message in violations:
            print(
                f"{file_path}:{lineno}: loguru logger call uses printf-style placeholders"
            )
            print(f"  {message!r}")
            exit_code = 1

    if exit_code:
        print()
        print(
            "Hint: use loguru brace formatting, e.g. logger.info('value: {}', x)"
        )

    return exit_code


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