import { fetchJSON, HttpMethod } from "std::http"
import { parse } from "std::date"

/** @module
  @summary Shared request and normalization helpers for data connectors.
  Use these helpers when writing a connector for a public JSON API. They
  provide request handling, consistent error messages, limit clamping,
  and timestamp conversion.

  ```ts
  import { clampLimit, dateStrToEpochMs } from "std::data/connector"

  node main() {
    return {
      limit: clampLimit(500, 100),
      timestamp: dateStrToEpochMs("2026-01-01T00:00:00Z")
    }
  }
  ```
*/

/**
  In a custom connector, raise your connector's effect before calling this
  helper with `with approve`. That avoids a separate interactive prompt
  for each HTTP request. Outer handlers still receive the HTTP interrupt
  and can reject it. Calling this helper directly requires an HTTP decision.
*/
export def connectorFetch(
  base: string,
  domains: string[],
  path: string,
  headers: Record<string, any> = {},
  method: HttpMethod = "GET",
  body: Record<string, any> | string | null = null,
): Result raises <std::http::fetchJSON> {
  """
  Fetch a JSON API path within the allowed domains.

  @param base - The API base URL to resolve the path against.
  @param domains - Hostnames that the request is allowed to reach.
  @param path - The API path and query string, with user-supplied values URL-encoded.
  """
  return fetchJSON(baseUrl: base, path: path, headers: headers, allowedDomains: domains, method: method, body: body)
}

/** Keep request failures consistent across connector operations. */
export def connectorError(source: string, err: any): string {
  """
  Format a connector request failure with its source name.
  """
  return "${source} request failed (the API may be rate-limited): ${err.message ?? err}"
}

/** Preserve validation details so a caller can identify changed API fields. */
export def shapeError(source: string, endpoint: string, err: any): string {
  """
  Format a connector response-validation failure with its source and endpoint.
  """
  return "${source} ${endpoint} response did not match the expected shape (the API may have changed): ${err.message ?? err}"
}

/** Use for connector limits that should be clamped instead of rejected. */
export def clampLimit(n: number, cap: number): number {
  """
  Clamp a limit to the range from zero through the supplied cap.
  """
  if (n > cap) {
    return cap
  }
  if (n < 0) {
    return 0
  }
  return n
}

/** Normalize source timestamps so results from different connectors can be compared. */
export def dateStrToEpochMs(iso: string): number {
  """
  Convert an ISO 8601 timestamp to epoch milliseconds, returning zero if it cannot be parsed.
  """
  const parsed = try parse(iso)
  return parsed catch 0
}
