"""Global fail-closed validation for every customer history."""

from __future__ import annotations

from datetime import date, datetime
from pathlib import Path
from unittest import TestCase

from checkin_cli.weekly_operations import CanonicalPin, CustomerKey, DayState, WeeklyOperationInput, WeeklyOperationRow, WeeklyOperationsCorruption, WeeklyOperationsInputError, canonical_weekly_row, customer_identity_digest, weekly_row_digest
from checkin_cli.weekly_operations_authority import AuthorityId, WeeklyOperationsAuthorityRoot, issue_repair_authority, open_authority_root, open_authority_root_for_repair
from checkin_cli.weekly_operations_layout import customer_data_name, customer_lock_name
from checkin_cli.weekly_operations_store import WeeklyOperationsStore

from tests._weekly_operations_support import initialize_at

FORGED = CustomerKey("client_001")
UNRELATED = CustomerKey("client_002")
THIRD = CustomerKey("client_003")
ASSERTIONS = TestCase()


def _operation(customer: CustomerKey, day: int, sequence: int, digest: str) -> WeeklyOperationInput:
    local_day = date(2026, 8, day)
    occurred = datetime.fromisoformat(f"2026-08-{day:02d}T20:00:00+09:00")
    return WeeklyOperationInput.for_customer(customer, local_day, DayState.SUBMITTED, CanonicalPin(sequence, digest * 64), occurred)


def _setup(tmp_path: Path) -> tuple[Path, WeeklyOperationsAuthorityRoot, WeeklyOperationsStore, WeeklyOperationsStore]:
    path = tmp_path / "authority"
    path.mkdir(mode=0o700)
    authority = initialize_at(path, AuthorityId("a" * 64))
    return path, authority, WeeklyOperationsStore.for_authority(authority, FORGED), WeeklyOperationsStore.for_authority(authority, UNRELATED)


def _data(path: Path, customer: CustomerKey = FORGED) -> Path:
    return path / customer_data_name(customer_identity_digest(customer))


def _snapshot(path: Path) -> tuple[tuple[str, bytes], ...]:
    return tuple(sorted((str(item.relative_to(path)), item.read_bytes()) for item in path.rglob("*") if item.is_file()))


def _rewrite(path: Path, rows: tuple[WeeklyOperationRow, ...]) -> None:
    payload = b"".join(canonical_weekly_row(row, include_digest=True) + b"\n" for row in rows)
    _ = _data(path).write_bytes(payload)
    _data(path).chmod(0o600)


def _assert_unrelated_blocked(path: Path, unrelated: WeeklyOperationsStore) -> None:
    before = _snapshot(path)
    with ASSERTIONS.assertRaises(WeeklyOperationsCorruption):
        _ = unrelated.append(_operation(UNRELATED, 19, 9, "9"))
    assert _snapshot(path) == before


def test_forged_logical_key_blocks_every_customer_mutation(tmp_path: Path) -> None:
    path, _, forged, unrelated = _setup(tmp_path)
    row = forged.append(_operation(FORGED, 17, 1, "1")).row
    changed = row.model_copy(update={"logical_key": "f" * 64, "row_digest": "0" * 64})
    changed = changed.model_copy(update={"row_digest": weekly_row_digest(changed)})
    _rewrite(path, (changed,))
    _assert_unrelated_blocked(path, unrelated)


def test_forged_predecessor_chain_blocks_every_customer_mutation(tmp_path: Path) -> None:
    path, _, forged, unrelated = _setup(tmp_path)
    first = forged.append(_operation(FORGED, 17, 1, "1")).row
    second = forged.append(_operation(FORGED, 18, 2, "2")).row
    changed = second.model_copy(update={"predecessor_row_digest": "f" * 64, "row_digest": "0" * 64})
    changed = changed.model_copy(update={"row_digest": weekly_row_digest(changed)})
    _rewrite(path, (first, changed))
    _assert_unrelated_blocked(path, unrelated)


def test_forged_canonical_order_blocks_every_customer_mutation(tmp_path: Path) -> None:
    path, _, forged, unrelated = _setup(tmp_path)
    first = forged.append(_operation(FORGED, 17, 2, "2")).row
    second = forged.append(_operation(FORGED, 18, 3, "3")).row
    changed = second.model_copy(update={"canonical_sequence": 1, "row_digest": "0" * 64})
    changed = changed.model_copy(update={"row_digest": weekly_row_digest(changed)})
    _rewrite(path, (first, changed))
    _assert_unrelated_blocked(path, unrelated)


def test_forged_same_sequence_digest_blocks_every_customer_mutation(tmp_path: Path) -> None:
    path, _, forged, unrelated = _setup(tmp_path)
    first = forged.append(_operation(FORGED, 17, 1, "1")).row
    second = forged.append(_operation(FORGED, 18, 2, "2")).row
    changed = second.model_copy(update={"canonical_sequence": 1, "row_digest": "0" * 64})
    changed = changed.model_copy(update={"row_digest": weekly_row_digest(changed)})
    _rewrite(path, (first, changed))
    _assert_unrelated_blocked(path, unrelated)


def test_partial_source_lineage_blocks_every_customer_mutation(tmp_path: Path) -> None:
    path, _, forged, unrelated = _setup(tmp_path)
    row = forged.append(_operation(FORGED, 17, 1, "1")).row
    changed = row.model_copy(update={"source_event_id": "forged-source", "row_digest": "0" * 64})
    changed = changed.model_copy(update={"row_digest": weekly_row_digest(changed)})
    _rewrite(path, (changed,))
    _assert_unrelated_blocked(path, unrelated)


def test_filename_mismatched_history_with_paired_lock_blocks_mutation(tmp_path: Path) -> None:
    path, _, forged, unrelated = _setup(tmp_path)
    _ = forged.append(_operation(FORGED, 17, 1, "1"))
    customers = path
    injected = customers / customer_data_name(customer_identity_digest(THIRD))
    lock = customers / customer_lock_name(customer_identity_digest(THIRD))
    _ = injected.write_bytes(_data(path).read_bytes())
    _ = lock.write_bytes(b"")
    injected.chmod(0o600)
    lock.chmod(0o600)
    _assert_unrelated_blocked(path, unrelated)


def test_other_customer_interior_corruption_blocks_mutation(tmp_path: Path) -> None:
    path, _, forged, unrelated = _setup(tmp_path)
    _ = forged.append(_operation(FORGED, 17, 1, "1"))
    payload = _data(path).read_bytes().replace(b'"state":"submitted"', b'"state":"forgedxxx"')
    _ = _data(path).write_bytes(payload)
    _data(path).chmod(0o600)
    _assert_unrelated_blocked(path, unrelated)


def test_other_customer_torn_tail_blocks_then_selected_repair_unblocks(tmp_path: Path) -> None:
    path, _, forged, unrelated = _setup(tmp_path)
    row = forged.append(_operation(FORGED, 17, 1, "1")).row
    with _data(path).open("ab") as handle:
        _ = handle.write(b'{"schema_version"')
    _assert_unrelated_blocked(path, unrelated)
    repair_authority = issue_repair_authority(forged.authority, forged.customer_identity_digest)
    repair_store = WeeklyOperationsStore.for_authority(repair_authority, FORGED)
    repaired = repair_store.repair_torn_tail()
    repair_authority.close()
    assert repaired.retained_rows == 1 and repaired.removed_bytes > 0
    assert forged.read() == (row,)
    assert unrelated.append(_operation(UNRELATED, 19, 9, "9")).appended is True


def test_fresh_repair_capability_permits_only_selected_tail_repair(tmp_path: Path) -> None:
    path, authority, forged, _ = _setup(tmp_path)
    row = forged.append(_operation(FORGED, 17, 1, "1")).row
    binding = authority.binding
    with _data(path).open("ab") as handle:
        _ = handle.write(b"torn")
    authority.close()
    with ASSERTIONS.assertRaises(WeeklyOperationsCorruption):
        _ = open_authority_root(authority.parent, binding)
    repair_authority = open_authority_root_for_repair(authority.parent, binding, customer_identity_digest(FORGED))
    repair_store = WeeklyOperationsStore.for_authority(repair_authority, FORGED)
    with ASSERTIONS.assertRaisesRegex(WeeklyOperationsInputError, "repair-only authority"):
        _ = repair_store.append(_operation(FORGED, 18, 2, "2"))
    assert repair_store.repair_torn_tail().retained_rows == 1
    repair_authority.close()
    reopened = open_authority_root(authority.parent, binding)
    assert WeeklyOperationsStore.for_authority(reopened, FORGED).read() == (row,)
