"""동시 worker claim 회귀 — 한 쪽만 성공 (Block C C3, AC-C5).

minimum gate (사용자 지시): 1 test. plan v2.1.3 §3556~3636 기반.
production PG 또는 local theroad_test 에 의존.
"""
import threading
import uuid

import pytest
from sqlalchemy import text

from app.core.database import SessionLocal
from app.core.step_runner import StepRunner


@pytest.fixture
def step_run_seed():
    """test step_run row 미리 정리 + 사후 cleanup."""
    pid = "test-concurrent-pid-" + str(uuid.uuid4())[:8]
    eid = "test-concurrent-eid-" + str(uuid.uuid4())[:8]
    sid = "concurrent_test_step"

    with SessionLocal() as db:
        db.execute(text(
            "DELETE FROM step_run WHERE project_id=:pid AND episode_id=:eid AND step_id=:sid"
        ), {"pid": pid, "eid": eid, "sid": sid})
        db.commit()

    yield pid, eid, sid

    with SessionLocal() as db:
        db.execute(text(
            "DELETE FROM step_run WHERE project_id=:pid AND episode_id=:eid AND step_id=:sid"
        ), {"pid": pid, "eid": eid, "sid": sid})
        db.commit()


def _now_iso():
    """fake _now — runner mock 용."""
    from datetime import datetime, timezone
    return datetime.now(timezone.utc).isoformat()


def _build_runner(db, pid, eid, sid, run_id):
    runner = StepRunner.__new__(StepRunner)
    runner.step_id = sid
    runner.project_id = pid
    runner.episode_id = eid
    runner.run_id = run_id
    runner.db = db
    runner._now = _now_iso
    return runner


def test_concurrent_claim_only_one_succeeds(step_run_seed):
    """두 thread 가 같은 step 에 claim 시도 → 한 쪽만 성공."""
    pid, eid, sid = step_run_seed
    results = []
    barrier = threading.Barrier(2)

    def worker(run_id):
        with SessionLocal() as db:
            runner = _build_runner(db, pid, eid, sid, run_id)
            barrier.wait()  # 동시 진입 보장
            ok = runner._try_claim_running()
            results.append((run_id, ok))

    t1 = threading.Thread(target=worker, args=("worker-1",))
    t2 = threading.Thread(target=worker, args=("worker-2",))
    t1.start()
    t2.start()
    t1.join()
    t2.join()

    successes = [r for r in results if r[1] is True]
    failures = [r for r in results if r[1] is False]
    assert len(successes) == 1, f"동시 claim 한 쪽만 성공해야 함: {results}"
    assert len(failures) == 1, f"failure 측 1 건 기대: {results}"
