"""Shared flock + atomic JSON persistence for small okstra registries."""
from __future__ import annotations

import contextlib
import fcntl
from collections.abc import Callable, Iterator
from pathlib import Path

from .json_boundary import (
    JsonBoundaryError,
    load_owned_object,
    write_owned_object_atomic,
)


@contextlib.contextmanager
def registry_lock(lock_path: Path) -> Iterator[None]:
    """Hold an exclusive flock on ``lock_path``."""
    lock_path.parent.mkdir(parents=True, exist_ok=True)
    if not lock_path.exists():
        lock_path.touch()
    handle = lock_path.open("r+")
    try:
        fcntl.flock(handle.fileno(), fcntl.LOCK_EX)
        yield
    finally:
        fcntl.flock(handle.fileno(), fcntl.LOCK_UN)
        handle.close()


def load_registry_json(path: Path, default_factory: Callable[[], dict]) -> dict:
    """Load a registry dict, or a fresh default when absent/corrupt."""
    try:
        return load_owned_object(path, artifact="registry")
    except JsonBoundaryError:
        return default_factory()


def save_registry_json(path: Path, data: dict) -> None:
    """Persist registry JSON through the owned-artifact boundary."""
    write_owned_object_atomic(path, data, artifact="registry")
