/**
 * Create Attribute - Attio API
 *
 * Creates a new custom attribute (field) on an Attio object.
 * POST /v2/objects/{object}/attributes
 */

import { ToolingError } from '../../../../../../types'
import type { ExecutionContext } from '../../../../../../../base/types'
import { withRetry, createHttpError, DEFAULT_RETRY_POLICY } from '../../../../../../../../../platform/resilience'
import type {
  AttioCredentials,
  CreateAttributeParams,
  CreateAttributeResult,
  AttioAttributeResponse,
  AttributeConfig
} from '../utils/types'

/**
 * Create a new attribute on an Attio object
 *
 * @param credentials - Attio API credentials (apiKey)
 * @param params - Attribute creation parameters
 * @param context - Execution context for logging
 * @returns Created attribute ID, slug, and success status
 * @throws ToolingError if attribute creation fails
 *
 * @example
 * // Create a text attribute
 * const attr = await createAttribute(
 *   { apiKey: 'xxx' },
 *   {
 *     objectSlug: 'people',
 *     title: 'Lead Source',
 *     apiSlug: 'lead_source',
 *     type: 'text'
 *   },
 *   context
 * )
 *
 * @example
 * // Create a select attribute with options
 * const attr = await createAttribute(
 *   { apiKey: 'xxx' },
 *   {
 *     objectSlug: 'companies',
 *     title: 'Industry',
 *     apiSlug: 'industry',
 *     type: 'select',
 *     config: {
 *       options: [
 *         { title: 'Technology', isArchived: false },
 *         { title: 'Healthcare', isArchived: false },
 *         { title: 'Finance', isArchived: false }
 *       ]
 *     }
 *   },
 *   context
 * )
 */
export async function createAttribute(
  credentials: AttioCredentials,
  params: CreateAttributeParams,
  context?: ExecutionContext
): Promise<CreateAttributeResult> {
  const { apiKey } = credentials
  const { objectSlug, title, apiSlug, type, description, isRequired, isUnique, isMultiselect, config } = params

  // Validate credentials
  if (!apiKey) {
    throw new ToolingError('credentials_invalid', 'Attio API credentials must include apiKey', {
      integration: 'attio',
      method: 'createAttribute'
    })
  }

  // Validate required parameters
  if (!objectSlug) {
    throw new ToolingError('validation_error', 'objectSlug is required', {
      integration: 'attio',
      method: 'createAttribute',
      params: { objectSlug }
    })
  }
  if (!title) {
    throw new ToolingError('validation_error', 'title is required', {
      integration: 'attio',
      method: 'createAttribute',
      params: { title }
    })
  }
  if (!apiSlug) {
    throw new ToolingError('validation_error', 'apiSlug is required', {
      integration: 'attio',
      method: 'createAttribute',
      params: { apiSlug }
    })
  }
  if (!type) {
    throw new ToolingError('validation_error', 'type is required', {
      integration: 'attio',
      method: 'createAttribute',
      params: { type }
    })
  }

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

  // Build request body with nested data structure
  // Note: Attio API requires description (can be null) and config (empty object for simple types)
  const requestBody = {
    data: {
      title,
      description: description ?? null,
      api_slug: apiSlug,
      type,
      is_required: isRequired ?? false,
      is_unique: isUnique ?? false,
      is_multiselect: isMultiselect ?? false,
      config: config ? buildAttributeConfig(config) : {}
    }
  }

  try {
    // Execute with retry logic
    const response = await withRetry(async () => {
      const res = await fetch(url, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${apiKey}`,
          'Content-Type': 'application/json',
          Accept: 'application/json'
        },
        body: JSON.stringify(requestBody)
      })

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

      return res
    }, DEFAULT_RETRY_POLICY)

    // Parse response
    const result = (await response.json()) as AttioAttributeResponse

    // Extract attribute ID from nested structure
    const attributeId = result.data.id.attribute_id

    // Log success
    if (context?.logger) {
      context.logger.info(
        `[AttioAdapter] Attribute created: attributeId=${attributeId} objectSlug=${objectSlug} title=${title} type=${type} executionId=${context.executionId}`
      )
    }

    // Return standardized result
    return {
      attributeId,
      slug: result.data.api_slug,
      success: true
    }
  } catch (error) {
    // Re-throw ToolingError as-is
    if (error instanceof ToolingError) {
      throw error
    }

    // Wrap unknown errors
    throw new ToolingError('api_error', `Failed to create Attio attribute: ${(error as Error).message}`, {
      integration: 'attio',
      method: 'createAttribute',
      organizationId: context?.organizationId,
      params: { objectSlug, title, type },
      originalError: error
    })
  }
}

/**
 * Build attribute config for API request
 * Transforms camelCase to snake_case for API compatibility
 */
function buildAttributeConfig(config: AttributeConfig): Record<string, unknown> {
  const result: Record<string, unknown> = {}

  // Build select options
  if (config.options) {
    result.options = config.options.map((opt) => ({
      ...(opt.id && { id: opt.id }),
      title: opt.title,
      is_archived: opt.isArchived ?? false
    }))
  }

  // Build other config fields
  if (config.targetObject) {
    result.target_object = config.targetObject
  }
  if (config.currencyCode) {
    result.currency_code = config.currencyCode
  }
  if (config.maxValue !== undefined) {
    result.max_value = config.maxValue
  }

  return result
}
