"""App-layer model-context service contracts and implementation.

Responsibility: define adapter-facing projections for model-visible runtime
context and output-governance hints derived from resolved execution truth.

Non-responsibility: assemble prompts, serialize provider payloads, or perform
runtime/tool-call side effects.

Spec source:
- docs/proposals/execution-architecture-refactor.md#execution-contract-specific-design-rules/model-visible-runtime-context
- docs/proposals/execution-architecture-refactor.md#repository-target-architecture/app
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Literal, Protocol

from anima.core.execution import (
    ExecutionOutputGovernanceView,
    RuntimeContextFactsView,
    RuntimeOutputPolicyView,
)

ModelContextAdapterSurface = Literal["runtime_model_instructions"]


@dataclass(frozen=True)
class ModelContextProjection:
    """Adapter-facing projection for model-injection surfaces.

    Invariants:
    - ``runtime_context`` carries only contract-approved model-visible facts.
    - ``output_policy`` is included so runtime adapters can explain progressive
      inspection and truncation expectations without reading the full contract.
    - This projection is consumed by runtime adapters that inject context into
      model instructions, not by terminal presenters.
    """

    adapter_surface: ModelContextAdapterSurface
    runtime_context: RuntimeContextFactsView
    output_policy: RuntimeOutputPolicyView


class ContextService(Protocol):
    """App-layer boundary for model-visible runtime-context projection.

    Invariants:
    - Consumers depend on ``ExecutionOutputGovernanceView`` instead of the full
      ``ResolvedExecutionContract``.
    - Model-injection adapters consume this service; terminal result adapters do
      not.
    - The projection preserves the separation between runtime context facts and
      terminal-result shaping policy.
    """

    def project_model_context(
        self,
        contract: ExecutionOutputGovernanceView,
        *,
        adapter_surface: ModelContextAdapterSurface = "runtime_model_instructions",
    ) -> ModelContextProjection: ...


@dataclass(frozen=True)
class DefaultContextService:
    """Default implementation of ContextService.

    This service projects model-visible runtime context from a resolved
    execution contract. All runtime facts (work_dir, project_root, filesystem_scope,
    effective_tool_count, etc.) come exclusively from the contract - no
    independent derivation is performed.

    Spec source: model-visible-runtime-context

    Invariants:
    - All model-visible facts derive from contract.model_context.values only.
    - No adapter independently computes filesystem/project-root hints.
    - The projection is a read-only view, never mutations to the contract.

    Examples:
        >>> from anima.core.execution import ResolvedExecutionContract
        >>> from anima.core.contracts import RuntimeOutputPolicy
        >>> # Create a minimal contract for testing
        >>> contract = ResolvedExecutionContract.model_validate({
        ...     "identity": {"instance_id": "test", "resolver": {"resolver_version": "v1"}},
        ...     "runtime": {"effective_model": "gpt-4o"},
        ...     "tool_access": {"effective_side_effect_policy": "allow"},
        ...     "persona_provenance": {"source": "file", "materialization_status": "not_required", "inline_behavior": "reject_spawn", "child_inheritance_policy": "require_explicit_child_persona", "spawnability": {"can_spawn": True}},
        ...     "lifecycle_policy": {"lifecycle": "ephemeral", "completion_policy": "explicit"},
        ...     "output_policy": {"provider_profile": "test-provider", "truncation_strategy": "truncate"},
        ...     "model_context": {"values": {"instance_id": "test", "work_dir": "/workspace", "project_root": "/project"}}
        ... })
        >>> service = DefaultContextService()
        >>> projection = service.project_model_context(contract)
        >>> projection.runtime_context.values.get("work_dir")
        '/workspace'
        >>> projection.runtime_context.values.get("project_root")
        '/project'
        >>> projection.output_policy.provider_profile
        'test-provider'
    """

    def project_model_context(
        self,
        contract: ExecutionOutputGovernanceView,
        *,
        adapter_surface: ModelContextAdapterSurface = "runtime_model_instructions",
    ) -> ModelContextProjection:
        """Project model-visible context from resolved execution contract.

        Args:
            contract: The resolved execution contract containing model_context
                and output_policy views.
            adapter_surface: The target surface for injection (currently only
                "runtime_model_instructions").

        Returns:
            ModelContextProjection containing:
            - runtime_context: model-visible facts (work_dir, project_root,
              filesystem_scope, effective_tool_count, etc.)
            - output_policy: output governance values (provider_profile,
              per_call/per_turn caps, truncation_strategy)

        Note:
            All facts come exclusively from the contract. No independent
            computation of filesystem/project-root hints occurs here.
            The resolver already conditionally includes these values only
            when effective filesystem/shell access exists.

            The contract's model_context and output_policy already implement
            the required Protocol interfaces, so we pass them through directly.
        """
        # The contract's model_context and output_policy already implement
        # the RuntimeContextFactsView and RuntimeOutputPolicyView protocols.
        # No transformation needed - all facts come exclusively from contract.
        return ModelContextProjection(
            adapter_surface=adapter_surface,
            runtime_context=contract.model_context,
            output_policy=contract.output_policy,
        )
