"""Files that affect clang-tidy results, and a content hash over them.

``CLANG_TIDY_GLOBAL_FILES`` (plus ``SDKCONFIG_DEFAULTS_PREFIX``) is the single
source of truth for which files influence clang-tidy output. A change to any of
them can surface warnings in source files a PR didn't touch, so:

* ``script/determine-jobs.py`` runs a full clang-tidy scan when one changes, and
* ``calculate_clang_tidy_hash()`` folds them into the idedata cache key used by
  ``script/helpers.py`` (a content hash, unlike an mtime check, stays correct
  across git checkouts).
"""

from __future__ import annotations

import hashlib
from pathlib import Path

# Root-relative paths whose contents affect clang-tidy results.
CLANG_TIDY_GLOBAL_FILES = (
    ".clang-tidy",
    "platformio.ini",
    "requirements_dev.txt",
    "esphome/idf_component.yml",
)

# sdkconfig.defaults and per-target sdkconfig.defaults.<target> files flip the
# CONFIG flags that decide which variant code paths clang-tidy sees. Matched by
# this prefix at the repo root.
SDKCONFIG_DEFAULTS_PREFIX = "sdkconfig.defaults"


def read_file_bytes(path: Path) -> bytes:
    """Read bytes from a file."""
    with path.open("rb") as f:
        return f.read()


def get_repo_root() -> Path:
    """Get the repository root directory."""
    return Path(__file__).parent.parent


def _ensure_repo_root(repo_root: Path | None) -> Path:
    """Ensure repo_root is a Path, using default if None."""
    return repo_root if repo_root is not None else get_repo_root()


def calculate_clang_tidy_hash(repo_root: Path | None = None) -> str:
    """Calculate a hash of the files that affect clang-tidy results."""
    repo_root = _ensure_repo_root(repo_root)

    hasher = hashlib.sha256()

    for name in CLANG_TIDY_GLOBAL_FILES:
        path = repo_root / name
        if path.exists():
            hasher.update(read_file_bytes(path))

    # Hash each sdkconfig.defaults* file. Include the filename so adding or
    # renaming a per-target variant is detected, not just content edits.
    for path in sorted(repo_root.glob(f"{SDKCONFIG_DEFAULTS_PREFIX}*")):
        hasher.update(path.name.encode())
        hasher.update(read_file_bytes(path))

    return hasher.hexdigest()
