"""Integration: many concurrent ``run()`` calls in threads.

Pins the contract that ``run()`` is safe to call from multiple
threads simultaneously. Without proper isolation, you'd see:

  - Crossed stdout/stderr capture between processes (one
    process's output landing in another's ProcessResult).
  - Crossed log records (extra={"command_id": ...} pointing at
    the wrong process).
  - Race on the shared streamer-thread name space (daemon
    threads named ``mgf-process-stream-stdout-<pid>`` collide
    if pids reuse — unlikely, but the name shouldn't matter).

The test launches N parallel ``run()`` invocations; each child
prints ITS OWN ``command_id`` echo (passed via env_extra) so
we can verify each result's stdout matches its own id.
"""

from __future__ import annotations

import logging
import sys
import threading

import pytest

pytestmark = pytest.mark.integration


_NUM_CONCURRENT = 16


def test_n_concurrent_runs_preserve_per_call_isolation() -> None:
    """Each thread's run() returns ITS own captured stdout."""
    from mgf.common.process import run

    barrier = threading.Barrier(_NUM_CONCURRENT)
    results: dict[int, object] = {}
    errors: list[Exception] = []
    lock = threading.Lock()

    def _runner(idx: int) -> None:
        try:
            barrier.wait()  # synchronize start
            r = run(
                [sys.executable, "-c", f"print({idx!r})"],
                timeout=10.0,
            )
            with lock:
                results[idx] = r
        except Exception as exc:
            with lock:
                errors.append(exc)

    threads = [threading.Thread(target=_runner, args=(i,)) for i in range(_NUM_CONCURRENT)]
    for t in threads:
        t.start()
    for t in threads:
        t.join(timeout=15.0)

    assert not errors, f"Concurrent runs raised: {errors}"
    assert len(results) == _NUM_CONCURRENT

    # Each result's captured stdout MUST match its own index —
    # no crossed output between processes.
    for idx, r in results.items():
        assert r.stdout == str(idx), (
            f"Crossed output: result idx={idx} captured stdout={r.stdout!r}"
        )
        assert r.returncode == 0


def test_n_concurrent_runs_have_distinct_command_ids() -> None:
    """N parallel run()s produce N distinct command_ids."""
    from mgf.common.process import run

    barrier = threading.Barrier(_NUM_CONCURRENT)
    cmd_ids: list[str] = []
    lock = threading.Lock()

    def _runner() -> None:
        barrier.wait()
        r = run([sys.executable, "-c", "print('x')"])
        with lock:
            cmd_ids.append(r.command_id)

    threads = [threading.Thread(target=_runner) for _ in range(_NUM_CONCURRENT)]
    for t in threads:
        t.start()
    for t in threads:
        t.join(timeout=15.0)

    # All eight hex chars; 16 IDs should all be distinct.
    assert len(set(cmd_ids)) == _NUM_CONCURRENT, f"Duplicate command_ids: {cmd_ids}"
    for cid in cmd_ids:
        assert len(cid) == 8


def test_concurrent_runs_dont_cross_log_records(
    caplog: pytest.LogCaptureFixture,
) -> None:
    """Each process's stdout line lands on a record carrying ITS
    OWN command_id — not someone else's."""
    from mgf.common.process import run

    barrier = threading.Barrier(_NUM_CONCURRENT)
    results: dict[int, object] = {}
    lock = threading.Lock()

    def _runner(idx: int) -> None:
        barrier.wait()
        r = run([sys.executable, "-c", f"print('payload-{idx}')"])
        with lock:
            results[idx] = r

    with caplog.at_level(logging.INFO, logger="mgf.process"):
        threads = [threading.Thread(target=_runner, args=(i,)) for i in range(_NUM_CONCURRENT)]
        for t in threads:
            t.start()
        for t in threads:
            t.join(timeout=15.0)

    assert len(results) == _NUM_CONCURRENT
    # For each result, find the record that has its command_id +
    # verify the message matches the expected payload.
    for idx, r in results.items():
        records_for_id = [
            rec for rec in caplog.records if getattr(rec, "command_id", None) == r.command_id
        ]
        # Should be exactly one (the print line).
        assert len(records_for_id) == 1, (
            f"Expected 1 record for command_id={r.command_id} "
            f"(idx={idx}); got {len(records_for_id)}"
        )
        assert records_for_id[0].message == f"payload-{idx}"
