"""Production factory for the retained weekly reminder authority owner."""

from __future__ import annotations

import hashlib
import json
from collections.abc import Mapping
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path

from typing_extensions import TypeIs

from checkin_cli.customer_coaching import CustomerRegistry, CustomerRuntime

from .nutrition_weekly_operations_authority import (
    WeeklyOperationsAuthorityReceipt,
    WeeklyOperationsRuntimeContext,
    parse_weekly_operations_authority,
)
from .nutrition_weekly_operations_config import (
    JsonValue,
    WeeklyOperationsAuthorityError,
    WeeklyOperationsConfigError,
    parse_weekly_operations_config,
)
from .nutrition_weekly_reminder_authority import (
    RegisteredWeeklyReminderCustomer,
    WeeklyReminderAuthorityOwner,
    WeeklyReminderOwnerError,
    WeeklyReminderOwnerInput,
)


@dataclass(frozen=True, slots=True)
class WeeklyReminderProductionInput:
    extra: Mapping[str, JsonValue]
    candidate_digest: str | None
    registry: CustomerRegistry
    registry_path: Path
    customers: tuple[RegisteredWeeklyReminderCustomer, ...]


@dataclass(frozen=True, slots=True)
class _ProductionContextSource:
    candidate_digest: str
    receipt: WeeklyOperationsAuthorityReceipt

    def consent_digest(self, runtime: CustomerRuntime) -> str:
        return weekly_reminder_consent_digest(runtime)

    def current_context(
        self, runtime: CustomerRuntime, now: datetime
    ) -> WeeklyOperationsRuntimeContext:
        consent = runtime.spec.ai_processing_consent
        return WeeklyOperationsRuntimeContext(
            self.candidate_digest,
            runtime.spec.customer_key,
            self.receipt.owner.user_id,
            self.receipt.owner.chat_id,
            self.receipt.owner.version,
            weekly_reminder_consent_digest(runtime),
            consent.granted,
            self.receipt.feature_epoch,
            now,
        )


def weekly_reminder_consent_digest(runtime: CustomerRuntime) -> str:
    consent = runtime.spec.ai_processing_consent
    payload = {
        "granted": consent.granted,
        "recorded_on": None if consent.recorded_on is None else consent.recorded_on.isoformat(),
        "notice_version": consent.notice_version,
    }
    encoded = json.dumps(payload, sort_keys=True, separators=(",", ":")).encode()
    return hashlib.sha256(encoded).hexdigest()


def _json_mapping(
    value: JsonValue | None,
) -> TypeIs[Mapping[str, JsonValue]]:
    return isinstance(value, Mapping)


def build_weekly_reminder_authority_owner(
    data: WeeklyReminderProductionInput,
) -> WeeklyReminderAuthorityOwner | None:
    """Build the production owner from current gateway facts and real capabilities."""
    try:
        config = parse_weekly_operations_config(data.extra)
        if not config.enabled:
            return None
        nutrition = data.extra.get("nutrition_coaching")
        if not _json_mapping(nutrition):
            raise WeeklyReminderOwnerError("weekly reminder nutrition config is unavailable")
        raw = nutrition.get("weekly_operations_authority")
        if not _json_mapping(raw):
            raise WeeklyReminderOwnerError("weekly reminder authority receipt is unavailable")
        receipt = parse_weekly_operations_authority(raw)
    except (WeeklyOperationsConfigError, WeeklyOperationsAuthorityError) as error:
        raise WeeklyReminderOwnerError("weekly reminder production config is invalid") from error
    candidate = data.candidate_digest
    if candidate is None or receipt.candidate_digest != candidate:
        raise WeeklyReminderOwnerError("weekly reminder candidate authority disagrees")
    try:
        registry_digest = hashlib.sha256(data.registry_path.read_bytes()).hexdigest()
    except OSError as error:
        raise WeeklyReminderOwnerError("weekly reminder registry is unavailable") from error
    owner = data.registry.owner
    if (
        receipt.owner.user_id != owner.user_id
        or receipt.owner.chat_id != owner.chat_id
    ):
        raise WeeklyReminderOwnerError("weekly reminder owner authority disagrees")
    enabled = set(receipt.enabled_customer_keys)
    registered = {customer.runtime.spec.customer_key: customer for customer in data.customers}
    if not enabled or not enabled <= set(registered):
        raise WeeklyReminderOwnerError("weekly reminder registered capability is unavailable")
    for key in enabled:
        if weekly_reminder_consent_digest(registered[key].runtime) != receipt.consent_digest:
            raise WeeklyReminderOwnerError("weekly reminder consent authority disagrees")
    result = WeeklyReminderAuthorityOwner(
        WeeklyReminderOwnerInput(
            config,
            receipt,
            registry_digest,
            data.customers,
            _ProductionContextSource(candidate, receipt),
        )
    )
    result.verify_registry(data.registry)
    return result
