"""Filesystem mutations for maintenance boundary tests."""

from __future__ import annotations

import os
from pathlib import Path

import pytest

from tests.gateway.nutrition_weekly_maintenance_support import MaintenanceFixture


def rewrite(path: Path, content: bytes, mode: int) -> None:
    if os.path.lexists(path):
        path.unlink()
    _ = path.write_bytes(content)
    _ = path.chmod(mode)


def noncanonical(raw: bytes) -> bytes:
    return b"{ " + raw[1:]


def extra(raw: bytes) -> bytes:
    return raw[:-2] + b',"unexpected":true}\n'


def symlink(path: Path, target: Path) -> None:
    path.unlink()
    path.symlink_to(target)


def hardlink(path: Path) -> None:
    os.link(path, path.with_name(f"{path.name}.linked"))


def fifo(path: Path) -> None:
    path.unlink()
    os.mkfifo(path, 0o600)


def replace_directory_with_symlink(fixture: MaintenanceFixture) -> None:
    for child in fixture.maintenance.iterdir():
        child.unlink()
    fixture.maintenance.rmdir()
    fixture.maintenance.symlink_to(fixture.credentials, target_is_directory=True)


def fake_identity(
    monkeypatch: pytest.MonkeyPatch, target: Path, *, change_uid: bool,
) -> None:
    original = os.fstat
    target_inode = target.stat().st_ino

    def altered(descriptor: int) -> os.stat_result:
        current = original(descriptor)
        if current.st_ino != target_inode:
            return current
        values = list(current)
        index = 4 if change_uid else 5
        values[index] = values[index] + 1
        return os.stat_result(values)

    monkeypatch.setattr(os, "fstat", altered)


def artifact_snapshot(path: Path) -> tuple[tuple[str, int, int, int, int], ...]:
    if path.is_symlink() or not path.is_dir():
        info = path.lstat()
        return ((path.name, info.st_mode, info.st_nlink, info.st_size, info.st_mtime_ns),)
    rows: list[tuple[str, int, int, int, int]] = []
    for child in sorted(path.iterdir(), key=lambda item: item.name):
        info = child.lstat()
        rows.append((child.name, info.st_mode, info.st_nlink, info.st_size, info.st_mtime_ns))
    return tuple(rows)
