from __future__ import annotations

from datetime import date
from pathlib import Path

import pytest

import checkin_cli.customer_admin as customer_admin_module
from checkin_cli.customer_admin import (
    CustomerAdminError,
    commit_multi_customer_admission_migration,
)
from checkin_cli.multi_customer_admission_migration import (
    apply_admission_migration,
    propose_admission_migration,
)
from checkin_cli.multi_customer_admission_migration_models import (
    AdmissionMigrationError,
)
from tests.multi_customer_testkit import (
    TEST_CANDIDATE_DIGEST,
    admission_proposal,
)
from tests.test_customer_admin import _activation_fixture, activate_customer


def test_capacity_migration_rejects_wrong_approval_without_mutation(
    tmp_path: Path,
) -> None:
    profile_root, registry_path, _, _ = _activation_fixture(tmp_path)
    before = registry_path.read_bytes()
    proposal = admission_proposal(registry_path, 5)

    with pytest.raises(CustomerAdminError, match="rejected"):
        commit_multi_customer_admission_migration(
            profile_root,
            proposal,
            "wrong approval",
        )

    assert registry_path.read_bytes() == before


def test_capacity_proposal_rejects_invalid_candidate_binding(
    tmp_path: Path,
) -> None:
    _, registry_path, _, _ = _activation_fixture(tmp_path)

    with pytest.raises(AdmissionMigrationError, match="candidate"):
        propose_admission_migration(
            registry_path.read_bytes(),
            candidate_digest="not-a-candidate",
            max_enabled_customers=5,
        )


def test_capacity_apply_rejects_stale_registry_bytes(tmp_path: Path) -> None:
    _, registry_path, _, _ = _activation_fixture(tmp_path)
    before = registry_path.read_bytes()
    _, proposal = propose_admission_migration(
        before,
        candidate_digest=TEST_CANDIDATE_DIGEST,
        max_enabled_customers=5,
    )

    with pytest.raises(AdmissionMigrationError, match="before"):
        apply_admission_migration(
            before + b"\n",
            proposal,
            proposal.approval_phrase,
        )


def test_capacity_migration_write_failure_rolls_back_exactly(
    tmp_path: Path,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    profile_root, registry_path, data_root, checklist_path = _activation_fixture(
        tmp_path,
    )
    activate_customer(
        profile_root,
        data_root,
        "client_001",
        checklist_path,
        kst_date=date(2026, 8, 1),
    )
    registry_before = registry_path.read_bytes()
    journal_path = profile_root / "data/customer-activation-journal.json"
    journal_before = journal_path.read_bytes()
    proposal = admission_proposal(registry_path, 5)
    atomic_write = customer_admin_module._atomic_write_bytes
    failed = False

    def fail_registry_write(path: Path, content: bytes) -> None:
        nonlocal failed
        if path == registry_path and not failed:
            failed = True
            raise OSError("registry write crash")
        atomic_write(path, content)

    monkeypatch.setattr(
        customer_admin_module,
        "_atomic_write_bytes",
        fail_registry_write,
    )
    with pytest.raises(CustomerAdminError, match="migration failed"):
        commit_multi_customer_admission_migration(
            profile_root,
            proposal,
            proposal.approval_phrase,
        )

    assert registry_path.read_bytes() == registry_before
    assert journal_path.read_bytes() == journal_before
    assert not (
        profile_root / "data/customer-activation-receipts/client_001.json"
    ).exists()
