// SPDX-FileCopyrightText: © 2026 LEDGER SAS
// SPDX-License-Identifier: Apache-2.0

import { LedgerAPI4xx, LedgerAPI5xx, NetworkDown } from '@ledgerhq/errors'
import { NetworkError, NotFoundError } from '@stellar/stellar-sdk'
import { documentationSummaryFromHorizonBody, getHorizonErrorBody } from './horizonErrorBody'

export function messageFromHorizonUnknown(e: unknown): string {
  const body = getHorizonErrorBody(e)
  if (body) {
    return documentationSummaryFromHorizonBody(body)
  }
  if (e instanceof Error) {
    return e.message
  }
  if (typeof e === 'string') {
    return e
  }
  return ''
}

const HORIZON_STATUS_404 = /status code 404/
const HORIZON_TOO_MANY_REQUESTS = /too many requests/i
const HORIZON_STATUS_4XX = /status code 4\d{2}/
const HORIZON_STATUS_5XX = /status code 5\d{2}/
const HORIZON_NETWORK_DOWN = /ECONNRESET|ECONNREFUSED|ENOTFOUND|EPIPE|ETIMEDOUT/
const HORIZON_UNDEFINED_OBJECT = /undefined is not an object/

export function throwHorizonLedgerOrOperationsError(e: unknown, notFoundMessage: string): never {
  if (e instanceof NotFoundError) {
    throw new Error(notFoundMessage)
  }

  const body = getHorizonErrorBody(e)
  const status = body?.status
  if (status === 404) {
    throw new Error(notFoundMessage)
  }
  if (status === 429) {
    throw new LedgerAPI4xx('status code 4xx', { status: 429, url: undefined, method: 'GET' })
  }
  if (status !== undefined && status >= 400 && status < 500) {
    throw new LedgerAPI4xx()
  }
  if (status !== undefined && status >= 500 && status < 600) {
    throw new LedgerAPI5xx()
  }

  const errorMsg = messageFromHorizonUnknown(e)

  if (HORIZON_STATUS_404.exec(errorMsg)) {
    throw new Error(notFoundMessage)
  }
  if (HORIZON_TOO_MANY_REQUESTS.exec(errorMsg)) {
    throw new LedgerAPI4xx('status code 4xx', { status: 429, url: undefined, method: 'GET' })
  }
  if (HORIZON_STATUS_4XX.exec(errorMsg)) {
    throw new LedgerAPI4xx()
  }
  if (HORIZON_STATUS_5XX.exec(errorMsg)) {
    throw new LedgerAPI5xx()
  }
  if (
    e instanceof NetworkError ||
    HORIZON_NETWORK_DOWN.exec(errorMsg) ||
    HORIZON_UNDEFINED_OBJECT.exec(errorMsg)
  ) {
    throw new NetworkDown()
  }

  throw e
}
