# Copyright (C) 2026 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Unittests for the git_refs.py module."""

import os
from pathlib import Path
import subprocess
from typing import Any, List
from unittest import mock

import pytest
import utils_for_test

import git_refs


def _run(repo: str, *args: str) -> str:
    return subprocess.run(
        ["git", "-C", repo, *args],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        encoding="utf-8",
        check=True,
    ).stdout.strip()


def _init_repo(tmp_path: Path, reftable: bool = False) -> str:
    repo = os.path.join(tmp_path, "repo")
    ref_format = "reftable" if reftable else "files"
    utils_for_test.init_git_tree(repo, ref_format=ref_format)

    Path(os.path.join(repo, "a")).write_text("1")
    _run(repo, "add", "a")
    _run(repo, "commit", "-q", "-m", "init")
    return repo


@pytest.mark.parametrize("reftable", [False, True])
def test_reads_refs(tmp_path, reftable):
    if reftable and not utils_for_test.supports_reftable():
        pytest.skip("reftable not supported")

    repo = _init_repo(tmp_path, reftable=reftable)
    gitdir = os.path.join(repo, ".git")
    refs = git_refs.GitRefs(gitdir)

    branch = _run(repo, "symbolic-ref", "--short", "HEAD")
    head = _run(repo, "rev-parse", "HEAD")
    assert refs.symref("HEAD") == f"refs/heads/{branch}"
    assert refs.head == f"refs/heads/{branch}"
    assert refs.get("HEAD") == head
    assert refs.get(f"refs/heads/{branch}") == head


@pytest.mark.parametrize("reftable", [False, True])
def test_reads_detached_head(tmp_path: Path, reftable: bool) -> None:
    if reftable and not utils_for_test.supports_reftable():
        pytest.skip("reftable not supported")

    repo = _init_repo(tmp_path, reftable=reftable)
    head = _run(repo, "rev-parse", "HEAD")
    _run(repo, "checkout", "--detach", head)
    refs = git_refs.GitRefs(os.path.join(repo, ".git"))

    assert refs.symref("HEAD") == ""
    assert refs.head == head
    assert refs.get("HEAD") == head


def test_reads_head_with_root_refs_in_one_command(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Git 2.45 and newer include HEAD in the ref snapshot."""
    head = "1" * 40
    commands = []

    class FakeGitCommand:
        def __init__(
            self, _project: Any, cmdv: List[str], **_kwargs: Any
        ) -> None:
            commands.append(cmdv)
            self.stdout = (
                f"{head}\0HEAD\0refs/heads/main\n"
                f"{head}\0refs/heads/main\0\n"
            )

        def Wait(self) -> int:
            return 0

    monkeypatch.setattr(git_refs, "GitCommand", FakeGitCommand)
    monkeypatch.setattr(git_refs, "git_require", lambda _version: True)
    refs = git_refs.GitRefs("/nonexistent")
    with mock.patch.object(refs, "_ReadSymbolicRef") as read_head:
        assert refs.get("HEAD") == head

    assert commands == [
        [
            "for-each-ref",
            "--include-root-refs",
            "--format=%(objectname)%00%(refname)%00%(symref)",
            "HEAD",
            "refs",
        ]
    ]
    read_head.assert_not_called()


def test_root_ref_snapshot_falls_back_for_unborn_head(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """An unborn HEAD still uses symbolic-ref after the ref snapshot."""

    class FakeGitCommand:
        def __init__(
            self, _project: Any, _cmdv: List[str], **_kwargs: Any
        ) -> None:
            self.stdout = ""

        def Wait(self) -> int:
            return 0

    monkeypatch.setattr(git_refs, "GitCommand", FakeGitCommand)
    monkeypatch.setattr(git_refs, "git_require", lambda _version: True)
    refs = git_refs.GitRefs("/nonexistent")

    def read_head(name: str) -> None:
        assert name == "HEAD"
        refs._symref[name] = "refs/heads/main"

    monkeypatch.setattr(refs, "_ReadSymbolicRef", read_head)

    assert refs.symref("HEAD") == "refs/heads/main"


def test_old_git_keeps_separate_head_fallback(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Git before 2.45 uses the original for-each-ref and HEAD calls."""
    head = "1" * 40
    commands = []

    class FakeGitCommand:
        def __init__(
            self, _project: Any, cmdv: List[str], **_kwargs: Any
        ) -> None:
            commands.append(cmdv)
            self.stdout = f"{head}\0refs/heads/main\0\n"

        def Wait(self) -> int:
            return 0

    monkeypatch.setattr(git_refs, "GitCommand", FakeGitCommand)
    monkeypatch.setattr(git_refs, "git_require", lambda _version: False)
    refs = git_refs.GitRefs("/nonexistent")

    def read_head(name: str) -> None:
        assert name == "HEAD"
        refs._symref[name] = "refs/heads/main"

    monkeypatch.setattr(refs, "_ReadSymbolicRef", read_head)

    assert refs.get("HEAD") == head
    assert commands == [
        [
            "for-each-ref",
            "--format=%(objectname)%00%(refname)%00%(symref)",
        ]
    ]


def test_for_each_ref_failure_falls_back_to_symbolic_ref(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """When for-each-ref fails, HEAD is still resolved via symbolic-ref."""

    class FakeGitCommand:
        def __init__(
            self, _project: Any, _cmdv: List[str], **_kwargs: Any
        ) -> None:
            self.stdout = ""

        def Wait(self) -> int:
            return 1

    monkeypatch.setattr(git_refs, "GitCommand", FakeGitCommand)
    monkeypatch.setattr(git_refs, "git_require", lambda _version: True)
    refs = git_refs.GitRefs("/nonexistent")

    def read_head(name: str) -> None:
        assert name == "HEAD"
        refs._symref[name] = "refs/heads/main"

    monkeypatch.setattr(refs, "_ReadSymbolicRef", read_head)

    assert refs.symref("HEAD") == "refs/heads/main"


@pytest.mark.parametrize("reftable", [False, True])
def test_updates_when_refs_change(tmp_path, reftable):
    if reftable and not utils_for_test.supports_reftable():
        pytest.skip("reftable not supported")

    repo = _init_repo(tmp_path, reftable=reftable)
    gitdir = os.path.join(repo, ".git")
    refs = git_refs.GitRefs(gitdir)

    head = _run(repo, "rev-parse", "HEAD")
    assert refs.get("refs/heads/topic") == ""
    _run(repo, "branch", "topic")
    assert refs.get("refs/heads/topic") == head
    _run(repo, "branch", "-D", "topic")
    assert refs.get("refs/heads/topic") == ""


@pytest.mark.skipif(
    not utils_for_test.supports_refs_migrate(),
    reason="git refs migrate reftable support is required for this test",
)
def test_updates_when_storage_backend_toggles(tmp_path):
    repo = _init_repo(tmp_path, reftable=False)
    gitdir = os.path.join(repo, ".git")
    refs = git_refs.GitRefs(gitdir)

    head = _run(repo, "rev-parse", "HEAD")
    assert refs.get("refs/heads/reftable-branch") == ""
    _run(repo, "refs", "migrate", "--ref-format=reftable")
    _run(repo, "branch", "reftable-branch")
    assert refs.get("refs/heads/reftable-branch") == head

    assert refs.get("refs/heads/files-branch") == ""
    _run(repo, "refs", "migrate", "--ref-format=files")
    _run(repo, "branch", "files-branch")
    assert refs.get("refs/heads/files-branch") == head
