"""fsio carries the project's central resumability promise: a kill or
crash mid-write must never leave a torn file. These pin that promise
directly — six modules depend on it."""

from __future__ import annotations

import os
import stat

import pytest

from bggpipe.fsio import atomic_write_bytes, atomic_write_csv, atomic_write_text


def test_failed_write_leaves_original_intact(tmp_path, monkeypatch):
    target = tmp_path / "artifact.json"
    target.write_text("precious")
    # a read-only directory makes the tmp-file write fail
    os.chmod(tmp_path, stat.S_IRUSR | stat.S_IXUSR)
    try:
        with pytest.raises(OSError):
            atomic_write_text(target, "replacement")
    finally:
        os.chmod(tmp_path, 0o755)
    assert target.read_text() == "precious"
    assert not list(tmp_path.glob("*.tmp"))  # no leftovers


def test_returned_mtime_matches_the_written_file(tmp_path):
    target = tmp_path / "rows.csv"
    mtime = atomic_write_csv(target, ["a", "b"], [{"a": "1", "b": "2"}])
    # ReviewSession records this as "my own write" — it must be the mtime
    # the file actually carries, or external-change detection breaks
    assert mtime == target.stat().st_mtime_ns


def test_bytes_variant_round_trips(tmp_path):
    target = tmp_path / "photo.jpg"
    atomic_write_bytes(target, b"\xff\xd8jpeg")
    assert target.read_bytes() == b"\xff\xd8jpeg"
    atomic_write_bytes(target, b"\xff\xd8jpeg2")  # overwrite is atomic too
    assert target.read_bytes() == b"\xff\xd8jpeg2"


def test_concurrent_writers_use_distinct_tmp_names(tmp_path):
    from bggpipe.fsio import _tmp_for

    target = tmp_path / "x.csv"
    assert _tmp_for(target) != _tmp_for(target)  # no shared-inode interleave
