/**
 * engine/sip/tools.ts — SIP-channel tool list.
 *
 * Reuses every restaurant-domain tool from `engine/twilio/tools.ts`
 * (place_order, book_table, search_knowledge_base, list_menu) but
 * REPLACES `escalate_call` with a SIP-native variant that transfers
 * the call through jambonz REST instead of Twilio.
 *
 * See engine/voice-core.ts for the full SIP file map.
 */
import { tool } from '@openai/agents';
import { db } from '@server/db/drizzle';
import { sql } from 'drizzle-orm';
import { makeRestaurantTools, ToolSessionContext } from '../twilio/tools';
import { transferSipCall } from '@server/services/telephone/sip/sip-transfer.service';

import { childLogger } from '@server/logger';
import { redactPhone } from '@server/logger/redact';
const log = childLogger('engine.sip.tools');

export function makeSipRestaurantTools(ctx: ToolSessionContext) {
  const base = makeRestaurantTools(ctx);
  // Strip the Twilio-bound escalate_call (it imports twilio-phone.service)
  // and replace it with a SIP-native one. Filtering by `name` keeps the
  // list otherwise byte-identical to the Twilio bridge's tool surface.
  const filtered = base.filter(t => (t as { name?: string }).name !== 'escalate_call');

  const escalateCallTool = tool({
    name: 'escalate_call',
    description:
      'Transfer the call to a human staff member when the caller requests it or when you cannot handle their query. Call this immediately when a caller asks to speak to a person.',
    parameters: {
      type: 'object' as const,
      properties: {
        reason: {
          type: 'string',
          description: 'Brief reason for escalation (e.g. "caller requested human", "complaint handling").',
        },
      },
      required: ['reason'] as string[],
      additionalProperties: false as const,
    },
    execute: async (args: unknown) => {
      const { reason } = args as { reason: string };
      try {
        /* raw: SELECT pn.fallback_number FROM sip_call_sessions s JOIN phone_numbers pn ON pn.id = s.phone_number_id WHERE s.id = $1 AND pn.fallback_number IS NOT NULL LIMIT 1 */
        const { rows } = await db.execute(sql`
          SELECT pn.fallback_number FROM sip_call_sessions s
          JOIN phone_numbers pn ON pn.id = s.phone_number_id
          WHERE s.id = ${ctx.session_id} AND pn.fallback_number IS NOT NULL
          LIMIT 1
        `);
        const fallbackNumber = rows[0]?.fallback_number as string | undefined;
        if (!fallbackNumber) {
          log.info({ reason }, 'escalation requested but no fallback number configured');
          return 'No transfer number is configured. Please tell the caller: "I\'ll have one of our staff members call you back shortly. Thank you for your patience."';
        }
        try {
          log.info({ sessionId: ctx.session_id, fallback: redactPhone(fallbackNumber), reason }, 'escalating SIP call');
          await transferSipCall(ctx.session_id, ctx.restaurant_id, fallbackNumber);
          return 'Please hold for a moment while I connect you to a staff member.';
        } catch (err) {
          log.error({ err, sessionId: ctx.session_id }, 'SIP transfer failed');
          return 'I apologise — I was unable to connect the transfer. Please let the caller know a staff member will call them back shortly.';
        }
      } catch (err) {
        log.error({ err, sessionId: ctx.session_id }, 'SIP escalate_call error');
        return 'Please tell the caller a staff member will call them back shortly.';
      }
    },
  });

  // Mirror the capability gating from makeRestaurantTools: only push the
  // SIP escalate tool when the agent's escalation capability is on.
  const caps = ctx.capabilities;
  const hasCaps = !!caps && typeof caps === 'object';
  const escalationOn = hasCaps ? caps.escalation !== false : true;

  return escalationOn ? [...filtered, escalateCallTool] : filtered;
}
