/**
 * List Attributes - Attio API
 *
 * Lists all attributes (fields) for a specific object.
 * GET /v2/objects/{object}/attributes
 *
 * Documentation: https://developers.attio.com/reference/get-attributes
 */

import { ToolingError } from '../../../../../../types'
import { withRetry, createHttpError, DEFAULT_RETRY_POLICY } from '../../../../../../../../../platform/resilience'
import type { ExecutionContext } from '../../../../../../../base/types'
import type {
  AttioCredentials,
  ListAttributesParams,
  ListAttributesResult,
  AttioAttributesListResponse,
  AttioAttributeType
} from '../utils/types'

/**
 * List all attributes for an Attio object
 *
 * @param credentials - Attio API credentials (apiKey)
 * @param params - Object slug to list attributes for
 * @param context - Execution context for logging
 * @returns List of attributes with metadata and configuration
 * @throws ToolingError if API call fails
 *
 * @example
 * const result = await listAttributes(
 *   { apiKey: 'xxx' },
 *   { objectSlug: 'people' },
 *   context
 * )
 * // result.attributes = [{ id: '...', slug: 'name', type: 'text', ... }, ...]
 */
export async function listAttributes(
  credentials: AttioCredentials,
  params: ListAttributesParams,
  context?: ExecutionContext
): Promise<ListAttributesResult> {
  const { apiKey } = credentials
  const { objectSlug } = params

  // Validate credentials
  if (!apiKey) {
    throw new ToolingError('credentials_invalid', 'Missing Attio API key', {
      integration: 'attio',
      method: 'listAttributes',
      organizationId: context?.organizationId
    })
  }

  // Validate parameters
  if (!objectSlug) {
    throw new ToolingError('validation_error', 'objectSlug is required', {
      integration: 'attio',
      method: 'listAttributes',
      organizationId: context?.organizationId
    })
  }

  // Build URL
  const url = `https://api.attio.com/v2/objects/${encodeURIComponent(objectSlug)}/attributes`

  try {
    // Execute with retry logic
    const data = await withRetry(async () => {
      const response = await fetch(url, {
        method: 'GET',
        headers: {
          Authorization: `Bearer ${apiKey}`,
          Accept: 'application/json'
        }
      })

      // Handle HTTP errors
      if (!response.ok) {
        throw await createHttpError(response, {
          integration: 'attio',
          method: 'listAttributes',
          organizationId: context?.organizationId,
          params: { objectSlug }
        })
      }

      return (await response.json()) as AttioAttributesListResponse
    }, DEFAULT_RETRY_POLICY)

    // Log success
    if (context?.logger) {
      context.logger.info(
        `[AttioAdapter] Attributes listed: objectSlug=${objectSlug} attributeCount=${data.data.length} executionId=${context.executionId}`
      )
    }

    // Transform response to clean format
    return {
      attributes: data.data.map((attr) => ({
        id: attr.id.attribute_id,
        slug: attr.api_slug,
        title: attr.title,
        description: attr.description,
        type: attr.type as AttioAttributeType,
        isSystemAttribute: attr.is_system_attribute,
        isRequired: attr.is_required,
        isUnique: attr.is_unique,
        isMultiselect: attr.is_multiselect,
        isArchived: attr.is_archived,
        config: attr.config ? parseAttributeConfig(attr.config) : undefined
      }))
    }
  } catch (error) {
    // Re-throw ToolingError as-is
    if (error instanceof ToolingError) {
      throw error
    }

    // Wrap unknown errors
    throw new ToolingError('api_error', `Failed to list Attio attributes: ${(error as Error).message}`, {
      integration: 'attio',
      method: 'listAttributes',
      organizationId: context?.organizationId,
      params: { objectSlug }
    })
  }
}

/**
 * Parse attribute config from API response
 *
 * Transforms snake_case API response to camelCase internal format.
 * Handles type-specific configuration fields.
 */
function parseAttributeConfig(config: Record<string, unknown>) {
  const result: {
    options?: Array<{ id?: string; title: string; isArchived: boolean }>
    targetObject?: string
    currencyCode?: string
    maxValue?: number
  } = {}

  // Parse select options
  if (Array.isArray(config.options)) {
    result.options = config.options.map((opt: { id?: string; title: string; is_archived?: boolean }) => ({
      id: opt.id,
      title: opt.title,
      isArchived: opt.is_archived ?? false
    }))
  }

  // Parse other config fields
  if (typeof config.target_object === 'string') {
    result.targetObject = config.target_object
  }
  if (typeof config.currency_code === 'string') {
    result.currencyCode = config.currency_code
  }
  if (typeof config.max_value === 'number') {
    result.maxValue = config.max_value
  }

  return Object.keys(result).length > 0 ? result : undefined
}
