"""Strict flat authority-root namespace validation."""

from __future__ import annotations

import hashlib
import json
import os
import re
import stat
from typing import Final

from checkin_cli.weekly_operations import CustomerIdentityDigest, WeeklyOperationsCorruption, customer_storage_digest as _customer_storage_digest
from checkin_cli.weekly_operations_canonical_registry_history import REGISTRATION_SCHEMA, REGISTRY_NAME, validate_registration_history
from checkin_cli.weekly_operations_history import validate_history_bytes

MARKER_NAME: Final = "authority-v1.json"
DATA_SUFFIX: Final = ".day-status-v1.jsonl"
LOCK_SUFFIX: Final = ".day-status-v1.lock"
LAYOUT_SCHEMA: Final = "nutricoach-weekly-operations-flat-root-layout-v3"
_CHILD = re.compile(r"^(?P<digest>[0-9a-f]{64})(?P<suffix>\.day-status-v1\.(?:jsonl|lock))$")
_FILE_FLAGS: Final = os.O_RDONLY | os.O_NOFOLLOW | os.O_CLOEXEC | os.O_NONBLOCK


def _canonical_digest(value: tuple[str, ...]) -> str:
    return hashlib.sha256(json.dumps(value, separators=(",", ":")).encode()).hexdigest()


ROOT_INVENTORY_DIGEST: Final = _canonical_digest((MARKER_NAME, REGISTRY_NAME, "fixed-optional-registry", "regular-0600", "marker-plus-strict-flat-customer-grammar"))
LAYOUT_DIGEST: Final = _canonical_digest((LAYOUT_SCHEMA, REGISTRY_NAME, REGISTRATION_SCHEMA, "<sha256>.day-status-v1.jsonl", "<sha256>.day-status-v1.lock", "regular-0600-owner-link1"))


def customer_storage_digest(customer_identity: CustomerIdentityDigest) -> str:
    return _customer_storage_digest(customer_identity)


def customer_data_name(customer_identity: CustomerIdentityDigest) -> str:
    return customer_storage_digest(customer_identity) + DATA_SUFFIX


def customer_lock_name(customer_identity: CustomerIdentityDigest) -> str:
    return customer_storage_digest(customer_identity) + LOCK_SUFFIX


def _verify_child(descriptor: int, name: str, opened: os.stat_result) -> None:
    named = os.stat(name, dir_fd=descriptor, follow_symlinks=False)
    identity = opened.st_dev, opened.st_ino
    safe = stat.S_ISREG(opened.st_mode) and opened.st_uid == os.geteuid() and opened.st_nlink == 1 and stat.S_IMODE(opened.st_mode) == 0o600
    if not safe or identity != (named.st_dev, named.st_ino):
        raise WeeklyOperationsCorruption("authority inventory child is unsafe")


def validate_customer_inventory(descriptor: int, *, repair_target_digest: str | None = None) -> None:
    """Validate every dynamic flat child without following links."""
    try:
        registry = os.open(REGISTRY_NAME, _FILE_FLAGS, dir_fd=descriptor)
    except OSError as error:
        raise WeeklyOperationsCorruption("authority registry is unsafe") from error
    try:
        opened_registry = os.fstat(registry)
        _verify_child(descriptor, REGISTRY_NAME, opened_registry)
        registry_chunks: list[bytes] = []
        while registry_chunk := os.read(registry, 65536):
            registry_chunks.append(registry_chunk)
        _verify_child(descriptor, REGISTRY_NAME, os.fstat(registry))
        _ = validate_registration_history(b"".join(registry_chunks))
    finally:
        os.close(registry)
    for name in os.listdir(descriptor):
        if name == MARKER_NAME:
            continue
        if name == REGISTRY_NAME:
            continue
        matched = _CHILD.fullmatch(name)
        if matched is None:
            raise WeeklyOperationsCorruption("authority inventory contains an unrecognized child")
        try:
            child = os.open(name, _FILE_FLAGS, dir_fd=descriptor)
        except OSError as error:
            raise WeeklyOperationsCorruption("authority inventory child is unsafe") from error
        try:
            opened = os.fstat(child)
            _verify_child(descriptor, name, opened)
            if matched.group("suffix") == DATA_SUFFIX:
                chunks: list[bytes] = []
                while chunk := os.read(child, 65536):
                    chunks.append(chunk)
                _verify_child(descriptor, name, os.fstat(child))
                digest = matched.group("digest")
                _ = validate_history_bytes(b"".join(chunks), digest, allow_torn_tail=digest == repair_target_digest)
        finally:
            os.close(child)

