"""Проверка защиты общего git-индекса от чужих staged-файлов (R04, R05).

Рычаги порчи:
1. Отключить проверку staged_files_outside_zone в close_task — покраснеет `test_alien_file_in_staged_index_blocks_task_done`.
2. Не пропускать файлы из разрешённых подкаталогов зоны — покраснеет `test_clean_index_allows_task_done`.
"""

from __future__ import annotations

import subprocess
import sys
from pathlib import Path

import pytest

ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))

from chekan import proof  # noqa: E402
from chekan.store import Run  # noqa: E402


@pytest.fixture
def repo(tmp_path: Path) -> Path:
    subprocess.run(["git", "init", "-q"], cwd=tmp_path, check=True)
    subprocess.run(["git", "config", "user.email", "t@t"], cwd=tmp_path, check=True)
    subprocess.run(["git", "config", "user.name", "t"], cwd=tmp_path, check=True)
    (tmp_path / "app.py").write_text("print('app')\n", encoding="utf-8")
    (tmp_path / "other.py").write_text("print('other')\n", encoding="utf-8")
    (tmp_path / "src").mkdir()
    (tmp_path / "src" / "worker.py").write_text("print('worker')\n", encoding="utf-8")
    subprocess.run(["git", "add", "-A"], cwd=tmp_path, check=True)
    subprocess.run(["git", "commit", "-qm", "init"], cwd=tmp_path, check=True)

    r = Run.create(tmp_path, "Тестовый прогон", "normal", "T2")
    r.add_requirement("R04", "цитата", "причина")
    r.add_task("01", "Правка app", ["R04"], zone="app.py,src/", verify="true")
    r.set_task_status("01", "in-progress")
    return tmp_path


def test_clean_index_allows_task_done(repo: Path):
    """Когда staged-индекс чист, задача успешно закрывается."""
    run = Run.load(repo)
    proof.run_command(run, "true", task="01")
    ok, msgs = proof.close_task(run, "01")
    assert ok, f"Не удалось закрыть с чистым индексом: {msgs}"
    assert "закрыт" in msgs[0]


def test_alien_file_in_staged_index_blocks_task_done(repo: Path):
    """Удаление или добавление чужого файла (git rm --cached) вне зоны блокирует закрытие."""
    run = Run.load(repo)
    proof.run_command(run, "true", task="01")

    # Подкладываем удаление чужого файла other.py в staged index
    subprocess.run(["git", "rm", "--cached", "other.py"], cwd=repo, check=True)

    ok, msgs = proof.close_task(run, "01")
    assert not ok, "Задача закрылась при чужом файле в индексе!"
    assert any("общий индекс git содержит чужие файлы вне зоны задачи" in m for m in msgs)
    assert any("other.py" in m for m in msgs)
    assert any("git restore --staged" in m for m in msgs)

    # Очищаем индекс — задача должна закрыться
    subprocess.run(["git", "restore", "--staged", "other.py"], cwd=repo, check=True)
    # Повторяем доказательство на чистом дереве
    proof.run_command(run, "true", task="01")
    ok_after, msgs_after = proof.close_task(run, "01")
    assert ok_after, f"Не удалось закрыть после restore: {msgs_after}"


def test_staged_file_inside_zone_is_allowed(repo: Path):
    """Файлы внутри зоны задачи (например, src/worker.py) в staged-индексе не блокируют закрытие."""
    (repo / "src" / "worker.py").write_text("print('worker modified')\n", encoding="utf-8")
    subprocess.run(["git", "add", "src/worker.py"], cwd=repo, check=True)
    subprocess.run(["git", "commit", "-qm", "worker update"], cwd=repo, check=True)

    run = Run.load(repo)
    proof.run_command(run, "true", task="01")

    # Staged правка файла в зоне
    (repo / "app.py").write_text("print('app modified')\n", encoding="utf-8")
    subprocess.run(["git", "add", "app.py"], cwd=repo, check=True)

    alien = proof.staged_files_outside_zone(run.root, run.task("01")["zone"])
    assert alien == []


def test_chekan_files_do_not_block_task_done(repo: Path):
    """Файлы состояния .chekan/ в staged-индексе не считаются чужими."""
    (repo / ".chekan" / "test.tmp").write_text("tmp", encoding="utf-8")
    subprocess.run(["git", "add", "-f", ".chekan/test.tmp"], cwd=repo, check=True)

    run = Run.load(repo)
    alien = proof.staged_files_outside_zone(run.root, run.task("01")["zone"])
    assert alien == []
