/**
 * `@arcjet/guard/fetch` — Fetch-based entrypoint.
 *
 * Uses the Connect-Web transport which works in Deno, Cloudflare Workers,
 * browsers, and any runtime with a standard `fetch` API (WinterTC minimum
 * common API). Deno's fetch transparently negotiates HTTP/2 over TLS via
 * ALPN — no special configuration needed.
 *
 * Bun's fetch does not support HTTP/2 ({@link https://github.com/oven-sh/bun/issues/7194}).
 * On Bun, the `"."` export resolves to the `bun` entrypoint which uses
 * `node:http2` directly for HTTP/2 support.
 *
 * **Lifecycle:** Create the client once at module scope and reuse it.
 *
 * @example
 * ```ts
 * import { launchArcjet, tokenBucket, detectPromptInjection } from "@arcjet/guard";
 *
 * // Create the client once at module scope
 * const arcjet = launchArcjet({ key: "ajkey_..." });
 *
 * // Configure reusable rules (also at module scope)
 * const limitRule = tokenBucket({ bucket: "user-tokens", refillRate: 10, intervalSeconds: 60, maxTokens: 100 });
 * const piRule = detectPromptInjection();
 *
 * // Per request — create rule inputs each time
 * const rl = limitRule({ key: userId, requested: tokenCount });
 * const decision = await arcjet.guard({
 *   label: "tools.weather",
 *   rules: [rl, piRule(userMessage)],
 * });
 *
 * // Overall decision
 * if (decision.conclusion === "DENY") {
 *   console.log(decision.reason); // "RATE_LIMIT", "PROMPT_INJECTION", etc.
 * }
 *
 * // Fail open by default; opt in to fail closed when a rule could not run.
 * if (decision.hasFailedOpen()) {
 *   console.warn("a rule could not be evaluated", decision.errorResults());
 * }
 *
 * // Request diagnostics — the decision is still valid.
 * for (const warning of decision.warnings) {
 *   console.warn(warning.code, warning.message);
 * }
 *
 * // Per-rule results
 * for (const result of decision.results) {
 *   console.log(result.type, result.conclusion);
 * }
 *
 * // From a RuleWithInput — result for this specific submission
 * const r = rl.result(decision);
 * if (r) {
 *   console.log(r.remainingTokens, r.maxTokens);
 * }
 *
 * // From a RuleWithConfig — first denied result across all submissions
 * const denied = limitRule.deniedResult(decision);
 * if (denied) {
 *   console.log(denied.remainingTokens); // 0
 * }
 * ```
 *
 * Unlike some other `@arcjet/*` packages, `@arcjet/guard` never reads
 * environment variables directly. All configuration must be passed
 * explicitly via `launchArcjet()` options, `.guard()`, or rule inputs.
 *
 * @packageDocumentation
 */

export {
  // Types
  type Conclusion,
  type Billing,
  type Reason,
  type Mode,
  type RuleResult,
  type RuleResultTokenBucket,
  type RuleResultFixedWindow,
  type RuleResultSlidingWindow,
  type RuleResultPromptInjection,
  type RuleResultModerateContent,
  type RuleResultSensitiveInfo,
  type RuleResultCustom,
  type RuleResultNotRun,
  type RuleResultError,
  type RuleResultUnknown,
  type Decision,
  type DecisionAllow,
  type DecisionDeny,
  type DecisionBase,
  type RuleWithInput,
  type RuleWithConfig,
  type CaptureOptions,
  type GuardOptions,
  type DiagnosticLogger,
  type LaunchOptions,
  type ArcjetGuard,
  type PolicyEvaluation,
  type PolicyInput,
  type PolicyInputMap,
  type PolicyRuleResult,
  type RuleResultInputConstraint,
  type StringMatchOperator,

  // Rule config types
  type TokenBucketConfig,
  type TokenBucketInput,
  type FixedWindowConfig,
  type FixedWindowInput,
  type SlidingWindowConfig,
  type SlidingWindowInput,
  type DetectPromptInjectionConfig,
  type DetectPromptInjectionInput,
  type ExperimentalModerateContentConfig,
  type ExperimentalModerateContentInput,
  type LocalDetectSensitiveInfoConfig,
  type LocalDetectSensitiveInfoInput,
  type SensitiveInfoEntityType,
  type SensitiveInfoBackend,
  type SensitiveInfoBackendContext,
  type SensitiveInfoBackendOptions,
  type SensitiveInfoBackendLogger,
  type LocalCustomConfig,
  type LocalCustomInput,

  // Rule factories
  tokenBucket,
  fixedWindow,
  slidingWindow,
  detectPromptInjection,
  experimental_moderateContent,
  localDetectSensitiveInfo,
  defineCustomRule,
  policyInput,

  // Transport-agnostic factory
  launchArcjetWithTransport,

  // Optional registration, and the free calls it enables
  registerArcjet,
  unregisterArcjet,
  guard,
  capture,
  flush,

  // Internal
  _launchWithTransportFactory,
} from "./index.ts";

import { _launchWithTransportFactory } from "./index.ts";
import type { LaunchOptions, ArcjetGuard } from "./index.ts";
import { createTransport } from "./transport-fetch.ts";

/**
 * Create an Arcjet guard client using the fetch-based transport.
 *
 * Compatible with Deno, Bun, Cloudflare Workers, browsers, and
 * any runtime providing the WHATWG Fetch API.
 *
 * Connect to the Arcjet MCP server at `https://api.arcjet.com/mcp` to manage
 * sites, retrieve SDK keys, and more. Learn more at
 * {@link https://docs.arcjet.com/mcp-server}.
 *
 * **Create once, reuse everywhere.** The returned client should be
 * created at module scope so it can be shared across requests.
 *
 * Three lifetimes to keep in mind:
 * 1. **Client** (`launchArcjet`) — create once at module scope.
 * 2. **Rule config** (`tokenBucket(...)`) — create once at module scope (recommended).
 * 3. **Rule input** (`limitRule({ key })`) — create per request / tool call.
 *
 * @example
 * ```ts
 * import { launchArcjet, tokenBucket, detectPromptInjection } from "@arcjet/guard";
 *
 * // Create the client once at module scope
 * const arcjet = launchArcjet({ key: "ajkey_..." });
 *
 * // Configure reusable rules (also at module scope)
 * const limitRule = tokenBucket({ bucket: "user-tokens", refillRate: 10, intervalSeconds: 60, maxTokens: 100 });
 * const piRule = detectPromptInjection();
 *
 * // Per request — create rule inputs each time
 * const rl = limitRule({ key: userId, requested: tokenCount });
 * const decision = await arcjet.guard({
 *   label: "tools.weather",
 *   rules: [rl, piRule(userMessage)],
 * });
 *
 * // Overall decision
 * if (decision.conclusion === "DENY") {
 *   console.log(decision.reason); // "RATE_LIMIT", "PROMPT_INJECTION", etc.
 * }
 *
 * // Fail open by default; opt in to fail closed when a rule could not run.
 * if (decision.hasFailedOpen()) {
 *   console.warn("a rule could not be evaluated", decision.errorResults());
 * }
 *
 * // Request diagnostics — the decision is still valid.
 * for (const warning of decision.warnings) {
 *   console.warn(warning.code, warning.message);
 * }
 *
 * // Per-rule results
 * for (const result of decision.results) {
 *   console.log(result.type, result.conclusion);
 * }
 *
 * // From a RuleWithInput — result for this specific submission
 * const r = rl.result(decision);
 * if (r) {
 *   console.log(r.remainingTokens, r.maxTokens);
 * }
 *
 * // From a RuleWithConfig — first denied result across all submissions
 * const denied = limitRule.deniedResult(decision);
 * if (denied) {
 *   console.log(denied.remainingTokens); // 0
 * }
 * ```
 */
export function launchArcjet(options: LaunchOptions): ArcjetGuard {
  return _launchWithTransportFactory(createTransport, options);
}

export { createTransport } from "./transport-fetch.ts";
