from __future__ import annotations

from pathlib import Path

import pytest

from gateway.platforms.nutrition_weekly_maintenance_contract import (
    Topic59MaintenanceDecisionKind,
    Topic59MaintenanceFailure,
)
from gateway.platforms.nutrition_weekly_maintenance_store import Topic59MaintenanceGate
from gateway.platforms.nutrition_weekly_operations import Topic59PublicationDisposition
from gateway.platforms.nutrition_weekly_operations_publication_contract import (
    Topic59IncidentReason,
)
from tests.gateway.nutrition_weekly_maintenance_adversarial_support import (
    MatrixCase,
    apply_case,
)
from tests.gateway.nutrition_weekly_maintenance_fs_mutations import artifact_snapshot
from tests.gateway.nutrition_weekly_maintenance_support import (
    arm_maintenance,
    change_group,
    publish_with_tripwires,
)


@pytest.fixture
def anyio_backend() -> str:
    return "asyncio"


def test_lock_wrong_gid_denies_before_state_change(
    tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
) -> None:
    # Given
    fixture = arm_maintenance(tmp_path, monkeypatch)
    lock = fixture.maintenance / "maintenance.lock"
    alternate_gid = change_group(lock)
    assert alternate_gid != fixture.profile.stat().st_gid
    before = artifact_snapshot(fixture.maintenance)

    # When
    result = Topic59MaintenanceGate.for_profile(fixture.profile).evaluate(
        fixture.projection, fixture.now,
    )

    # Then
    assert result.kind is Topic59MaintenanceDecisionKind.DENY
    assert result.reason is Topic59MaintenanceFailure.FILESYSTEM_CONTRACT
    assert artifact_snapshot(fixture.maintenance) == before
    assert not fixture.audit.exists()
    assert not fixture.ledger.exists()


@pytest.mark.anyio
@pytest.mark.parametrize(
    "case", tuple(MatrixCase), ids=[case.value for case in MatrixCase],
)
async def test_negative_matrix_denies_before_claim_transport_or_network(
    case: MatrixCase, tmp_path: Path, monkeypatch: pytest.MonkeyPatch,
) -> None:
    # Given
    fixture = arm_maintenance(tmp_path, monkeypatch)
    _ = apply_case(case, fixture, monkeypatch)
    before = artifact_snapshot(fixture.maintenance)

    # When
    decision = Topic59MaintenanceGate.for_profile(fixture.profile).evaluate(
        fixture.projection, fixture.now,
    )
    observation = await publish_with_tripwires(fixture)

    # Then
    assert decision.kind is Topic59MaintenanceDecisionKind.DENY
    assert decision.reason is not None
    assert observation.result.disposition is Topic59PublicationDisposition.REFUSED
    assert observation.result.reason is Topic59IncidentReason.MAINTENANCE_REJECTED
    assert observation.result.message_id is None
    assert observation.result.maintenance_audit_digest is None
    assert (
        observation.claim_calls,
        observation.record_calls,
        observation.send_calls,
        observation.edit_calls,
        observation.network_calls,
    ) == (0, 0, 0, 0, 0)
    assert not fixture.ledger.exists()
    assert artifact_snapshot(fixture.maintenance) == before
