"""Agent Platform Port (INV-G12 / docs/spec/X15) — the single seam to the platform.

Paperclip is the *agent platform*: a replaceable shell, not the core. This module
is the ONLY place in the web layer that may import the Paperclip client
(``web.paperclip_client`` / ``web.paperclip_api``). ``web/app.py`` — and any future
web code — imports the platform operations from HERE, never from the Paperclip
modules directly. So the dependency points inward (Ports & Adapters / the
Dependency Rule, Cockburn / Martin): swapping the platform means re-implementing
this one module, not touching app.py.

Enforced by the leak-guard (X15 §4 / R4): no file outside this Port imports
``paperclip_client`` / ``paperclip_api``.

Two tiers:
  • **Lifecycle side-effects** — archive / restore / create a case's project, and
    the case-status notification — are also exposed under domain names
    (``archive_case_project`` …). These are the genuine domain events the app
    emits over a case's lifecycle; prefer them in new code.
  • **Issue / interaction / comment / agent operations** are re-exported under
    their existing ``pc_*`` names: they are request/response API calls, not
    events, so a faithful facade re-export — rather than an artificial "event" —
    is the honest treatment. Migrating these to domain verbs is a follow-up that
    can happen as call sites are touched; the import seam (the enforceable part
    of G12) holds regardless.
"""
from __future__ import annotations

# ── the Paperclip shell — imported ONLY here (the Port is the single seam) ──
from web.paperclip_api import (
    emit_case_status_webhook,
    emit_export_complete_webhook,
    emit_missing_precedent_webhook,
    pc_request,
    require_paperclip_db_url,
)
from web.agent_telemetry import instrument
from web.paperclip_client import (
    COMPANIES as PAPERCLIP_COMPANIES,
    accept_interaction as pc_accept_interaction,
    archive_project as pc_archive_project,
    create_project as pc_create_project,
    create_workflow_issue as pc_create_workflow_issue,
    get_agent_health as pc_get_agent_health,
    get_recent_escalations as pc_get_recent_escalations,
    get_predecessor_context as pc_get_predecessor_context,
    get_predecessor_for_case as pc_get_predecessor_for_case,
    get_agents_for_case as pc_get_agents_for_case,
    get_agents_for_company as pc_get_agents,
    get_case_issues as pc_get_case_issues,
    pick_default_comment_target as pc_pick_default_comment_target,
    get_issue_comments as pc_get_issue_comments,
    get_issue_interactions as pc_get_issue_interactions,
    get_project_url,
    get_run_events as pc_get_run_events,
    get_run_log as pc_get_run_log,
    list_live_runs as pc_list_live_runs,
    reject_interaction as pc_reject_interaction,
    respond_to_interaction as pc_respond_to_interaction,
    restore_project as pc_restore_project,
    update_project_name as pc_update_project_name,
    get_generation_run_status as pc_get_generation_run_status,
    # ── raw imports: wrapped with telemetry below (state-affecting ops, #219) ──
    cancel_interaction as _cancel_interaction,
    cancel_run as _cancel_run,
    escalate_issue as _escalate_issue,
    mark_comment_routed as _mark_comment_routed,
    post_comment as _post_comment,
    reap_stale_interactions as _reap_stale_interactions,
    reset_agent_session as _reset_agent_session,
    reset_case_agents as _reset_case_agents,
    set_issue_status as _set_issue_status,
    wake_analyst_for_appraiser_facts as _wake_analyst_for_appraiser_facts,
    wake_analyst_for_argument_aggregation as _wake_analyst_for_argument_aggregation,
    wake_analyst_for_protocol_analysis as _wake_analyst_for_protocol_analysis,
    wake_ceo_agent as _wake_ceo,
    wake_ceo_for_action as _wake_ceo_for_action,
    open_ceo_run as _open_ceo_run,
    wake_ceo_for_feedback_fold as _wake_ceo_for_feedback_fold,
    wake_curator_for_final as _wake_curator_for_final,
    wake_for_precedent_extraction as _wake_for_precedent_extraction,
)

# ── telemetry-wrapped platform ops (#219 / docs/spec/X15) ───────────────────
# Every state-affecting platform op the Port exposes emits one structured event
# through web.agent_telemetry, so recovery-loop behaviour (repeated wakeups,
# stranded dispositions) is observable in real time rather than reconstructed
# from the Paperclip DB. The wrappers preserve the public ``pc_*`` names and
# signatures — call sites in app.py are unchanged. Read-only observability ops
# (list_live_runs / get_run_log / get_issue_comments …) are intentionally NOT
# instrumented: they neither wake agents nor change disposition state.
pc_wake_ceo = instrument("agent.wakeup", role="ceo")(_wake_ceo)
pc_wake_ceo_for_action = instrument(
    "agent.wakeup", role="ceo", keys=("case_number", "company_id", "action"),
)(_wake_ceo_for_action)
pc_open_ceo_run = instrument(
    "agent.wakeup", role="ceo", keys=("case_number", "company_id"),
)(_open_ceo_run)
pc_wake_ceo_for_feedback_fold = instrument(
    "agent.wakeup", role="ceo", keys=("feedback_id", "category", "block_id"),
)(_wake_ceo_for_feedback_fold)
pc_wake_curator_for_final = instrument(
    "agent.wakeup", role="curator", keys=("case_number", "company_id", "task"),
)(_wake_curator_for_final)
pc_wake_for_precedent_extraction = instrument(
    "agent.wakeup", role="ceo", keys=("case_law_id", "citation", "practice_area"),
)(_wake_for_precedent_extraction)
pc_wake_analyst_for_appraiser_facts = instrument(
    "agent.wakeup", role="analyst",
)(_wake_analyst_for_appraiser_facts)
pc_wake_analyst_for_argument_aggregation = instrument(
    "agent.wakeup", role="analyst",
)(_wake_analyst_for_argument_aggregation)
pc_wake_analyst_for_protocol_analysis = instrument(
    "agent.wakeup", role="analyst", keys=("case_number", "company_id", "document_id"),
)(_wake_analyst_for_protocol_analysis)
pc_post_comment = instrument(
    "agent.comment", keys=("issue_id", "company_id"),
)(_post_comment)
pc_mark_comment_routed = instrument(
    "agent.comment", keys=("issue_id", "comment_id"),
)(_mark_comment_routed)
pc_cancel_interaction = instrument(
    "interaction.cancelled", keys=("issue_id", "interaction_id"),
)(_cancel_interaction)
# First-class escalation-to-chair (#218): the loop-safe alternative to leaving an
# issue agent-owned+blocked. Emits a severity-tagged event so escalations are
# countable per case in the same stream as the wakeups they replace.
pc_escalate_issue = instrument(
    "agent.escalated", keys=("issue_id", "severity", "company_id", "reason"),
)(_escalate_issue)
# Manual chair close of a board issue (done/cancelled) — the loop-safe primitive
# behind the agents-board "סמן כהושלם / בטל" actions. Countable per case in the
# same telemetry stream as the escalations/wakeups it sits beside.
pc_set_issue_status = instrument(
    "issue.status_set", keys=("issue_id", "status", "company_id"),
)(_set_issue_status)
pc_reap_stale_interactions = instrument(
    "interaction.reaped", result_keys=("cancelled",),
)(_reap_stale_interactions)
pc_cancel_run = instrument("run.cancelled", keys=("run_id",))(_cancel_run)
pc_reset_agent_session = instrument(
    "agent.session_reset", keys=("agent_id",),
)(_reset_agent_session)
pc_reset_case_agents = instrument(
    "agent.session_reset", keys=("case_number",),
)(_reset_case_agents)

# ── domain-named lifecycle aliases (preferred for new call sites) ───────────
archive_case_project = pc_archive_project
restore_case_project = pc_restore_project
create_case_project = pc_create_project
rename_case_project = pc_update_project_name
notify_case_status = emit_case_status_webhook

__all__ = [
    # platform infrastructure
    "PAPERCLIP_COMPANIES",
    "pc_request",
    "require_paperclip_db_url",
    "get_project_url",
    # lifecycle — domain names (preferred) + legacy aliases
    "archive_case_project",
    "restore_case_project",
    "create_case_project",
    "rename_case_project",
    "notify_case_status",
    "emit_case_status_webhook",
    "emit_export_complete_webhook",
    "emit_missing_precedent_webhook",
    "pc_archive_project",
    "pc_restore_project",
    "pc_create_project",
    "pc_update_project_name",
    # issues / workflow
    "pc_create_workflow_issue",
    "pc_get_case_issues",
    "pc_pick_default_comment_target",
    # agents / wakeups
    "pc_get_agents_for_case",
    "pc_get_agents",
    "pc_wake_ceo",
    "pc_wake_ceo_for_action",
    "pc_open_ceo_run",
    "pc_wake_ceo_for_feedback_fold",
    "pc_wake_curator_for_final",
    "pc_wake_for_precedent_extraction",
    "pc_wake_analyst_for_appraiser_facts",
    "pc_wake_analyst_for_argument_aggregation",
    "pc_wake_analyst_for_protocol_analysis",
    "pc_get_generation_run_status",
    # comments / interactions
    "pc_post_comment",
    "pc_mark_comment_routed",
    "pc_get_issue_comments",
    "pc_get_issue_interactions",
    "pc_accept_interaction",
    "pc_reject_interaction",
    "pc_respond_to_interaction",
    "pc_cancel_interaction",
    "pc_reap_stale_interactions",
    "pc_escalate_issue",
    "pc_set_issue_status",
    # agent-run observability + control (live view + smart management)
    "pc_get_agent_health",
    "pc_get_recent_escalations",
    "pc_get_predecessor_context",
    "pc_get_predecessor_for_case",
    "pc_list_live_runs",
    "pc_get_run_log",
    "pc_get_run_events",
    "pc_cancel_run",
    "pc_reset_agent_session",
    "pc_reset_case_agents",
]
