/**
 * outbound.ts — initiate an outbound SIP call via jambonz.
 * Mirrors the shape of twilio-phone.service#initiateOutboundCall but uses
 * the jambonz REST API. Gated by FEATURE_SIP_ENABLED via the route layer.
 */
import { db } from '@server/db/drizzle';
import { sql } from 'drizzle-orm';
import { ValidationError } from '@server/errors';
import { isSipFeatureEnabled } from '@/shared/config/sip-feature';
import { isRestaurantSipEnabled } from '@server/middleware/withSipFeature';
import { getJambonzCreds, createCall } from '@server/services/telephone/jambonz/jambonz.service';

export async function initiateSipOutboundCall(
  restaurantId: string,
  to: string,
  fromNumberId: string
): Promise<{ callSid: string; sessionId: string }> {
  if (!isSipFeatureEnabled() || !(await isRestaurantSipEnabled(restaurantId))) {
    throw new ValidationError('SIP add-on is not enabled');
  }

  /* raw: SELECT id, number, assigned_agent_id, sip_config FROM phone_numbers WHERE id = $1 AND restaurant_id = $2 AND provider = 'sip' AND is_active = true */
  const { rows: phoneRows } = await db.execute(sql`SELECT id, number, assigned_agent_id, sip_config FROM phone_numbers WHERE id = ${fromNumberId} AND restaurant_id = ${restaurantId} AND provider = 'sip' AND is_active = true`);
  const phone = phoneRows[0] as { id: string; number: string; assigned_agent_id: string | null; sip_config: Record<string, unknown> | string } | undefined;
  if (!phone) throw new ValidationError('SIP phone number not found or inactive');

  const creds = await getJambonzCreds(restaurantId);
  if (!creds) throw new ValidationError('jambonz credentials not configured');

  // Same fallback chain as sip.service provisioning so outbound works in
  // any environment where inbound provisioning works.
  const baseUrl = (
    process.env.WEBHOOK_BASE_URL
    || process.env.NEXT_PUBLIC_APP_URL
    || (process.env.REPLIT_DEV_DOMAIN ? `https://${process.env.REPLIT_DEV_DOMAIN}` : '')
  ).replace(/\/+$/, '');
  if (!baseUrl) throw new ValidationError('WEBHOOK_BASE_URL is not configured');

  /* raw: INSERT INTO sip_call_sessions (...) VALUES (...) RETURNING * */
  const { rows: sessionRows } = await db.execute(sql`
    INSERT INTO sip_call_sessions (restaurant_id, phone_number_id, agent_id, caller_number, callee_number, direction, status, transcript)
    VALUES (${restaurantId}, ${phone.id}, ${phone.assigned_agent_id || null}, ${phone.number}, ${to}, 'outbound', 'ringing', '[]'::jsonb)
    RETURNING *
  `);
  const session = sessionRows[0] as { id: string };

  const call = await createCall(creds, {
    from: phone.number,
    to: to.startsWith('sip:') ? { type: 'sip', sipUri: to } : { type: 'phone', number: to },
    call_hook: `${baseUrl}/api/webhooks/sip/voice?sessionId=${session.id}`,
    call_status_hook: `${baseUrl}/api/webhooks/sip/status`,
  });

  if (!call) {
    /* raw: DELETE FROM sip_call_sessions WHERE id = $1 */
    await db.execute(sql`DELETE FROM sip_call_sessions WHERE id = ${session.id}`);
    throw new ValidationError('Failed to initiate SIP call via jambonz');
  }

  /* raw: UPDATE sip_call_sessions SET sip_call_id = $1, status = 'active' WHERE id = $2 */
  await db.execute(sql`UPDATE sip_call_sessions SET sip_call_id = ${call.sid}, status = 'active' WHERE id = ${session.id}`);

  return { callSid: call.sid, sessionId: session.id };
}
