/**
 * Typed failure model for Effect HTTP client operations.
 *
 * HTTP clients wrap request construction, transport, status-code validation, and
 * response decoding failures in `HttpClientError`. The wrapper keeps the failed
 * request and the specific failure reason together, so callers can handle client
 * failures uniformly while still matching on the reason `_tag` for retry
 * policy, logging, metrics, and user-facing messages.
 *
 * **Mental model**
 *
 * A client error reason belongs to one of two families. Request errors happen
 * before a response exists: `TransportError`, `EncodeError`, and
 * `InvalidUrlError`. Response errors include the response that triggered them:
 * `StatusCodeError`, `DecodeError`, and `EmptyBodyError`.
 *
 * **Common tasks**
 *
 * - Use `isHttpClientError` at untyped boundaries.
 * - Read `request` for the method and URL associated with any client failure.
 * - Match on `reason._tag` when different failures need different recovery.
 * - Read `response` only for response errors or after checking that it exists.
 *
 * **Gotchas**
 *
 * `response` is `undefined` for transport, encoding, and invalid URL failures.
 * Preserve the original `cause` when constructing reason classes so lower-level
 * platform or decoding details are not lost.
 *
 * @since 4.0.0
 */
import * as Data from "../../Data.js";
import { hasProperty } from "../../Predicate.js";
import * as Schema from "../../Schema.js";
const TypeId = "~effect/http/HttpClientError";
/**
 * Returns `true` when a value is an `HttpClientError`.
 *
 * @category guards
 * @since 4.0.0
 */
export const isHttpClientError = u => hasProperty(u, TypeId);
/**
 * Error wrapper for HTTP client failures, exposing the failed request and the optional response through its `reason`.
 *
 * @category errors
 * @since 4.0.0
 */
export class HttpClientError extends /*#__PURE__*/Data.TaggedError("HttpClientError") {
  constructor(props) {
    if ("cause" in props.reason) {
      super({
        ...props,
        cause: props.reason.cause
      });
    } else {
      super(props);
    }
  }
  /**
   * Marks this value as an HTTP client error for runtime guards.
   *
   * @since 4.0.0
   */
  [TypeId] = TypeId;
  /**
   * HTTP request associated with the client failure.
   *
   * @since 4.0.0
   */
  get request() {
    return this.reason.request;
  }
  /**
   * HTTP response associated with the client failure, when one was received.
   *
   * @since 4.0.0
   */
  get response() {
    return "response" in this.reason ? this.reason.response : undefined;
  }
  get message() {
    return this.reason.message;
  }
}
const formatReason = tag => tag.endsWith("Error") ? tag.slice(0, -5) : tag;
const formatMessage = (reason, description, info) => description ? `${reason}: ${description} (${info})` : `${reason} error (${info})`;
/**
 * Error describing transport-level failures that occur while sending an HTTP request.
 *
 * @category errors
 * @since 4.0.0
 */
export class TransportError extends /*#__PURE__*/Data.TaggedError("TransportError") {
  /**
   * Formats the request method and URL for transport error messages.
   *
   * @since 4.0.0
   */
  get methodAndUrl() {
    return `${this.request.method} ${this.request.url}`;
  }
  /**
   * Builds the transport error message from the optional description and request details.
   *
   * @since 4.0.0
   */
  get message() {
    return formatMessage(formatReason(this._tag), this.description, this.methodAndUrl);
  }
}
/**
 * Error describing failures while encoding an HTTP request body.
 *
 * @category errors
 * @since 4.0.0
 */
export class EncodeError extends /*#__PURE__*/Data.TaggedError("EncodeError") {
  /**
   * Formats the request method and URL for request encoding error messages.
   *
   * @since 4.0.0
   */
  get methodAndUrl() {
    return `${this.request.method} ${this.request.url}`;
  }
  /**
   * Builds the request encoding error message from the optional description and request details.
   *
   * @since 4.0.0
   */
  get message() {
    return formatMessage(formatReason(this._tag), this.description, this.methodAndUrl);
  }
}
/**
 * Error describing failures while constructing a URL from an HTTP client request.
 *
 * @category errors
 * @since 4.0.0
 */
export class InvalidUrlError extends /*#__PURE__*/Data.TaggedError("InvalidUrlError") {
  /**
   * Formats the request method and URL for invalid URL error messages.
   *
   * @since 4.0.0
   */
  get methodAndUrl() {
    return `${this.request.method} ${this.request.url}`;
  }
  /**
   * Builds the invalid URL error message from the optional description and request details.
   *
   * @since 4.0.0
   */
  get message() {
    return formatMessage(formatReason(this._tag), this.description, this.methodAndUrl);
  }
}
/**
 * Response error for HTTP responses rejected because of their status code.
 *
 * @category errors
 * @since 4.0.0
 */
export class StatusCodeError extends /*#__PURE__*/Data.TaggedError("StatusCodeError") {
  /**
   * Formats the request method and URL for status code error messages.
   *
   * @since 4.0.0
   */
  get methodAndUrl() {
    return `${this.request.method} ${this.request.url}`;
  }
  /**
   * Builds the status code error message from the response status, optional description, and request details.
   *
   * @since 4.0.0
   */
  get message() {
    const info = `${this.response.status} ${this.methodAndUrl}`;
    return formatMessage(formatReason(this._tag), this.description, info);
  }
}
/**
 * Response error for failures while decoding an HTTP response body.
 *
 * @category errors
 * @since 4.0.0
 */
export class DecodeError extends /*#__PURE__*/Data.TaggedError("DecodeError") {
  /**
   * Formats the request method and URL for response decoding error messages.
   *
   * @since 4.0.0
   */
  get methodAndUrl() {
    return `${this.request.method} ${this.request.url}`;
  }
  /**
   * Builds the response decoding error message from the response status, optional description, and request details.
   *
   * @since 4.0.0
   */
  get message() {
    const info = `${this.response.status} ${this.methodAndUrl}`;
    return formatMessage(formatReason(this._tag), this.description, info);
  }
}
/**
 * Response error for operations that expected a response body but received an empty body.
 *
 * @category errors
 * @since 4.0.0
 */
export class EmptyBodyError extends /*#__PURE__*/Data.TaggedError("EmptyBodyError") {
  /**
   * Formats the request method and URL for empty response body error messages.
   *
   * @since 4.0.0
   */
  get methodAndUrl() {
    return `${this.request.method} ${this.request.url}`;
  }
  /**
   * Builds the empty body error message from the response status, optional description, and request details.
   *
   * @since 4.0.0
   */
  get message() {
    const info = `${this.response.status} ${this.methodAndUrl}`;
    return formatMessage(formatReason(this._tag), this.description, info);
  }
}
/**
 * Schema for serializable HTTP client errors, preserving the specific error kind
 * and cause.
 *
 * @category schemas
 * @since 4.0.0
 */
export class HttpClientErrorSchema extends /*#__PURE__*/Schema.ErrorClass(TypeId)({
  _tag: /*#__PURE__*/Schema.tag("HttpError"),
  kind: /*#__PURE__*/Schema.Literals(["EncodeError", "DecodeError", "TransportError", "InvalidUrlError", "StatusCodeError", "EmptyBodyError"]),
  cause: /*#__PURE__*/Schema.optional(Schema.Defect)
}) {
  /**
   * Builds the serializable schema representation for an HTTP client error.
   *
   * @since 4.0.0
   */
  static fromHttpClientError(error) {
    return new HttpClientErrorSchema({
      _tag: "HttpError",
      kind: error.reason._tag,
      cause: error.reason
    });
  }
}
//# sourceMappingURL=HttpClientError.js.map