/**
 * Studio Flow JSON builder.
 * Generates Twilio Studio flow definitions programmatically.
 */

export interface StudioWidget {
  name: string;
  type: string;
  transitions: Array<{
    event: string;
    next?: string;
  }>;
  properties: Record<string, any>;
  offset?: { x: number; y: number };
}

export interface StudioFlow {
  description: string;
  states: StudioWidget[];
  initial_state: string;
  flags: { allow_concurrent_calls: boolean };
}

// Widget type constants
export const WIDGET_TYPES = {
  TRIGGER: 'trigger',
  SEND_MESSAGE: 'send-message',
  SEND_AND_REPLY: 'send-and-wait-for-reply',
  SAY_PLAY: 'say-play',
  GATHER: 'gather-input-on-call',
  CONNECT_CALL: 'connect-call-to',
  RECORD: 'record-voicemail',
  SPLIT: 'split-based-on',
  HTTP_REQUEST: 'make-http-request',
  SET_VARIABLES: 'set-variables',
  ENQUEUE: 'enqueue-call',
  SUBFLOW: 'run-subflow',
} as const;

/** Create the trigger widget (every flow starts here) */
export function triggerWidget(transitions: {
  incomingMessage?: string;
  incomingCall?: string;
  incomingRequest?: string;
}): StudioWidget {
  return {
    name: 'Trigger',
    type: WIDGET_TYPES.TRIGGER,
    transitions: [
      { event: 'incomingMessage', next: transitions.incomingMessage },
      { event: 'incomingCall', next: transitions.incomingCall },
      { event: 'incomingRequest', next: transitions.incomingRequest },
      { event: 'incomingParent' },
    ],
    properties: { offset: { x: 0, y: 0 } },
  };
}

/** Create a Say/Play widget */
export function sayWidget(name: string, message: string, options?: {
  voice?: string;
  loop?: number;
  next?: string;
}): StudioWidget {
  return {
    name,
    type: WIDGET_TYPES.SAY_PLAY,
    transitions: [
      { event: 'audioComplete', next: options?.next },
    ],
    properties: {
      say: message,
      voice: options?.voice || 'Polly.Amy',
      loop: options?.loop || 1,
    },
  };
}

/** Create a Gather widget (collect DTMF/speech input) */
export function gatherWidget(name: string, prompt: string, options?: {
  numDigits?: number;
  timeout?: number;
  voice?: string;
  validDigits?: string;
  onComplete?: string;
  onTimeout?: string;
}): StudioWidget {
  return {
    name,
    type: WIDGET_TYPES.GATHER,
    transitions: [
      { event: 'keypress', next: options?.onComplete },
      { event: 'speech', next: options?.onComplete },
      { event: 'timeout', next: options?.onTimeout },
    ],
    properties: {
      say: prompt,
      voice: options?.voice || 'Polly.Amy',
      number_of_digits: options?.numDigits || 1,
      timeout: options?.timeout || 5,
      valid_digits: options?.validDigits || '0123456789',
      gather_language: 'en',
      speech_timeout: 'auto',
      finish_on_key: '#',
    },
  };
}

/** Create a Connect Call widget */
export function connectWidget(name: string, toNumber: string, options?: {
  callerId?: string;
  timeout?: number;
  next?: string;
  noAnswer?: string;
  busy?: string;
}): StudioWidget {
  return {
    name,
    type: WIDGET_TYPES.CONNECT_CALL,
    transitions: [
      { event: 'callCompleted', next: options?.next },
      { event: 'callFailure', next: options?.noAnswer },
    ],
    properties: {
      to: toNumber,
      caller_id: options?.callerId || '{{contact.channel.address}}',
      timeout: options?.timeout || 30,
    },
  };
}

/** Create a Send Message widget */
export function sendMessageWidget(name: string, body: string, options?: {
  to?: string;
  from?: string;
  mediaUrl?: string;
  next?: string;
}): StudioWidget {
  return {
    name,
    type: WIDGET_TYPES.SEND_MESSAGE,
    transitions: [
      { event: 'sent', next: options?.next },
      { event: 'failed' },
    ],
    properties: {
      body,
      to: options?.to || '{{contact.channel.address}}',
      from: options?.from || '{{flow.channel.address}}',
      media_url: options?.mediaUrl,
    },
  };
}

/** Create a Split widget (conditional routing) */
export function splitWidget(name: string, variable: string, conditions: Array<{
  value: string;
  operator?: 'equal_to' | 'not_equal_to' | 'contains' | 'starts_with' | 'matches_any_of';
  next: string;
}>, options?: { noMatch?: string }): StudioWidget {
  return {
    name,
    type: WIDGET_TYPES.SPLIT,
    transitions: [
      ...conditions.map((c, i) => ({
        event: `match${i + 1}`,
        next: c.next,
        conditions: [{
          friendly_name: `${c.value}`,
          arguments: [variable],
          type: 'equal_to',
          value: c.value,
        }],
      })),
      { event: 'noMatch', next: options?.noMatch },
    ],
    properties: {
      input: variable,
    },
  };
}

/** Create an HTTP Request widget */
export function httpWidget(name: string, url: string, options?: {
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
  body?: Record<string, string>;
  headers?: Record<string, string>;
  onSuccess?: string;
  onFailure?: string;
}): StudioWidget {
  return {
    name,
    type: WIDGET_TYPES.HTTP_REQUEST,
    transitions: [
      { event: 'success', next: options?.onSuccess },
      { event: 'failed', next: options?.onFailure },
    ],
    properties: {
      method: options?.method || 'GET',
      url,
      body: options?.body || {},
      headers: options?.headers || {},
      content_type: 'application/json',
    },
  };
}

/** Create a Record widget */
export function recordWidget(name: string, options?: {
  playBeep?: boolean;
  maxLength?: number;
  transcribe?: boolean;
  onComplete?: string;
  onTimeout?: string;
}): StudioWidget {
  return {
    name,
    type: WIDGET_TYPES.RECORD,
    transitions: [
      { event: 'recordingComplete', next: options?.onComplete },
      { event: 'noAudio', next: options?.onTimeout },
    ],
    properties: {
      play_beep: options?.playBeep !== false ? 'true' : 'false',
      max_length: options?.maxLength || 120,
      transcribe: options?.transcribe !== false,
      trim: 'trim-silence',
    },
  };
}

/** Assemble a complete Studio flow definition */
export function buildFlow(description: string, widgets: StudioWidget[]): StudioFlow {
  // Auto-assign offsets for visual layout
  widgets.forEach((w, i) => {
    if (!w.offset) {
      w.offset = { x: 0, y: i * 200 };
    }
  });

  return {
    description,
    states: widgets,
    initial_state: 'Trigger',
    flags: { allow_concurrent_calls: true },
  };
}
