/**
 * Typeform API Client
 *
 * Uses the Typeform API to fetch form schemas and responses.
 * API docs: https://developer.typeform.com/
 */

const TYPEFORM_API_BASE = 'https://api.typeform.com'

// Type definitions for Typeform API responses
export interface TypeformForm {
  id: string
  title: string
  fields: TypeformField[]
}

export interface TypeformField {
  id: string
  ref: string
  title: string
  type: string
  properties?: {
    choices?: Array<{ id: string; label: string }>
    allow_multiple_selection?: boolean
    description?: string
  }
  validations?: {
    required?: boolean
    max_length?: number
  }
}

export interface TypeformResponse {
  response_id: string
  submitted_at: string
  answers: TypeformAnswer[]
  hidden?: Record<string, string>
  metadata?: {
    user_agent?: string
    platform?: string
    referer?: string
  }
}

export interface TypeformAnswer {
  field: {
    id: string
    ref: string
    type: string
  }
  type: string
  text?: string
  number?: number
  boolean?: boolean
  email?: string
  url?: string
  phone_number?: string
  date?: string
  choice?: { id: string; label: string }
  choices?: { ids: string[]; labels: string[] }
  file_url?: string
}

export interface TypeformResponsesResult {
  total_items: number
  page_count: number
  items: TypeformResponse[]
}

/**
 * Test connection to Typeform API
 */
export async function testTypeformConnection(
  apiKey: string
): Promise<{ success: boolean; error?: string }> {
  try {
    const response = await fetch(`${TYPEFORM_API_BASE}/me`, {
      headers: {
        Authorization: `Bearer ${apiKey}`,
      },
    })

    if (!response.ok) {
      const error = await response.text()
      return {
        success: false,
        error: `API error: ${response.status} - ${error}`,
      }
    }

    return { success: true }
  } catch (error) {
    return {
      success: false,
      error: error instanceof Error ? error.message : 'Failed to connect to Typeform',
    }
  }
}

/**
 * Get form schema (fields)
 */
export async function getTypeformSchema(
  apiKey: string,
  formId: string
): Promise<TypeformForm> {
  const response = await fetch(`${TYPEFORM_API_BASE}/forms/${formId}`, {
    headers: {
      Authorization: `Bearer ${apiKey}`,
    },
  })

  if (!response.ok) {
    const error = await response.text()
    throw new Error(`Failed to fetch form: ${response.status} - ${error}`)
  }

  const data = await response.json()

  return {
    id: data.id,
    title: data.title,
    fields: (data.fields || []).map((field: TypeformField) => ({
      id: field.id,
      ref: field.ref,
      title: field.title,
      type: field.type,
      properties: field.properties,
      validations: field.validations,
    })),
  }
}

/**
 * Get form responses
 */
export async function getTypeformResponses(
  apiKey: string,
  formId: string,
  options?: {
    limit?: number
    since?: string // ISO date string
    until?: string // ISO date string
  }
): Promise<TypeformResponsesResult> {
  const params = new URLSearchParams()

  if (options?.limit) {
    params.set('page_size', String(Math.min(options.limit, 1000)))
  }
  if (options?.since) {
    params.set('since', options.since)
  }
  if (options?.until) {
    params.set('until', options.until)
  }

  const url = `${TYPEFORM_API_BASE}/forms/${formId}/responses?${params.toString()}`

  const response = await fetch(url, {
    headers: {
      Authorization: `Bearer ${apiKey}`,
    },
  })

  if (!response.ok) {
    const error = await response.text()
    throw new Error(`Failed to fetch responses: ${response.status} - ${error}`)
  }

  const data = await response.json()

  return {
    total_items: data.total_items,
    page_count: data.page_count,
    items: data.items || [],
  }
}

/**
 * Get all responses with pagination
 */
export async function getAllTypeformResponses(
  apiKey: string,
  formId: string,
  limit?: number
): Promise<TypeformResponse[]> {
  const allResponses: TypeformResponse[] = []
  let hasMore = true
  let before: string | undefined

  while (hasMore) {
    const params = new URLSearchParams({
      page_size: '1000',
    })

    if (before) {
      params.set('before', before)
    }

    const url = `${TYPEFORM_API_BASE}/forms/${formId}/responses?${params.toString()}`

    const response = await fetch(url, {
      headers: {
        Authorization: `Bearer ${apiKey}`,
      },
    })

    if (!response.ok) {
      break
    }

    const data = await response.json()
    const items = data.items || []

    allResponses.push(...items)

    if (limit && allResponses.length >= limit) {
      return allResponses.slice(0, limit)
    }

    if (items.length < 1000) {
      hasMore = false
    } else {
      // Get the token for the next page
      before = items[items.length - 1]?.token
      if (!before) {
        hasMore = false
      }
    }
  }

  return allResponses
}

/**
 * Extract a value from a Typeform answer
 */
export function extractAnswerValue(answer: TypeformAnswer): unknown {
  switch (answer.type) {
    case 'text':
      return answer.text
    case 'number':
      return answer.number
    case 'boolean':
      return answer.boolean
    case 'email':
      return answer.email
    case 'url':
      return answer.url
    case 'phone_number':
      return answer.phone_number
    case 'date':
      return answer.date
    case 'choice':
      return answer.choice?.label
    case 'choices':
      return answer.choices?.labels || []
    case 'file_url':
      return answer.file_url
    default:
      return null
  }
}

/**
 * Convert a Typeform response to a flat object using field refs as keys
 */
export function responseToObject(
  response: TypeformResponse,
  fields: TypeformField[]
): Record<string, unknown> {
  const result: Record<string, unknown> = {
    _response_id: response.response_id,
    _submitted_at: response.submitted_at,
  }

  // Create a map of field refs to titles for better key naming
  const fieldMap = new Map<string, string>()
  for (const field of fields) {
    fieldMap.set(field.ref, field.title)
  }

  for (const answer of response.answers) {
    const key = fieldMap.get(answer.field.ref) || answer.field.ref
    result[key] = extractAnswerValue(answer)
  }

  // Include hidden fields if present
  if (response.hidden) {
    for (const [key, value] of Object.entries(response.hidden)) {
      result[`_hidden_${key}`] = value
    }
  }

  return result
}
