"""Exact authority-bound input and outcome types for weekly owner drafts."""

from __future__ import annotations

import hashlib
import json
from collections.abc import Callable
from dataclasses import dataclass
from typing import override

from checkin_cli.weekly_operations_grounding import (
    GroundedWeeklyFacts,
    WeeklyGroundingBindings,
    lock_weekly_facts,
)
from checkin_cli.weekly_operations_owner_binding import BoundWeeklySummaryForOwnerDraft

from .nutrition_weekly_operations_authority import (
    WeeklyOperationsAuthorityReceipt,
    WeeklyOperationsRuntimeContext,
)
from .nutrition_weekly_operations_config import WeeklyOperationsConfig
from .nutrition_weekly_owner_contract import WeeklyLifecycleResult


@dataclass(frozen=True, slots=True)
class WeeklyOwnerDraftRequest:
    customer_key: str
    owner_key: tuple[str, str, str]
    config: WeeklyOperationsConfig
    receipt: WeeklyOperationsAuthorityReceipt
    runtime: WeeklyOperationsRuntimeContext
    bound_summary: BoundWeeklySummaryForOwnerDraft
    storage_binding_digest: str
    current_bound_summary: Callable[[], BoundWeeklySummaryForOwnerDraft]

    @property
    def facts(self) -> GroundedWeeklyFacts:
        return lock_weekly_facts(self.bound_summary, self.bindings)

    @property
    def bindings(self) -> WeeklyGroundingBindings:
        return WeeklyGroundingBindings(
            self.runtime.candidate_digest, self.config.digest,
            customer_authority_digest(self.runtime),
            authority_hash("owner", *self.owner_key), self.runtime.consent_digest,
        )


@dataclass(frozen=True, slots=True)
class WeeklyOwnerDraftResult:
    accepted: bool
    draft: WeeklyLifecycleResult | None
    provider_calls: int
    fallback_used: bool
    error: str | None = None


@dataclass(frozen=True, slots=True)
class WeeklyProviderOutcomeUnknown(RuntimeError):
    reason: str

    @override
    def __str__(self) -> str:
        return f"weekly provider outcome is unknown: {self.reason}"


def customer_authority_digest(runtime: WeeklyOperationsRuntimeContext) -> str:
    return authority_hash(
        "customer-authority", runtime.candidate_digest, runtime.consent_digest,
        str(runtime.feature_epoch), runtime.owner_chat_id, runtime.owner_user_id,
        str(runtime.owner_version),
    )


def authority_hash(domain: str, *parts: str) -> str:
    encoded = json.dumps((domain, parts), sort_keys=True, separators=(",", ":"))
    return hashlib.sha256(encoded.encode()).hexdigest()
