"""Canonical weekly-reminder authority postimage for the v1.5 migration."""

from __future__ import annotations

import hashlib
import json
import os
from pathlib import Path
import stat
from typing import Final, cast

import yaml
from pydantic import JsonValue, TypeAdapter

from checkin_cli.customer_coaching import load_customer_registry
from checkin_cli.weekly_operations_authority import (
    AuthorityId,
    WeeklyOperationsAuthorityRoot,
    begin_authority_initialization,
)
from checkin_cli.weekly_operations_parent import acquire_parent_authority
from checkin_cli.weekly_operations_registration_handoff import (
    begin_canonical_authority_registration,
)
from gateway.platforms.nutrition_weekly_operations_config import (
    parse_weekly_operations_config,
)
from gateway.platforms.nutrition_weekly_operations_registry_identity import (
    WeeklyOperationsRegistryIdentity,
    parse_weekly_operations_registry_identity,
)
from gateway.platforms.nutrition_weekly_reminder_owner_factory import (
    weekly_reminder_consent_digest,
)
from scripts.nutricoach_v150_live_models import (
    CANDIDATE_DIGEST,
    WEEKLY_AUTHORITY_EXPIRES_AT,
    WEEKLY_AUTHORITY_ISSUED_AT,
)
from scripts.nutricoach_v150_sealed_target import HostError, HostPaths

_OBJECT: Final = TypeAdapter(dict[str, JsonValue])
_AUTHORITY_PATH: Final = "data/weekly-operations-authority"
_FEATURE_EPOCH: Final = "weekly-operations-v1"


def weekly_authority_path(paths: HostPaths, candidate_digest: str) -> Path:
    """Return the candidate's weekly-operations authority root."""
    predecessor = paths.profile / _AUTHORITY_PATH
    if not predecessor.exists():
        return predecessor
    return paths.profile / f"{_AUTHORITY_PATH}-{candidate_digest[:16]}"


def _mapping(value: JsonValue | None, label: str) -> dict[str, JsonValue]:
    if not isinstance(value, dict):
        raise HostError(f"weekly_authority:{label}")
    return value


def _registry_identity(paths: HostPaths) -> WeeklyOperationsRegistryIdentity:
    try:
        relative = str(paths.registry.relative_to(paths.profile))
        info = paths.registry.stat(follow_symlinks=False)
    except (OSError, ValueError) as error:
        raise HostError("weekly_authority:registry_path") from error
    if (
        not stat.S_ISREG(info.st_mode)
        or stat.S_IMODE(info.st_mode) != 0o600
        or info.st_uid != os.geteuid()
        or info.st_nlink != 1
    ):
        raise HostError("weekly_authority:registry_identity")
    values: dict[str, str | int] = {
        "schema_version": "nutricoach-weekly-registry-identity-v1",
        "relative_name": relative,
        "device": info.st_dev,
        "inode": info.st_ino,
        "mode": stat.S_IMODE(info.st_mode),
        "owner": info.st_uid,
        "links": info.st_nlink,
        "content_digest": hashlib.sha256(paths.registry.read_bytes()).hexdigest(),
    }
    encoded = json.dumps(values, sort_keys=True, separators=(",", ":")).encode()
    values["binding_digest"] = hashlib.sha256(encoded).hexdigest()
    return parse_weekly_operations_registry_identity(values)


def _identity_document(
    identity: WeeklyOperationsRegistryIdentity,
) -> dict[str, JsonValue]:
    return {
        "schema_version": identity.schema_version,
        "relative_name": identity.relative_name,
        "device": identity.device,
        "inode": identity.inode,
        "mode": identity.mode,
        "owner": identity.owner,
        "links": identity.links,
        "content_digest": identity.content_digest,
        "binding_digest": identity.binding_digest,
    }


def missing_canonical_weekly_files(paths: HostPaths) -> tuple[Path, ...]:
    """Return only absent canonical files required by enabled customers."""
    registry = load_customer_registry(paths.registry, paths.profile)
    missing: list[Path] = []
    for runtime in registry.customers:
        if not runtime.spec.enabled:
            continue
        candidates = (
            runtime.wizard_root / "events.jsonl",
            runtime.wizard_root / ".events.lock",
            runtime.nutrition_plans_root / "canonical-sequence.jsonl",
        )
        for path in candidates:
            if path.is_symlink():
                raise HostError("weekly_authority:canonical_file")
            if not path.exists():
                missing.append(path)
                continue
            info = path.stat(follow_symlinks=False)
            if (
                not stat.S_ISREG(info.st_mode)
                or stat.S_IMODE(info.st_mode) != 0o600
                or info.st_uid != os.geteuid()
                or info.st_nlink != 1
            ):
                raise HostError("weekly_authority:canonical_file")
    return tuple(missing)


def initialize_canonical_weekly_files(paths: tuple[Path, ...]) -> None:
    """Exclusively create rollback-owned empty canonical files."""
    for path in paths:
        descriptor = os.open(
            path,
            os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW | os.O_CLOEXEC,
            0o600,
        )
        try:
            os.fsync(descriptor)
        finally:
            os.close(descriptor)


def _register_authority(
    paths: HostPaths,
    customer_keys: tuple[str, ...],
    candidate_digest: str = CANDIDATE_DIGEST,
    authority_path: Path | None = None,
) -> None:
    selected = authority_path or weekly_authority_path(paths, candidate_digest)
    selected.mkdir(parents=True, mode=0o700)
    parent = acquire_parent_authority(selected)
    authority: WeeklyOperationsAuthorityRoot | None = None
    created: WeeklyOperationsAuthorityRoot | None = None
    registry = load_customer_registry(paths.registry, paths.profile)
    by_key = {runtime.spec.customer_key: runtime for runtime in registry.customers}
    try:
        with begin_authority_initialization(
            parent, AuthorityId(candidate_digest)
        ) as initialization:
            created = initialization.authority
            authority = created
            _ = initialization.binding
            initialization.acknowledge_binding()
        if created is None:
            raise HostError("weekly_authority:initialization")
        for key in customer_keys:
            source = None
            with begin_canonical_authority_registration(
                by_key[key], created
            ) as registration:
                source = registration.authority
                _ = registration.binding
                registration.acknowledge_binding()
            if source is None:
                raise HostError("weekly_authority:customer_registration")
            source.close()
    finally:
        if authority is not None:
            authority.close()
        parent.close()


def build_weekly_authority_postimage(
    paths: HostPaths,
    candidate_digest: str = CANDIDATE_DIGEST,
    authority_path: Path | None = None,
) -> bytes:
    """Build canonical sidecars and return the complete YAML config postimage."""
    identity = _registry_identity(paths)
    registry = load_customer_registry(paths.registry, paths.profile)
    enabled = tuple(runtime for runtime in registry.customers if runtime.spec.enabled)
    if not enabled or len(enabled) > 5:
        raise HostError("weekly_authority:enabled_customers")
    consent_digests = {weekly_reminder_consent_digest(runtime) for runtime in enabled}
    if len(consent_digests) != 1:
        raise HostError("weekly_authority:consent_binding")
    customer_keys = tuple(runtime.spec.customer_key for runtime in enabled)

    try:
        raw = cast(object, yaml.safe_load(paths.config.read_text(encoding="utf-8")))
        document = _OBJECT.validate_python(raw)
    except (OSError, ValueError, yaml.YAMLError) as error:
        raise HostError("weekly_authority:config") from error
    platforms = _mapping(document.get("platforms"), "platforms")
    telegram = _mapping(platforms.get("telegram"), "telegram")
    extra = _mapping(telegram.get("extra"), "extra")
    production_preflight = extra.get("production_preflight")
    if production_preflight is not None:
        production = _mapping(production_preflight, "production_preflight")
        production["candidate_package_identity"] = candidate_digest
    nutrition = _mapping(extra.get("nutrition_coaching"), "nutrition_coaching")
    nutrition["profile_root"] = str(paths.profile)
    nutrition["registry_path"] = identity.relative_name
    selected = authority_path or weekly_authority_path(paths, candidate_digest)
    try:
        relative_authority = str(selected.relative_to(paths.profile))
    except ValueError as error:
        raise HostError("weekly_authority:path") from error
    nutrition["weekly_operations_authority_path"] = relative_authority
    nutrition["weekly_operations_capacity"] = 5
    nutrition["weekly_operations"] = {
        "enabled": True,
        "reminder_time": "20:00:00",
        "missed_cutoff_time": "23:00:00",
        "weekly_weekday": 0,
        "feature_epoch": _FEATURE_EPOCH,
        "registry_identity_binding_digest": identity.binding_digest,
    }
    config = parse_weekly_operations_config(extra)
    owner = registry.owner
    nutrition["weekly_operations_authority"] = {
        "schema": "nutricoach-weekly-operations-authority-v2",
        "candidate_digest": candidate_digest,
        "config_digest": config.digest,
        "enabled_customer_keys": list(customer_keys),
        "owner": {"user_id": owner.user_id, "chat_id": owner.chat_id, "version": 7},
        "consent_digest": next(iter(consent_digests)),
        "registry_identity": _identity_document(identity),
        "issued_at": WEEKLY_AUTHORITY_ISSUED_AT,
        "expires_at": WEEKLY_AUTHORITY_EXPIRES_AT,
        "feature_epoch": _FEATURE_EPOCH,
    }
    nutrition["weekly_operations_authority_source"] = "operator"
    _register_authority(paths, customer_keys, candidate_digest, selected)
    return yaml.safe_dump(document, sort_keys=False, allow_unicode=True).encode()
