"""Atomic file writes for every accumulated artifact.

A kill mid-write must never leave a torn file that poisons future runs —
the same tmp + os.replace guarantee write_matches gives matches.csv,
available to JSON artifacts and the XML response cache.
"""

from __future__ import annotations

import csv
import os
from pathlib import Path


def atomic_write_text(path: Path, text: str) -> None:
    path.parent.mkdir(parents=True, exist_ok=True)
    tmp = path.with_name(path.name + ".tmp")
    tmp.write_text(text)
    os.replace(tmp, path)


def atomic_write_csv(path: Path, columns: list[str], rows: list[dict]) -> int:
    """Atomic CSV rewrite (tmp + os.replace). Returns the written file's
    mtime_ns so callers tracking their own writes avoid a re-stat race."""
    path.parent.mkdir(parents=True, exist_ok=True)
    tmp = path.with_name(path.name + ".tmp")
    with tmp.open("w", newline="") as f:
        writer = csv.DictWriter(
            f, fieldnames=columns, extrasaction="ignore", restval=""
        )
        writer.writeheader()
        writer.writerows(rows)
    os.replace(tmp, path)
    return path.stat().st_mtime_ns
