import axios, { AxiosError, type AxiosRequestConfig } from 'axios'
import { isKbxProblem, kbxUnexpectedProblem, type KbxProblem, type KbxSystemProblem } from '@kbx/contracts'

export const kbxHttp = axios.create({
  timeout: 30_000,
  headers: { 'X-KBX-Client': 'web' },
})

kbxHttp.interceptors.request.use(config => {
  config.headers['X-Correlation-Id'] ??= crypto.randomUUID()
  return config
})

kbxHttp.interceptors.response.use(
  response => response,
  (error: AxiosError) => {
    const correlationId = String(error.config?.headers?.['X-Correlation-Id'] ?? crypto.randomUUID())

    if (!error.response) {
      const problem: KbxSystemProblem = {
        type: 'system',
        code: 'NETWORK_UNAVAILABLE',
        title: '서버와 연결할 수 없습니다.',
        detail: '입력한 내용은 유지됩니다. 네트워크 상태를 확인한 후 다시 시도하세요.',
        correlationId,
        retryable: true,
      }
      return Promise.reject(problem)
    }

    const data = error.response.data
    if (isKbxProblem(data)) {
      const problem: KbxProblem = {
        ...data,
        correlationId: data.correlationId ?? correlationId,
      }
      return Promise.reject(problem)
    }

    if (error.response.status === 403) {
      return Promise.reject({
        type: 'permission', code: 'PERMISSION_DENIED', title: '이 작업을 수행할 권한이 없습니다.', correlationId,
      } satisfies KbxProblem)
    }
    if (error.response.status === 404) {
      return Promise.reject({
        type: 'not-found', code: 'RESOURCE_NOT_FOUND', title: '요청한 데이터를 찾을 수 없습니다.', correlationId,
      } satisfies KbxProblem)
    }

    return Promise.reject(kbxUnexpectedProblem(correlationId, `HTTP ${error.response.status}`, error.response.status >= 500))
  },
)

export function withIdempotency(config: AxiosRequestConfig = {}, key = crypto.randomUUID()): AxiosRequestConfig {
  return {
    ...config,
    headers: {
      ...(config.headers ?? {}),
      'Idempotency-Key': key,
    },
  }
}
