"""Замок на зону: вторая задача не заходит в файлы, которые уже кто-то правит.

Дефект с натуры: в прошлом прогоне два исполнителя взяли задачи с пересекающимися
зонами, правили одни файлы одновременно, и сводить пришлось руками. Гейт G3 ловит это
в плане, но взять занятую зону в работу не мешал ничто.
"""

from __future__ import annotations

import subprocess
import sys
from pathlib import Path

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

from test_core import repo, run  # noqa: E402,F401 — общие фикстуры

from chekan.store import Run  # noqa: E402

ROOT = Path(__file__).resolve().parent.parent


def ceh(root: Path, *args: str) -> subprocess.CompletedProcess:
    return subprocess.run(
        [sys.executable, "-m", "chekan", *args],
        cwd=root, capture_output=True, text=True,
        env={"PYTHONPATH": str(ROOT), "PATH": "/usr/bin:/bin", "HOME": str(root)},
    )


def status(run: Run, tid: str) -> str:
    """Состояние читается с диска: у CLI был свой процесс, объект в тесте о нём не знает."""
    return Run(run.root, run.slug).task(tid)["status"]


def two_tasks(run: Run, zone_a: str, zone_b: str) -> None:
    run.add_requirement("R01", "цитата", note="причина")
    run.add_task("01", "Первая", ["R01"], zone=zone_a, verify="true")
    run.add_task("02", "Вторая", ["R01"], zone=zone_b, verify="true")


# --- отказ ---


def test_start_refuses_when_the_zone_is_already_taken(run: Run):  # noqa: F811
    two_tasks(run, "chekan/store.py", "chekan/store.py")
    assert ceh(run.root, "task", "start", "01").returncode == 0

    proc = ceh(run.root, "task", "start", "02")
    assert proc.returncode != 0
    text = proc.stderr
    assert "01" in text and "02" in text, text
    assert "chekan/store.py" in text, text
    assert status(run, "02") == "pending"


def test_free_zone_starts_without_a_word(run: Run):  # noqa: F811
    two_tasks(run, "chekan/store.py", "assets/dashboard.html")
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "task", "start", "02").returncode == 0
    assert status(run, "02") == "in-progress"


# --- вложенность в обе стороны ---


def test_nested_zone_is_blocked_by_the_outer_one(run: Run):  # noqa: F811
    two_tasks(run, "chekan/", "chekan/store.py")
    assert ceh(run.root, "task", "start", "01").returncode == 0

    proc = ceh(run.root, "task", "start", "02")
    assert proc.returncode != 0, proc.stdout
    assert "chekan" in proc.stderr


def test_outer_zone_is_blocked_by_the_nested_one(run: Run):  # noqa: F811
    two_tasks(run, "chekan/store.py", "chekan/")
    assert ceh(run.root, "task", "start", "01").returncode == 0

    proc = ceh(run.root, "task", "start", "02")
    assert proc.returncode != 0, proc.stdout
    assert "chekan" in proc.stderr


def test_neighbour_with_a_common_prefix_is_not_a_nesting(run: Run):  # noqa: F811
    """`chekan/store.py` и `chekan/storage/` — разные файлы, а не вложенность по буквам."""
    two_tasks(run, "chekan/store.py", "chekan/store_extra.py")
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "task", "start", "02").returncode == 0


# --- зона из нескольких путей через запятую ---


def test_multi_path_zones_overlapping_on_one_file_are_blocked(run: Run):  # noqa: F811
    """Боевой случай: зоны совпадают целиком лишь частично — общий файл всего один из трёх."""
    two_tasks(
        run,
        "assets/index.html,chekan/serve_app.py,tests/test_home.py",
        "assets/index.html,chekan/serve_app.py,tests/test_buttons_guard.py",
    )
    assert ceh(run.root, "task", "start", "01").returncode == 0

    proc = ceh(run.root, "task", "start", "02")
    assert proc.returncode != 0, proc.stdout
    text = proc.stderr
    assert "01" in text and "02" in text, text
    assert "chekan/serve_app.py" in text, text
    assert status(run, "02") == "pending"


def test_multi_path_zone_overlaps_on_only_one_of_three_paths(run: Run):  # noqa: F811
    """Только один путь из трёх пересекается — остальные два разные, замок всё равно срабатывает."""
    two_tasks(
        run,
        "chekan/store.py,assets/a.html,tests/test_a.py",
        "tests/test_a.py,assets/b.html,ceh/other.py",
    )
    assert ceh(run.root, "task", "start", "01").returncode == 0

    proc = ceh(run.root, "task", "start", "02")
    assert proc.returncode != 0, proc.stdout
    assert "tests/test_a.py" in proc.stderr, proc.stderr


def test_multi_path_zones_without_shared_paths_both_start(run: Run):  # noqa: F811
    two_tasks(
        run,
        "chekan/store.py,assets/a.html",
        "ceh/other.py,assets/b.html",
    )
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "task", "start", "02").returncode == 0
    assert status(run, "02") == "in-progress"


def test_empty_pieces_and_spaces_around_commas_lock_nothing(run: Run):  # noqa: F811
    """`", "` между запятыми и пустые куски — не пути, они никого не запирают."""
    two_tasks(
        run,
        "chekan/store.py, , assets/a.html",
        " , tests/test_a.py,",
    )
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "task", "start", "02").returncode == 0
    assert status(run, "02") == "in-progress"


# --- замок отпускает сам ---


def test_zone_frees_after_the_holder_is_closed(run: Run):  # noqa: F811
    two_tasks(run, "chekan/store.py", "chekan/store.py")
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "run", "true", "--task", "01").returncode == 0

    done = ceh(run.root, "task", "done", "01")
    assert done.returncode == 0, done.stdout + done.stderr
    assert status(run, "01") == "done"

    started = ceh(run.root, "task", "start", "02")
    assert started.returncode == 0, started.stderr
    assert status(run, "02") == "in-progress"


def test_zone_frees_after_the_holder_failed(run: Run):  # noqa: F811
    two_tasks(run, "chekan/store.py", "chekan/store.py")
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "task", "fail", "01").returncode == 0
    assert ceh(run.root, "task", "start", "02").returncode == 0


def test_zone_frees_after_the_holder_was_reset(run: Run):  # noqa: F811
    two_tasks(run, "chekan/store.py", "chekan/store.py")
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "task", "reset", "01").returncode == 0
    assert ceh(run.root, "task", "start", "02").returncode == 0


def test_holder_can_restart_itself(run: Run):  # noqa: F811
    """Своя же зона не должна запирать задачу от повторного старта."""
    two_tasks(run, "chekan/store.py", "assets/")
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "task", "start", "01", "--model", "claude-opus-5").returncode == 0


# --- пустая зона не «весь репозиторий» ---


def test_two_tasks_without_a_zone_both_start(run: Run):  # noqa: F811
    two_tasks(run, "", "")
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "task", "start", "02").returncode == 0
    assert status(run, "02") == "in-progress"


def test_task_without_a_zone_locks_nothing(run: Run):  # noqa: F811
    two_tasks(run, "", "chekan/store.py")
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "task", "start", "02").returncode == 0


def test_task_without_a_zone_is_not_locked_by_anyone(run: Run):  # noqa: F811
    two_tasks(run, "chekan/store.py", "")
    assert ceh(run.root, "task", "start", "01").returncode == 0
    assert ceh(run.root, "task", "start", "02").returncode == 0
