import { ToolingError } from '../../../../../../types'
import type { ExecutionContext } from '../../../../../../../base/types'
import { withRetry, createHttpError, DEFAULT_RETRY_POLICY } from '../../../../../../../../../platform/resilience'
import type { AttioCredentials, UpdateRecordParams, UpdateRecordResult, AttioRecordResponse } from '../utils/types'

/**
 * Update an existing record in an Attio object using native fetch API
 *
 * @param credentials - Attio API credentials (apiKey)
 * @param params - Record update parameters (object type, record ID, and field values)
 * @param context - Execution context for logging
 * @returns Updated record ID and success status
 * @throws ToolingError if record update fails
 *
 * @example
 * // Update a person's status
 * const updated = await updateRecord(
 *   { apiKey: 'xxx' },
 *   {
 *     object: 'people',
 *     recordId: 'uuid-here',
 *     values: {
 *       status: 'active',
 *       description: 'Updated description'
 *     }
 *   },
 *   context
 * )
 *
 * @example
 * // Update a deal value
 * const updated = await updateRecord(
 *   { apiKey: 'xxx' },
 *   {
 *     object: 'deals',
 *     recordId: 'uuid-here',
 *     values: {
 *       value: {
 *         currency_code: 'USD',
 *         value: 75000
 *       },
 *       status: 'closed_won'
 *     }
 *   },
 *   context
 * )
 */
export async function updateRecord(
  credentials: AttioCredentials,
  params: UpdateRecordParams,
  context?: ExecutionContext
): Promise<UpdateRecordResult> {
  const { apiKey } = credentials
  const { object, recordId, values } = params

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

  if (!object || !recordId || !values) {
    throw new ToolingError('validation_error', 'Object type, record ID, and values are required', {
      integration: 'attio',
      method: 'updateRecord',
      params: { object, recordId, values }
    })
  }

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

  // Build request body with nested data.values structure (same as createRecord)
  const requestBody = {
    data: {
      values
    }
  }

  try {
    // Execute with retry logic
    const response = await withRetry(async () => {
      const res = await fetch(url, {
        method: 'PATCH',
        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: 'updateRecord',
          organizationId: context?.organizationId
        })
      }

      return res
    }, DEFAULT_RETRY_POLICY)

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

    // Extract record ID from nested structure and verify it matches
    const returnedRecordId = result.data.id.record_id

    // Log success
    if (context?.logger) {
      context.logger.info(
        `[AttioAdapter] Record updated: recordId=${returnedRecordId} object=${object} executionId=${context.executionId}`
      )
    }

    // Return standardized result
    return {
      recordId: returnedRecordId,
      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 update Attio record: ${(error as Error).message}`, {
      integration: 'attio',
      method: 'updateRecord',
      organizationId: context?.organizationId,
      params: { object, recordId },
      originalError: error
    })
  }
}
