/**
 * Natural language → TwiML builder.
 * Generates TwiML XML from simple action descriptions.
 */

export interface TwiMLAction {
  type: 'say' | 'play' | 'gather' | 'dial' | 'record' | 'hangup' | 'redirect' | 'pause' | 'enqueue';
  message?: string;
  voice?: string;
  url?: string;
  number?: string;
  timeout?: number;
  numDigits?: number;
  action?: string;
  method?: string;
  children?: TwiMLAction[];
  queue?: string;
}

export function buildTwiML(actions: TwiMLAction[]): string {
  let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<Response>\n';
  xml += actions.map(a => actionToXml(a, 2)).join('\n');
  xml += '\n</Response>';
  return xml;
}

function actionToXml(action: TwiMLAction, indent: number): string {
  const pad = ' '.repeat(indent);
  const voice = action.voice || 'Polly.Amy';

  switch (action.type) {
    case 'say':
      return `${pad}<Say voice="${voice}">${escapeXml(action.message || '')}</Say>`;

    case 'play':
      return `${pad}<Play>${escapeXml(action.url || '')}</Play>`;

    case 'gather': {
      const attrs = [
        action.numDigits ? `numDigits="${action.numDigits}"` : '',
        action.timeout ? `timeout="${action.timeout}"` : 'timeout="5"',
        action.action ? `action="${escapeXml(action.action)}"` : '',
        action.method ? `method="${action.method}"` : '',
      ].filter(Boolean).join(' ');

      let inner = '';
      if (action.children) {
        inner = '\n' + action.children.map(c => actionToXml(c, indent + 2)).join('\n') + '\n' + pad;
      }
      return `${pad}<Gather ${attrs}>${inner}</Gather>`;
    }

    case 'dial': {
      if (action.number) {
        return `${pad}<Dial>${action.number}</Dial>`;
      }
      if (action.queue) {
        return `${pad}<Dial><Queue>${escapeXml(action.queue)}</Queue></Dial>`;
      }
      return `${pad}<Dial/>`;
    }

    case 'record': {
      const attrs = [
        action.timeout ? `timeout="${action.timeout}"` : 'timeout="10"',
        action.action ? `action="${escapeXml(action.action)}"` : '',
        'transcribe="true"',
      ].filter(Boolean).join(' ');
      return `${pad}<Record ${attrs}/>`;
    }

    case 'hangup':
      return `${pad}<Hangup/>`;

    case 'pause':
      return `${pad}<Pause length="${action.timeout || 1}"/>`;

    case 'redirect':
      return `${pad}<Redirect>${escapeXml(action.url || '')}</Redirect>`;

    case 'enqueue':
      return `${pad}<Enqueue>${escapeXml(action.queue || '')}</Enqueue>`;

    default:
      return '';
  }
}

/** Build TwiML for a simple say-and-hangup */
export function sayTwiML(message: string, voice = 'Polly.Amy'): string {
  return buildTwiML([
    { type: 'say', message, voice },
    { type: 'hangup' },
  ]);
}

/** Build TwiML for connecting to another number */
export function connectTwiML(toNumber: string, callerMessage?: string): string {
  const actions: TwiMLAction[] = [];
  if (callerMessage) {
    actions.push({ type: 'say', message: callerMessage });
  }
  actions.push({ type: 'dial', number: toNumber });
  return buildTwiML(actions);
}

/** Build TwiML for a simple IVR menu */
export function menuTwiML(
  greeting: string,
  _options: Array<{ digit: string; action: TwiMLAction }>,
  voice = 'Polly.Amy'
): string {
  const gatherChildren: TwiMLAction[] = [
    { type: 'say', message: greeting, voice },
  ];

  return buildTwiML([
    {
      type: 'gather',
      numDigits: 1,
      timeout: 10,
      children: gatherChildren,
    },
    { type: 'say', message: 'Sorry, I didn\'t get that. Goodbye.', voice },
    { type: 'hangup' },
  ]);
}

function escapeXml(str: string): string {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&apos;');
}
