"""Descriptor-bound append-only single-flight ledger for weekly generation."""

from __future__ import annotations

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

from checkin_cli.weekly_operations_knowledge import WeeklyEmphasis, WeeklyPrincipleId
from gateway.platforms.nutrition_weekly_owner_storage import WeeklyOwnerStorageAuthority

_DATA: Final = "weekly-draft-generations.jsonl"
_LOCK: Final = "weekly-draft-generations.lock"

from .nutrition_weekly_owner_ledger_types import (
    WeeklyGenerationLedgerError,
    WeeklyGenerationOutcome,
    WeeklyGenerationRow,
    WeeklyGenerationState,
)

class WeeklyGenerationTransaction:
    """A lock-held append transaction; mutation is its sole purpose."""

    def __init__(self, authority: WeeklyOwnerStorageAuthority, rows: tuple[WeeklyGenerationRow, ...]) -> None:
        self._authority: WeeklyOwnerStorageAuthority = authority
        self.rows: tuple[WeeklyGenerationRow, ...] = rows

    def latest(self, logical_key: str) -> WeeklyGenerationRow | None:
        return next((row for row in reversed(self.rows) if row.logical_key == logical_key), None)

    def append(
        self,
        base: WeeklyGenerationRow,
        *,
        state: WeeklyGenerationState,
        outcome: WeeklyGenerationOutcome,
        ordinal: int,
        request_digest: str,
        principle_ids: tuple[WeeklyPrincipleId, ...] = (),
        emphasis: WeeklyEmphasis | None = None,
        fallback: bool = False,
        source_digest: str = "",
        draft_id: str = "",
    ) -> WeeklyGenerationRow:
        predecessor = self.rows[-1].row_digest if self.rows else ""
        from .nutrition_weekly_owner_ledger_codec import encode_row
        encoded = encode_row(
            base, state, outcome, ordinal, request_digest, principle_ids,
            emphasis, fallback, source_digest, draft_id, predecessor,
        )
        descriptor = self._authority.open_file(
            _DATA, os.O_WRONLY | os.O_APPEND | os.O_CREAT,
        )
        try:
            os.fchmod(descriptor, 0o600)
            offset = 0
            while offset < len(encoded):
                offset += os.write(descriptor, encoded[offset:])
            os.fsync(descriptor)
            self._authority.verify_child(_DATA, descriptor)
            os.fsync(self._authority.descriptor)
        finally:
            os.close(descriptor)
        from .nutrition_weekly_owner_ledger_codec import parse_row
        row = parse_row(encoded, predecessor)
        self.rows = (*self.rows, row)
        return row


class WeeklyGenerationLedger:
    def __init__(self, authority: WeeklyOwnerStorageAuthority) -> None:
        authority.verify()
        self._authority: WeeklyOwnerStorageAuthority = authority

    def read_rows(self) -> tuple[WeeklyGenerationRow, ...]:
        return self._read()

    @contextmanager
    def locked(self) -> Generator[WeeklyGenerationTransaction, None, None]:
        descriptor = self._authority.open_file(_LOCK, os.O_RDWR | os.O_CREAT)
        try:
            os.fchmod(descriptor, 0o600)
            self._authority.verify_child(_LOCK, descriptor)
            fcntl.flock(descriptor, fcntl.LOCK_EX)
            self._authority.verify_child(_LOCK, descriptor)
            yield WeeklyGenerationTransaction(self._authority, self._read())
            self._authority.verify_child(_LOCK, descriptor)
        finally:
            fcntl.flock(descriptor, fcntl.LOCK_UN)
            os.close(descriptor)

    def _read(self) -> tuple[WeeklyGenerationRow, ...]:
        self._authority.verify()
        if _DATA not in os.listdir(self._authority.descriptor):
            return ()
        descriptor = self._authority.open_file(_DATA, os.O_RDONLY)
        try:
            info = os.fstat(descriptor)
            if stat.S_IMODE(info.st_mode) != 0o600:
                raise WeeklyGenerationLedgerError("file mode")
            data = os.pread(descriptor, info.st_size, 0)
            if data != os.pread(descriptor, info.st_size, 0):
                raise WeeklyGenerationLedgerError("changed during read")
            self._authority.verify_child(_DATA, descriptor)
        finally:
            os.close(descriptor)
        rows: list[WeeklyGenerationRow] = []
        predecessor = ""
        for line in data.splitlines(keepends=True):
            from .nutrition_weekly_owner_ledger_codec import parse_row
            row = parse_row(line, predecessor)
            rows.append(row)
            predecessor = row.row_digest
        return tuple(rows)


def generation_base(
    logical_key: str, request_base_digest: str, customer_digest: str,
    week_start: str, owner_route_digest: str, authority_digest: str,
    aggregate_digest: str, source_authority_digest: str, candidate_digest: str,
    storage_binding_digest: str, config_digest: str, consent_digest: str,
) -> WeeklyGenerationRow:
    return WeeklyGenerationRow(
        logical_key, request_base_digest, customer_digest, week_start,
        owner_route_digest, authority_digest, aggregate_digest,
        source_authority_digest, storage_binding_digest, candidate_digest,
        config_digest, consent_digest,
        "", 0, WeeklyGenerationState.INVALID, WeeklyGenerationOutcome.SCHEMA_INVALID,
        (), None, False, "", "", "", "",
    )


def require_exact_request_row(base: WeeklyGenerationRow, row: WeeklyGenerationRow) -> None:
    """Reject a self-hashed row that is not the exact current request authority."""
    expected = (
        base.logical_key, base.request_base_digest, base.customer_digest,
        base.week_start, base.owner_route_digest, base.authority_digest,
        base.aggregate_digest, base.source_authority_digest,
        base.storage_binding_digest, base.candidate_digest,
        base.config_digest, base.consent_digest,
    )
    observed = (
        row.logical_key, row.request_base_digest, row.customer_digest,
        row.week_start, row.owner_route_digest, row.authority_digest,
        row.aggregate_digest, row.source_authority_digest,
        row.storage_binding_digest, row.candidate_digest,
        row.config_digest, row.consent_digest,
    )
    if observed != expected:
        raise WeeklyGenerationLedgerError("request authority conflict")
    if row.state is WeeklyGenerationState.BOUND and (not row.draft_id or not row.source_digest):
        raise WeeklyGenerationLedgerError("draft binding conflict")



__all__ = (
    "WeeklyGenerationLedger", "WeeklyGenerationLedgerError",
    "WeeklyGenerationOutcome", "WeeklyGenerationRow",
    "WeeklyGenerationState", "WeeklyGenerationTransaction",
    "generation_base", "require_exact_request_row",
)
