import { createHash } from 'node:crypto'
import { outcomeValueUsd } from '../registry.ts'
import type { ActionForDetection, OutcomeEvent } from './types.ts'

/**
 * Outcome detector for `mcp_call` rows.
 *
 * Many real personal-assistant outcomes don't go through the agent's
 * model_call (no inline tool_use block) — they go through a stdio
 * MCP server. Gmail, Google Calendar, Slack, Notion, Linear, GitHub
 * MCP, custom domain MCPs all emit `tools/call` over JSON-RPC. Those
 * frames are captured by `thomas-tap` and end up here as mcp_call
 * rows with direction='request' or 'response'.
 *
 * We fire outcomes from the request side (where the method + params
 * live), and the calculator's verification pass marks them verified
 * iff the paired response (matched by jsonrpcId) had no error.
 */
export function detectMcpFrame(action: ActionForDetection): OutcomeEvent[] {
  if (action.kind !== 'mcp_call') return []
  const p = action.payload
  if (!p || typeof p !== 'object') return []
  if (p.direction !== 'request') return []

  // Only tools/call frames carry an outcome; tools/list, ping, init etc
  // are infrastructure.
  if (p.method !== 'tools/call') return []
  const params = p.params
  if (!params || typeof params !== 'object') return []
  const name: string = typeof params.name === 'string' ? params.name : ''
  if (!name) return []
  const args = (params.arguments && typeof params.arguments === 'object'
    ? params.arguments
    : {}) as Record<string, unknown>
  const server: string = typeof p.server === 'string' ? p.server : ''

  const make = (kind: string, fingerprintSource: string): OutcomeEvent => ({
    kind,
    valueUsd: outcomeValueUsd(kind),
    fingerprint: hash(`mcp:${server}:${kind}:${fingerprintSource}`),
    detectedAt: action.ts,
    actionId: action.id,
    // why: store the request's jsonrpcId+server in toolUseId so the verification
    // pass can match against the paired response. (Format chosen to be unique
    // and never collide with real tool_use IDs which are opaque strings.)
    toolUseId: typeof p.jsonrpcId === 'number' || typeof p.jsonrpcId === 'string'
      ? `mcp:${server}:${p.jsonrpcId}`
      : undefined,
  })

  // ── Email ──────────────────────────────────────────────────────
  if (/^(?:gmail__|google__|email__)?(?:send_message|send_email|send_mail|sendEmail|drafts__send)$/i.test(name)) {
    const to = stringField(args, 'to', 'recipient', 'recipients')
    const subj = stringField(args, 'subject', 'title')
    return [make('email_sent', `${to}|${subj.slice(0, 40)}`)]
  }
  if (/^(?:gmail__|google__|email__)?(?:create_draft|draft|drafts__create|compose)$/i.test(name)) {
    return [make('email_drafted', stringField(args, 'subject', 'title'))]
  }

  // ── Calendar ───────────────────────────────────────────────────
  if (
    /^(?:gcal__|gcalendar__|calendar__|google_calendar__|googleCalendar__)?(?:create_event|events__insert|insert_event|schedule_event|book_meeting)$/i.test(
      name,
    )
  ) {
    const title = stringField(args, 'summary', 'title', 'name')
    const when = stringField(args, 'start', 'startTime', 'start_time')
    return [make('calendar_event_confirmed', `${title}|${when}`)]
  }

  // ── Booking / orders / shopping ────────────────────────────────
  if (/^(?:book_|booking_|reserve_|reservation_).+|.*_booking$|.*_reservation$/i.test(name)) {
    return [make('booking_confirmed', stringField(args, 'reference', 'confirmation', 'id'))]
  }
  if (/^(?:order_|place_order|cart__checkout|checkout__create)/i.test(name)) {
    return [make('order_placed', stringField(args, 'order_id', 'reference'))]
  }

  // ── Reminders / todos ──────────────────────────────────────────
  if (/^(?:reminder_|todo_|task_).+|set_reminder|create_reminder|add_todo|add_task/i.test(name)) {
    return [make('reminder_set', stringField(args, 'title', 'text', 'body').slice(0, 60))]
  }

  // ── Messaging (Slack / Discord / Feishu) ───────────────────────
  if (/^(?:slack__|discord__|feishu__).*(?:post_message|chat__post|send_message|webhook__send)|post_message|chat_postMessage/i.test(name)) {
    const channel = stringField(args, 'channel', 'channel_id', 'room')
    return [make('message_posted', `${server}|${channel}`)]
  }

  // ── Issue / ticket trackers ────────────────────────────────────
  if (/^(?:linear__|jira__|github__).*(?:create_issue|issue__create|tickets__create)|create_issue/i.test(name)) {
    const title = stringField(args, 'title', 'summary')
    return [make('ticket_resolved', `${server}|${title.slice(0, 60)}`)]
  }
  if (
    /^(?:linear__|jira__|github__).*(?:close_issue|update_issue.*resolved|comments__create)/i.test(
      name,
    )
  ) {
    return [make('ticket_resolved', stringField(args, 'issue_id', 'issue', 'number'))]
  }

  // ── Web search / synth via MCP ─────────────────────────────────
  if (/^(?:exa__|brave__|web__|google_search__).*(?:search|query)|web_search|brave_search/i.test(name)) {
    return [make('search_synthesized', stringField(args, 'query', 'q', 'search'))]
  }

  // ── Documents (Notion / Google Docs / Drive) ───────────────────
  if (/^(?:notion__|googleDrive__|google_drive__|gdocs__|gdrive__).*(?:create_page|create_doc|files__create|pages__create)|create_page/i.test(name)) {
    return [make('document_written', stringField(args, 'title', 'name'))]
  }

  return []
}

function stringField(obj: Record<string, unknown>, ...keys: string[]): string {
  for (const k of keys) {
    const v = obj[k]
    if (typeof v === 'string') return v
    if (Array.isArray(v) && v.length > 0 && typeof v[0] === 'string') return v[0] as string
  }
  return ''
}

function hash(s: string): string {
  return createHash('sha256').update(s).digest('hex').slice(0, 16)
}
