"""Descriptor-relative flat files beneath the dedicated authority root."""

from __future__ import annotations

import fcntl
import os
import stat
from collections.abc import Generator
from contextlib import contextmanager
from dataclasses import dataclass
from typing import Final

from checkin_cli.weekly_operations import CustomerIdentityDigest, WeeklyOperationsCorruption
from checkin_cli.weekly_operations_authority import WeeklyOperationsAuthorityRoot
from checkin_cli.weekly_operations_history import HistoryValidation
from checkin_cli.weekly_operations_layout import customer_data_name, customer_lock_name, customer_storage_digest
from checkin_cli.weekly_operations_repair import WeeklyOperationsRepairBinding, validate_bound_repair_lock, validate_bound_repair_payload

FileIdentity = tuple[int, int]
_FILE_FLAGS: Final = os.O_NOFOLLOW | os.O_CLOEXEC | os.O_NONBLOCK


@dataclass(frozen=True, slots=True)
class SidecarDirectory:
    authority: WeeklyOperationsAuthorityRoot
    directory: int
    customer_digest: str
    customer_identity: CustomerIdentityDigest
    data_name: str
    lock_name: str
    allow_torn_tail: bool

    @property
    def plans(self) -> int:
        return self.directory

    def verify(self) -> None:
        if self.allow_torn_tail:
            self.authority.verify_for_repair(self.customer_identity)
        else:
            self.authority.verify_locked()


@dataclass(frozen=True, slots=True)
class LockedRepair:
    directory: SidecarDirectory
    lock_descriptor: int
    data_descriptor: int
    payload: bytes
    validation: HistoryValidation


@dataclass(frozen=True, slots=True)
class OpenedFile:
    descriptor: int
    identity: FileIdentity
    created: bool


def _identity(info: os.stat_result) -> FileIdentity:
    return info.st_dev, info.st_ino


def verify_file(directory: int, name: str, opened: os.stat_result) -> FileIdentity:
    named = os.stat(name, dir_fd=directory, follow_symlinks=False)
    identity = _identity(opened)
    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 != _identity(named):
        raise WeeklyOperationsCorruption("authority child file is unsafe or replaced")
    return identity


def open_existing_file(directory: int, name: str, flags: int) -> OpenedFile:
    descriptor = os.open(name, flags | _FILE_FLAGS, dir_fd=directory)
    try:
        return OpenedFile(descriptor, verify_file(directory, name, os.fstat(descriptor)), False)
    except (OSError, WeeklyOperationsCorruption):
        os.close(descriptor)
        raise


def open_or_create_file(directory: int, name: str, flags: int) -> OpenedFile:
    try:
        descriptor = os.open(name, flags | _FILE_FLAGS | os.O_CREAT | os.O_EXCL, 0o600, dir_fd=directory)
    except FileExistsError:
        return open_existing_file(directory, name, flags)
    try:
        return OpenedFile(descriptor, verify_file(directory, name, os.fstat(descriptor)), True)
    except (OSError, WeeklyOperationsCorruption):
        os.close(descriptor)
        raise


@contextmanager
def secure_sidecar_directory(authority: WeeklyOperationsAuthorityRoot, customer_identity: CustomerIdentityDigest, *, allow_torn_tail: bool = False) -> Generator[SidecarDirectory]:
    """Derive one flat file pair under the locked authority root."""
    with authority.parent.locked():
        try:
            if allow_torn_tail:
                authority.verify_for_repair(customer_identity)
            else:
                authority.verify_locked()
            digest = customer_storage_digest(customer_identity)
            boundary = SidecarDirectory(authority, authority.descriptor, digest, customer_identity, customer_data_name(customer_identity), customer_lock_name(customer_identity), allow_torn_tail)
            boundary.verify()
            yield boundary
        except OSError as error:
            raise WeeklyOperationsCorruption("authority child boundary is unsafe") from error


def _preflight_data(directory: SidecarDirectory) -> FileIdentity | None:
    try:
        opened = open_existing_file(directory.directory, directory.data_name, os.O_RDONLY)
    except FileNotFoundError:
        return None
    os.close(opened.descriptor)
    return opened.identity


def _read_descriptor(descriptor: int) -> bytes:
    _ = os.lseek(descriptor, 0, os.SEEK_SET)
    chunks: list[bytes] = []
    while chunk := os.read(descriptor, 65536):
        chunks.append(chunk)
    return b"".join(chunks)


@contextmanager
def locked_repair_sidecar(authority: WeeklyOperationsAuthorityRoot, customer_identity: CustomerIdentityDigest, binding: WeeklyOperationsRepairBinding) -> Generator[LockedRepair]:
    """Open only the pre-existing bound lock and data file for repair."""
    with secure_sidecar_directory(authority, customer_identity, allow_torn_tail=True) as directory:
        try:
            lock = open_existing_file(directory.directory, directory.lock_name, os.O_RDWR)
        except OSError as error:
            raise WeeklyOperationsCorruption("repair requires an existing safe lock") from error
        try:
            validate_bound_repair_lock(binding, os.fstat(lock.descriptor), _read_descriptor(lock.descriptor))
            fcntl.flock(lock.descriptor, fcntl.LOCK_EX)
            directory.verify()
            validate_bound_repair_lock(binding, os.fstat(lock.descriptor), _read_descriptor(lock.descriptor))
            try:
                data = open_existing_file(directory.directory, directory.data_name, os.O_RDONLY)
            except OSError as error:
                raise WeeklyOperationsCorruption("repair data file is absent or unsafe") from error
            try:
                payload = _read_descriptor(data.descriptor)
                validation = validate_bound_repair_payload(binding, os.fstat(data.descriptor), payload)
                yield LockedRepair(directory, lock.descriptor, data.descriptor, payload, validation)
            finally:
                os.close(data.descriptor)
        finally:
            fcntl.flock(lock.descriptor, fcntl.LOCK_UN)
            os.close(lock.descriptor)


@contextmanager
def locked_sidecar(authority: WeeklyOperationsAuthorityRoot, customer_identity: CustomerIdentityDigest, *, exclusive: bool, allow_torn_tail: bool = False) -> Generator[SidecarDirectory]:
    """Hold one validated flat-customer lock under the authority descriptor."""
    with secure_sidecar_directory(authority, customer_identity, allow_torn_tail=allow_torn_tail) as directory:
        data_identity = _preflight_data(directory)
        directory.verify()
        lock = open_or_create_file(directory.directory, directory.lock_name, os.O_RDWR)
        try:
            fcntl.flock(lock.descriptor, fcntl.LOCK_EX if exclusive else fcntl.LOCK_SH)
            directory.verify()
            _ = verify_file(directory.directory, directory.lock_name, os.fstat(lock.descriptor))
            if data_identity is not None and _preflight_data(directory) != data_identity:
                raise WeeklyOperationsCorruption("authority data was replaced during lock acquisition")
            yield directory
        except OSError as error:
            raise WeeklyOperationsCorruption("authority lock boundary is unsafe") from error
        finally:
            fcntl.flock(lock.descriptor, fcntl.LOCK_UN)
            os.close(lock.descriptor)
