"""
delivery_export.py — Firm workflow output → real deliverables pipeline
Vide #6 : convertit les sorties multi-agents en PR GitHub, tickets Jira/Linear, docs

Tools exposed:
  firm_export_github_pr      — crée une PR GitHub (draft, needs-review)
  firm_export_jira_ticket    — crée un ticket Jira
  firm_export_linear_issue   — crée une issue Linear
  firm_export_slack_digest   — poste un digest formaté sur Slack
  firm_export_document       — génère un document Markdown structuré localement
  firm_export_auto           — détecte le format depuis delivery_format et route
"""

from __future__ import annotations

import logging
import os
import re
from datetime import UTC, datetime
from pathlib import Path
from typing import Any

import httpx

logger = logging.getLogger(__name__)

# ── Configuration ────────────────────────────────────────────────────────────

GITHUB_TOKEN: str | None = os.getenv("GITHUB_TOKEN")
JIRA_API_TOKEN: str | None = os.getenv("JIRA_API_TOKEN")
JIRA_BASE_URL: str | None = os.getenv("JIRA_BASE_URL")          # https://org.atlassian.net
JIRA_USER_EMAIL: str | None = os.getenv("JIRA_USER_EMAIL")
LINEAR_API_KEY: str | None = os.getenv("LINEAR_API_KEY")
SLACK_WEBHOOK_URL: str | None = os.getenv("SLACK_WEBHOOK_URL")

OUTPUT_DIR: str = os.getenv("FIRM_EXPORT_OUTPUT_DIR", os.path.expanduser("~/.firm/exports"))
HTTP_TIMEOUT: float = float(os.getenv("EXPORT_HTTP_TIMEOUT_SECONDS", "20"))
MAX_BODY_CHARS: int = int(os.getenv("EXPORT_MAX_BODY_CHARS", str(64_000)))

# ── Helpers ──────────────────────────────────────────────────────────────────

def _kebab(text: str) -> str:
    """Convert objective text to a safe kebab-case branch/slug."""
    s = text.lower().strip()
    s = re.sub(r"[^a-z0-9\s-]", "", s)
    s = re.sub(r"\s+", "-", s)
    s = re.sub(r"-+", "-", s)
    return s[:60].strip("-")


def _truncate(text: str, limit: int = MAX_BODY_CHARS) -> str:
    if len(text) <= limit:
        return text
    return text[: limit - 100] + "\n\n---\n_[truncated — full output in memory:delivery/latest]_"


# Use shared mask_secret from config_helpers (I26 — DRY)
from src.config_helpers import mask_secret as _mask_secret  # noqa: E402


def _ai_footer(objective: str, departments: list[str]) -> str:
    ts = datetime.now(UTC).strftime("%Y-%m-%d %H:%M UTC")
    depts = ", ".join(departments) if departments else "all"
    return (
        f"\n\n---\n"
        f"_🤖 AI-generated by firm-orchestration · {ts}_  \n"
        f"_Objective: {objective[:120]}_  \n"
        f"_Departments: {depts}_  \n"
        f"_⚠️ Human review required before merge/action_"
    )


# ── Tool: firm_export_github_pr ──────────────────────────────────────────────

async def firm_export_github_pr(
    repo: str,
    content: str,
    objective: str,
    departments: list[str] | None = None,
    base: str = "main",
    branch: str | None = None,
    title: str | None = None,
    reviewers: list[str] | None = None,
    labels: list[str] | None = None,
    draft: bool = True,
) -> dict[str, Any]:
    """
    Create a GitHub Pull Request from firm workflow output.

    Always creates as DRAFT with label ``needs-review`` and ``ai-generated``.
    Never auto-merges.

    Args:
        repo: "owner/repo" format.
        content: The merged workflow output (Markdown body).
        objective: Original firm objective (used for branch name + PR title).
        departments: List of departments involved.
        base: Target base branch (default: "main").
        branch: Override the auto-generated branch name.
        title: Override the auto-generated PR title.
        reviewers: GitHub usernames to request review from.
        labels: Additional labels (needs-review and ai-generated always added).
        draft: Create as draft PR (default: True — always recommended).

    Returns:
        dict with keys: ok, pr_url, pr_number, branch, draft.
    """
    if not GITHUB_TOKEN:
        return {"ok": False, "error": "GITHUB_TOKEN not set"}

    slug = _kebab(objective)
    actual_branch = branch or f"ai/{slug}"
    actual_title = title or f"feat: {objective[:72]} (AI-generated)"
    actual_labels = list(set(["ai-generated", "needs-review"] + (labels or [])))
    depts = departments or []

    body = _truncate(content) + _ai_footer(objective, depts)

    headers = {
        "Authorization": f"Bearer {GITHUB_TOKEN}",
        "Accept": "application/vnd.github.v3+json",
        "X-GitHub-Api-Version": "2022-11-28",
    }

    async with httpx.AsyncClient(timeout=HTTP_TIMEOUT) as client:
        # 1. Get default branch SHA
        try:
            ref_resp = await client.get(
                f"https://api.github.com/repos/{repo}/git/ref/heads/{base}",
                headers=headers,
            )
            ref_resp.raise_for_status()
            sha = ref_resp.json()["object"]["sha"]
        except httpx.HTTPStatusError as exc:
            return {"ok": False, "error": f"Cannot get ref heads/{base}: {exc.response.status_code}"}

        # 2. Create branch
        try:
            branch_resp = await client.post(
                f"https://api.github.com/repos/{repo}/git/refs",
                headers=headers,
                json={"ref": f"refs/heads/{actual_branch}", "sha": sha},
            )
            if branch_resp.status_code not in (201, 422):  # 422 = already exists
                branch_resp.raise_for_status()
        except httpx.HTTPStatusError as exc:
            return {"ok": False, "error": f"Cannot create branch: {exc.response.status_code}"}

        # 3. Create a commit with the content as a file
        file_path = f"ai-deliverables/{slug}/{datetime.now(UTC).strftime('%Y%m%d-%H%M')}.md"
        content_b64 = __import__("base64").b64encode(body.encode()).decode()
        commit_resp = await client.put(
            f"https://api.github.com/repos/{repo}/contents/{file_path}",
            headers=headers,
            json={
                "message": f"docs: AI delivery — {objective[:72]}",
                "content": content_b64,
                "branch": actual_branch,
            },
        )
        if commit_resp.status_code not in (200, 201):
            return {"ok": False, "error": f"Cannot commit file: {commit_resp.status_code} {commit_resp.text[:200]}"}

        # 4. Create PR
        pr_payload: dict[str, Any] = {
            "title": actual_title,
            "body": body,
            "head": actual_branch,
            "base": base,
            "draft": draft,
        }
        pr_resp = await client.post(
            f"https://api.github.com/repos/{repo}/pulls",
            headers=headers,
            json=pr_payload,
        )
        if pr_resp.status_code != 201:
            return {"ok": False, "error": f"Cannot create PR: {pr_resp.status_code} {pr_resp.text[:200]}"}

        pr_data = pr_resp.json()
        pr_number = pr_data["number"]
        pr_url = pr_data["html_url"]

        # 5. Add labels
        if actual_labels:
            await client.post(
                f"https://api.github.com/repos/{repo}/issues/{pr_number}/labels",
                headers=headers,
                json={"labels": actual_labels},
            )

        # 6. Request reviewers (optional)
        if reviewers:
            users = [r.lstrip("@") for r in reviewers]
            await client.post(
                f"https://api.github.com/repos/{repo}/pulls/{pr_number}/requested_reviewers",
                headers=headers,
                json={"reviewers": users},
            )

    return {
        "ok": True,
        "pr_url": pr_url,
        "pr_number": pr_number,
        "branch": actual_branch,
        "file_committed": file_path,
        "draft": draft,
        "labels": actual_labels,
        "reviewers": reviewers or [],
    }


# ── Tool: firm_export_jira_ticket ────────────────────────────────────────────

async def firm_export_jira_ticket(
    project_key: str,
    content: str,
    objective: str,
    departments: list[str] | None = None,
    issue_type: str = "Story",
    priority: str = "Medium",
    labels: list[str] | None = None,
    components: list[str] | None = None,
    assignee_account_id: str | None = None,
) -> dict[str, Any]:
    """
    Create a Jira issue from firm workflow output.

    Args:
        project_key: Jira project key (e.g. "ENG", "OPS").
        content: Merged workflow output (goes to description field).
        objective: Original firm objective (used for issue summary).
        departments: Departments involved.
        issue_type: Jira issue type (default: "Story").
        priority: Issue priority (default: "Medium").
        labels: Additional Jira labels.
        components: Jira components to assign.
        assignee_account_id: Jira account ID of assignee.

    Returns:
        dict with keys: ok, issue_key, issue_url.
    """
    if not JIRA_API_TOKEN or not JIRA_BASE_URL or not JIRA_USER_EMAIL:
        return {"ok": False, "error": "JIRA_API_TOKEN, JIRA_BASE_URL, JIRA_USER_EMAIL must all be set"}

    depts = departments or []
    summary = objective[:254]
    description_text = _truncate(content) + _ai_footer(objective, depts)
    all_labels = list(set(["ai-generated", "needs-review"] + (labels or [])))

    # Jira Cloud uses Atlassian Document Format (ADF) for description
    adf_description = {
        "version": 1,
        "type": "doc",
        "content": [
            {
                "type": "paragraph",
                "content": [{"type": "text", "text": description_text}],
            }
        ],
    }

    fields: dict[str, Any] = {
        "project": {"key": project_key},
        "summary": summary,
        "description": adf_description,
        "issuetype": {"name": issue_type},
        "priority": {"name": priority},
        "labels": all_labels,
    }
    if components:
        fields["components"] = [{"name": c} for c in components]
    if assignee_account_id:
        fields["assignee"] = {"accountId": assignee_account_id}

    auth = httpx.BasicAuth(JIRA_USER_EMAIL, JIRA_API_TOKEN)
    base = JIRA_BASE_URL.rstrip("/")

    async with httpx.AsyncClient(timeout=HTTP_TIMEOUT, auth=auth) as client:
        resp = await client.post(
            f"{base}/rest/api/3/issue",
            json={"fields": fields},
            headers={"Accept": "application/json", "Content-Type": "application/json"},
        )
        if resp.status_code != 201:
            return {"ok": False, "error": f"Jira API error {resp.status_code}: {resp.text[:300]}"}
        data = resp.json()

    issue_key = data["key"]
    return {
        "ok": True,
        "issue_key": issue_key,
        "issue_url": f"{base}/browse/{issue_key}",
        "summary": summary,
        "labels": all_labels,
    }


# ── Tool: firm_export_linear_issue ───────────────────────────────────────────

async def firm_export_linear_issue(
    team_id: str,
    content: str,
    objective: str,
    departments: list[str] | None = None,
    priority: int = 2,
    state_name: str = "Todo",
    label_names: list[str] | None = None,
    assignee_id: str | None = None,
) -> dict[str, Any]:
    """
    Create a Linear issue from firm workflow output.

    Args:
        team_id: Linear team ID (UUID).
        content: Merged workflow output (issue description).
        objective: Original firm objective (issue title).
        departments: Departments involved.
        priority: 0=No priority, 1=Urgent, 2=High(default), 3=Medium, 4=Low.
        state_name: Workflow state name (e.g. "Todo", "In Progress").
        label_names: Label names to apply.
        assignee_id: Linear user ID to assign.

    Returns:
        dict with keys: ok, issue_id, issue_url.
    """
    if not LINEAR_API_KEY:
        return {"ok": False, "error": "LINEAR_API_KEY not set"}

    depts = departments or []
    title = objective[:250]
    description = _truncate(content) + _ai_footer(objective, depts)

    gql = """
    mutation CreateIssue($input: IssueCreateInput!) {
      issueCreate(input: $input) {
        success
        issue {
          id
          identifier
          url
        }
      }
    }
    """

    variables: dict[str, Any] = {
        "input": {
            "teamId": team_id,
            "title": title,
            "description": description,
            "priority": priority,
        }
    }
    if assignee_id:
        variables["input"]["assigneeId"] = assignee_id

    headers = {
        "Authorization": LINEAR_API_KEY,
        "Content-Type": "application/json",
    }

    async with httpx.AsyncClient(timeout=HTTP_TIMEOUT) as client:
        resp = await client.post(
            "https://api.linear.app/graphql",
            json={"query": gql, "variables": variables},
            headers=headers,
        )
        resp.raise_for_status()
        body = resp.json()

    if body.get("errors"):
        return {"ok": False, "error": str(body["errors"])}

    issue_data = body["data"]["issueCreate"]["issue"]
    return {
        "ok": True,
        "issue_id": issue_data["id"],
        "issue_identifier": issue_data["identifier"],
        "issue_url": issue_data["url"],
        "title": title,
    }


# ── Tool: firm_export_slack_digest ───────────────────────────────────────────

async def firm_export_slack_digest(
    content: str,
    objective: str,
    departments: list[str] | None = None,
    channel: str | None = None,
    mention_users: list[str] | None = None,
) -> dict[str, Any]:
    """
    Post a formatted digest of the firm workflow to Slack.

    Uses Block Kit for rich formatting.

    Args:
        content: Merged workflow output.
        objective: Original objective.
        departments: Departments involved.
        channel: Override channel (uses webhook default if None).
        mention_users: Slack user IDs to mention.

    Returns:
        dict with keys: ok, webhook_used.
    """
    if not SLACK_WEBHOOK_URL:
        return {"ok": False, "error": "SLACK_WEBHOOK_URL not set"}

    depts = departments or []
    mentions = " ".join(f"<@{uid}>" for uid in (mention_users or []))
    ts = datetime.now(UTC).strftime("%Y-%m-%d %H:%M UTC")

    preview = content[:500] + ("..." if len(content) > 500 else "")

    blocks = [
        {
            "type": "header",
            "text": {"type": "plain_text", "text": f"🤖 AI Delivery: {objective[:72]}"},
        },
        {"type": "divider"},
        {
            "type": "section",
            "fields": [
                {"type": "mrkdwn", "text": f"*Departments:*\n{', '.join(depts) or 'all'}"},
                {"type": "mrkdwn", "text": f"*Generated:*\n{ts}"},
            ],
        },
        {
            "type": "section",
            "text": {"type": "mrkdwn", "text": f"*Summary:*\n```{preview}```"},
        },
        {
            "type": "context",
            "elements": [
                {"type": "mrkdwn", "text": "⚠️ Human review required before action"},
            ],
        },
    ]

    if mentions:
        blocks.append({
            "type": "section",
            "text": {"type": "mrkdwn", "text": f"*For review:* {mentions}"},
        })

    payload: dict[str, Any] = {"blocks": blocks}
    if channel:
        payload["channel"] = channel

    async with httpx.AsyncClient(timeout=HTTP_TIMEOUT) as client:
        resp = await client.post(SLACK_WEBHOOK_URL, json=payload)
        if resp.status_code != 200:
            return {"ok": False, "error": f"Slack error {resp.status_code}: {resp.text[:200]}"}

    return {"ok": True, "webhook_used": _mask_secret(SLACK_WEBHOOK_URL, 8)}


# ── Tool: firm_export_document ───────────────────────────────────────────────

async def firm_export_document(
    content: str,
    objective: str,
    departments: list[str] | None = None,
    format: str = "markdown_report",
    output_path: str | None = None,
) -> dict[str, Any]:
    """
    Write the firm workflow output to a local structured document file.

    Args:
        content: Merged workflow output.
        objective: Original objective.
        departments: Departments involved.
        format: Document format (markdown_report | structured_document | project_brief).
        output_path: Override default output path.

    Returns:
        dict with keys: ok, file_path, bytes_written.
    """
    depts = departments or []
    ts_file = datetime.now(UTC).strftime("%Y%m%d-%H%M%S")
    slug = _kebab(objective)
    filename = f"{ts_file}-{slug}.md"

    if output_path:
        file_path = Path(output_path)
    else:
        file_path = Path(OUTPUT_DIR) / format / filename

    file_path.parent.mkdir(parents=True, exist_ok=True)

    # Build header based on format
    if format == "project_brief":
        header = (
            f"---\n"
            f"title: \"{objective}\"\n"
            f"date: {datetime.now(UTC).strftime('%Y-%m-%d')}\n"
            f"departments: [{', '.join(depts)}]\n"
            f"status: draft\n"
            f"generated_by: firm-orchestration\n"
            f"---\n\n"
            f"# Project Brief: {objective}\n\n"
            f"**Date:** {datetime.now(UTC).strftime('%B %d, %Y')}  \n"
            f"**Departments:** {', '.join(depts) or 'all'}  \n"
            f"**Status:** 🔴 Draft — Pending human review\n\n"
            f"---\n\n"
        )
    elif format == "structured_document":
        header = (
            f"---\n"
            f"title: \"{objective}\"\n"
            f"date: {datetime.now(UTC).strftime('%Y-%m-%d')}\n"
            f"type: structured_document\n"
            f"generated_by: firm-orchestration\n"
            f"---\n\n"
            f"# {objective}\n\n"
        )
    else:  # markdown_report
        header = (
            f"# AI Delivery Report\n\n"
            f"**Objective:** {objective}  \n"
            f"**Date:** {datetime.now(UTC).strftime('%Y-%m-%d %H:%M UTC')}  \n"
            f"**Departments:** {', '.join(depts) or 'all'}  \n\n"
            f"---\n\n"
        )

    footer = _ai_footer(objective, depts)
    full_content = header + content + footer

    file_path.write_text(full_content, encoding="utf-8")
    bytes_written = len(full_content.encode())

    return {
        "ok": True,
        "file_path": str(file_path),
        "bytes_written": bytes_written,
        "format": format,
    }


# ── Tool: firm_export_auto ────────────────────────────────────────────────────

async def firm_export_auto(
    delivery_format: str,
    content: str,
    objective: str,
    departments: list[str] | None = None,
    # GitHub params
    github_repo: str | None = None,
    github_reviewers: list[str] | None = None,
    github_base: str = "main",
    # Jira params
    jira_project_key: str | None = None,
    # Linear params
    linear_team_id: str | None = None,
    # Slack params
    slack_mention_users: list[str] | None = None,
) -> dict[str, Any]:
    """
    Auto-route firm workflow output to the correct export target based on delivery_format.

    Acts as the single entrypoint — the firm-orchestration skill calls this
    automatically at the end of each run when a delivery_format is set.

    Args:
        delivery_format: One of github_pr | jira_ticket | linear_issue |
                         slack_digest | markdown_report | structured_document | project_brief.
        content: Merged workflow output.
        objective: Original firm objective.
        departments: Departments involved.
        github_repo: Required for github_pr format.
        github_reviewers: Optional reviewers list.
        github_base: Base branch (default: main).
        jira_project_key: Required for jira_ticket format.
        linear_team_id: Required for linear_issue format.
        slack_mention_users: Optional Slack user IDs to mention.

    Returns:
        dict with keys: ok, format, result.
    """
    depts = departments or []

    if delivery_format == "github_pr":
        if not github_repo:
            return {"ok": False, "error": "github_repo required for github_pr format"}
        result = await firm_export_github_pr(
            repo=github_repo,
            content=content,
            objective=objective,
            departments=depts,
            base=github_base,
            reviewers=github_reviewers,
        )

    elif delivery_format == "jira_ticket":
        if not jira_project_key:
            return {"ok": False, "error": "jira_project_key required for jira_ticket format"}
        result = await firm_export_jira_ticket(
            project_key=jira_project_key,
            content=content,
            objective=objective,
            departments=depts,
        )

    elif delivery_format == "linear_issue":
        if not linear_team_id:
            return {"ok": False, "error": "linear_team_id required for linear_issue format"}
        result = await firm_export_linear_issue(
            team_id=linear_team_id,
            content=content,
            objective=objective,
            departments=depts,
        )

    elif delivery_format == "slack_digest":
        result = await firm_export_slack_digest(
            content=content,
            objective=objective,
            departments=depts,
            mention_users=slack_mention_users,
        )

    else:
        # markdown_report | structured_document | project_brief → local file
        result = await firm_export_document(
            content=content,
            objective=objective,
            departments=depts,
            format=delivery_format,
        )

    return {"ok": result.get("ok", False), "format": delivery_format, "result": result}


# ── MCP tool descriptors ─────────────────────────────────────────────────────

TOOLS: list[dict[str, Any]] = [
    {
        "name": "firm_export_auto",
        "title": "Auto-Route Export",
        "description": (
            "Auto-route firm workflow output to the correct export target "
            "(GitHub PR, Jira, Linear, Slack, or local document) based on delivery_format. "
            "Main entrypoint for firm-delivery-export."
        ),
        "inputSchema": {
            "type": "object",
            "properties": {
                "delivery_format": {
                    "type": "string",
                    "enum": ["github_pr", "jira_ticket", "linear_issue", "slack_digest",
                             "markdown_report", "structured_document", "project_brief"],
                },
                "content": {"type": "string"},
                "objective": {"type": "string"},
                "departments": {"type": "array", "items": {"type": "string"}},
                "github_repo": {"type": "string", "description": "owner/repo (for github_pr)"},
                "github_reviewers": {"type": "array", "items": {"type": "string"}},
                "github_base": {"type": "string", "default": "main"},
                "jira_project_key": {"type": "string"},
                "linear_team_id": {"type": "string"},
                "slack_mention_users": {"type": "array", "items": {"type": "string"}},
            },
            "required": ["delivery_format", "content", "objective"],
        },
        "handler": firm_export_auto,
        "annotations": {"readOnlyHint": False, "destructiveHint": False, "idempotentHint": False, "openWorldHint": True},
        "outputSchema": {"type": "object", "properties": {"ok": {"type": "boolean"}}, "required": ["ok"]},
        "category": "export",
    },
    {
        "name": "firm_export_github_pr",
        "title": "Export to GitHub PR",
        "description": "Create a GitHub draft PR from firm workflow output. Always adds needs-review + ai-generated labels. Never auto-merges.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "repo": {"type": "string"},
                "content": {"type": "string"},
                "objective": {"type": "string"},
                "departments": {"type": "array", "items": {"type": "string"}},
                "base": {"type": "string", "default": "main"},
                "branch": {"type": "string"},
                "title": {"type": "string"},
                "reviewers": {"type": "array", "items": {"type": "string"}},
                "labels": {"type": "array", "items": {"type": "string"}},
                "draft": {"type": "boolean", "default": True},
            },
            "required": ["repo", "content", "objective"],
        },
        "handler": firm_export_github_pr,
        "category": "export",
        "annotations": {"readOnlyHint": False, "destructiveHint": False, "idempotentHint": False, "openWorldHint": True},
        "outputSchema": {"type": "object", "properties": {"ok": {"type": "boolean"}}, "required": ["ok"]},
    },
    {
        "name": "firm_export_jira_ticket",
        "title": "Export to Jira Ticket",
        "description": "Create a Jira issue from firm workflow output.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "project_key": {"type": "string"},
                "content": {"type": "string"},
                "objective": {"type": "string"},
                "departments": {"type": "array", "items": {"type": "string"}},
                "issue_type": {"type": "string", "default": "Story"},
                "priority": {"type": "string", "default": "Medium"},
                "labels": {"type": "array", "items": {"type": "string"}},
                "components": {"type": "array", "items": {"type": "string"}},
            },
            "required": ["project_key", "content", "objective"],
        },
        "handler": firm_export_jira_ticket,
        "category": "export",
        "annotations": {"readOnlyHint": False, "destructiveHint": False, "idempotentHint": False, "openWorldHint": True},
        "outputSchema": {"type": "object", "properties": {"ok": {"type": "boolean"}}, "required": ["ok"]},
    },
    {
        "name": "firm_export_linear_issue",
        "title": "Export to Linear Issue",
        "description": "Create a Linear issue from firm workflow output.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "team_id": {"type": "string"},
                "content": {"type": "string"},
                "objective": {"type": "string"},
                "departments": {"type": "array", "items": {"type": "string"}},
                "priority": {"type": "integer", "default": 2},
            },
            "required": ["team_id", "content", "objective"],
        },
        "handler": firm_export_linear_issue,
        "category": "export",
        "annotations": {"readOnlyHint": False, "destructiveHint": False, "idempotentHint": False, "openWorldHint": True},
        "outputSchema": {"type": "object", "properties": {"ok": {"type": "boolean"}}, "required": ["ok"]},
    },
    {
        "name": "firm_export_slack_digest",
        "title": "Export to Slack Digest",
        "description": "Post a formatted firm delivery digest to Slack via webhook.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "content": {"type": "string"},
                "objective": {"type": "string"},
                "departments": {"type": "array", "items": {"type": "string"}},
                "channel": {"type": "string"},
                "mention_users": {"type": "array", "items": {"type": "string"}},
            },
            "required": ["content", "objective"],
        },
        "handler": firm_export_slack_digest,
        "category": "export",
        "annotations": {"readOnlyHint": False, "destructiveHint": False, "idempotentHint": False, "openWorldHint": True},
        "outputSchema": {"type": "object", "properties": {"ok": {"type": "boolean"}}, "required": ["ok"]},
    },
    {
        "name": "firm_export_document",
        "title": "Export to Document",
        "description": "Write firm workflow output to a local Markdown document.",
        "inputSchema": {
            "type": "object",
            "properties": {
                "content": {"type": "string"},
                "objective": {"type": "string"},
                "departments": {"type": "array", "items": {"type": "string"}},
                "format": {
                    "type": "string",
                    "enum": ["markdown_report", "structured_document", "project_brief"],
                    "default": "markdown_report",
                },
                "output_path": {"type": "string"},
            },
            "required": ["content", "objective"],
        },
        "handler": firm_export_document,
        "category": "export",
        "annotations": {"readOnlyHint": False, "destructiveHint": False, "idempotentHint": True, "openWorldHint": False},
        "outputSchema": {"type": "object", "properties": {"ok": {"type": "boolean"}}, "required": ["ok"]},
    },
]
