import { kbxApiCatalog, type KbxApiOperationDefinition, type KbxApiOperationId, type KbxApiRequestOptions } from '@kbx/contracts'
import { kbxHttp } from '../kbxHttpClient'

function buildPath(template: string, values: Record<string, string | number> = {}) {
  return template.replace(/\{([^}:]+)(?::[^}]+)?\}/g, (_, name: string) => {
    const key = Object.keys(values).find(x => x.toLowerCase() === name.toLowerCase())
    if (!key) throw new Error(`API path parameter '${name}' is required.`)
    return encodeURIComponent(String(values[key]))
  })
}

export async function requestKbxApi<TResponse = unknown, TBody = unknown>(
  operationId: KbxApiOperationId,
  options: KbxApiRequestOptions<TBody> = {},
): Promise<TResponse> {
  const operation: KbxApiOperationDefinition = kbxApiCatalog[operationId]
  if (operation.idempotency === 'required' && !options.idempotencyKey) {
    throw new Error(`Operation '${operationId}' requires a stable idempotency key.`)
  }

  const headers: Record<string, string> = { ...(options.headers ?? {}) }
  if (options.idempotencyKey) headers['Idempotency-Key'] = options.idempotencyKey

  const response = await kbxHttp.request<TResponse>({
    method: operation.method,
    url: buildPath(operation.path, options.path),
    params: options.query,
    data: options.body,
    headers,
    responseType: options.responseType ?? operation.responseType ?? 'json',
    validateStatus: status => operation.successStatuses.some(value => value === status),
  })
  return response.data
}

export const kbxApi = {
  request: requestKbxApi,
}
