/**
 * @beignet/core/ports
 *
 * A tiny, framework-agnostic subpath that standardizes how apps define and
 * type their "ports" (outbound dependencies like db, cache, event bus).
 *
 * This subpath provides:
 * - `definePorts` – helper to define a typed ports object
 * - `PortsContext` – a generic type that describes ctx objects that carry ports
 * - `EventBusPort` – interface for event bus implementations
 * - `JobDispatcherPort` – interface for job dispatch implementations
 * - `UnitOfWorkPort` – interface for app-owned transaction boundaries
 * - `OutboxPort` – interface for durable event/job delivery storage
 * - `IdempotencyPort` – interface for retry-safe command/key storage
 * - `AuthPort` – interface for request authentication implementations
 * - `AuditLogPort` – interface for audit/activity log implementations
 * - `ClockPort` – interface for deterministic time
 * - `EntitlementsPort` – interface for product access checks
 * - `IdGeneratorPort` – interface for deterministic id generation
 * - `LoggerPort` – interface for structured application logging
 * - `GatePort` – interface for application authorization policies
 * - `RateLimitPort` – interface for rate limiting implementations
 * - `CachePort` – interface for cache implementations
 * - `StoragePort` – interface for object/file storage implementations
 * - `FlagsPort` – interface for feature flag evaluation implementations
 * - `ErrorReporterPort` – interface for production error reporting
 * - `LocksPort` – interface for lease-backed distributed locks
 *
 * Dedicated framework areas own their capability-specific APIs:
 * - `@beignet/core/entitlements` owns product access helpers and test adapters
 * - `@beignet/core/error-reporting` owns error reporting helpers and test adapters
 * - `@beignet/core/flags` owns feature flag helpers and test adapters
 * - `@beignet/core/idempotency` owns idempotency helpers and test adapters
 * - `@beignet/core/locks` owns lease-backed lock helpers and test adapters
 * - `@beignet/core/mail` owns `MailerPort` and mail test adapters
 * - `@beignet/core/notifications` owns notification helpers and test adapters
 * - `@beignet/core/outbox` owns durable outbox helpers and test adapters
 * - `@beignet/core/payments` owns `PaymentsPort` and payment test adapters
 * - `@beignet/core/schedules` owns schedule definitions and runners
 * - `@beignet/core/webhooks` owns inbound webhook definitions and verifiers
 */

import { createUnboundPort } from "./unbound.js";

/**
 * A generic map of named "ports" (outbound dependencies) that your
 * application depends on: db, mailer, cache, event bus, etc.
 *
 * This is intentionally very loose: users define the exact shape via
 * `definePorts(...)`.
 */
export type AnyPorts = Record<string, unknown>;

/**
 * Definition accepted by the curried `definePorts<P>()(...)` form.
 */
export type DeferredPortsDefinition<
  P extends AnyPorts,
  Deferred extends readonly (keyof P & string)[],
> = {
  /**
   * Ports the app binds directly. Optional keys of `P` may be omitted here
   * and contributed by providers instead.
   */
  bound: Omit<P, Deferred[number]>;
  /**
   * Port keys that providers contribute during server startup. Deferred keys
   * boot as throwing placeholders; `createServer(...)` fails startup if any
   * are still unbound after providers have started (see `onUnboundPorts`).
   */
  deferred: Deferred;
};

/**
 * Define the set of ports (outbound dependencies) for your application.
 *
 * The identity form captures the exact shape of the provided `ports` object
 * so you can export `type AppPorts = typeof initialPorts`.
 *
 * The curried form, `definePorts<AppPorts>()({ bound, deferred })`, declares
 * which port keys providers contribute at server startup. Deferred keys boot
 * as throwing placeholders instead of hand-written stubs, and
 * `createServer(...)` validates after provider startup that nothing is left
 * unbound. Optional keys of `AppPorts` may go in either bucket.
 *
 * @example
 * ```ts
 * // Identity form: every port is bound directly.
 * const initialPorts = definePorts({
 *   db: dbAdapter,
 *   mailer: mailerAdapter,
 * });
 * export type AppPorts = typeof initialPorts;
 *
 * // Deferred form: providers contribute the rest at startup.
 * export const initialPorts = definePorts<AppPorts>()({
 *   bound: { gate },
 *   deferred: ["db", "mailer", "storage"],
 * });
 * ```
 */
export function definePorts<P extends AnyPorts>(ports: P): P;
export function definePorts<P extends AnyPorts>(): <
  const Deferred extends readonly (keyof P & string)[],
>(
  definition: DeferredPortsDefinition<P, Deferred>,
) => P;
export function definePorts<P extends AnyPorts>(
  ports?: P,
):
  | P
  | ((
      definition: DeferredPortsDefinition<P, readonly (keyof P & string)[]>,
    ) => P) {
  if (ports !== undefined) {
    return ports;
  }

  return (definition) => {
    const result: AnyPorts = { ...(definition.bound as AnyPorts) };
    for (const key of definition.deferred) {
      result[key] = createUnboundPort(key);
    }
    return result as P;
  };
}

/**
 * A small helper type describing a context object that carries `ports`.
 *
 * You typically use this to define your application context:
 *
 * @example
 * ```ts
 * import type { PortsContext } from "@beignet/core/ports";
 * import type { AppPorts } from "./core/ports";
 *
 * export interface AppCtx extends PortsContext<AppPorts> {
 *   user: { id: string } | null;
 *   now: () => Date;
 *   appError: AppErrorCreator<typeof errors>;
 * }
 * ```
 */
export interface PortsContext<P extends AnyPorts = AnyPorts> {
  ports: P;
}

/**
 * Entitlement port exports.
 */
export type {
  CreateEntitlementsOptions,
  CreateStaticEntitlementsOptions,
  EntitlementAllowedDecision,
  EntitlementCheckInput,
  EntitlementDecision,
  EntitlementDeniedDecision,
  EntitlementKey,
  EntitlementResolver,
  EntitlementResolverResult,
  EntitlementSubject,
  EntitlementsContext,
  EntitlementsPort,
  RequireEntitlementOptions,
  StaticEntitlementGrantMap,
} from "../entitlements/index.js";
/**
 * Entitlement helper exports.
 */
export {
  allowEntitlement,
  createEntitlements,
  createStaticEntitlements,
  denyEntitlement,
  EntitlementRequiredError,
  requireEntitlement,
} from "../entitlements/index.js";
/**
 * Error reporting port exports.
 */
export type {
  ErrorReportContext,
  ErrorReporterFlushOptions,
  ErrorReporterPort,
  ErrorReportJsonValue,
  ErrorReportLevel,
  ErrorReportOptions,
  ErrorReportResult,
  ErrorReportTags,
  ErrorReportUser,
  MemoryErrorReport,
  MemoryErrorReporterPort,
  MemoryReportedException,
  MemoryReportedMessage,
} from "../error-reporting/index.js";
/**
 * Error reporting helper exports.
 */
export {
  createMemoryErrorReporter,
  createNoopErrorReporter,
  reportException,
  reportMessage,
} from "../error-reporting/index.js";
/**
 * Feature flag port exports.
 */
export type {
  FlagDef,
  FlagEvaluationContext,
  FlagEvaluationDetails,
  FlagEvaluationOptions,
  FlagExposureOptions,
  FlagsPort,
  FlagTrackOptions,
  FlagValue,
  MemoryFlagsPort,
} from "../flags/index.js";
/**
 * Feature flag helper exports.
 */
export {
  createMemoryFlags,
  createStaticFlags,
  defineFlag,
  defineFlags,
  evaluateFlag,
  getFlagDetails,
} from "../flags/index.js";
/**
 * Idempotency port exports.
 */
export type {
  IdempotencyCompleteInput,
  IdempotencyFailInput,
  IdempotencyPort,
  IdempotencyReservation,
  IdempotencyReserveInput,
} from "../idempotency/index.js";
/**
 * Lease-backed lock port exports.
 */
export type {
  CreateMemoryLocksOptions,
  LeaseAcquireOptions,
  LeaseAcquireResult,
  LeaseHandle,
  LeaseMetadata,
  LeaseRenewOptions,
  LocksPort,
  MemoryLeaseRecord,
  MemoryLocksPort,
  MemoryLocksProviderOptions,
  MemoryLocksProviderPorts,
} from "../locks/index.js";
/**
 * Lease-backed lock helper exports.
 */
export {
  acquireLease,
  createMemoryLocks,
  createMemoryLocksProvider,
  LeaseOptionsError,
  withLease,
} from "../locks/index.js";
/**
 * Notification port exports.
 */
export type {
  MemoryNotificationDelivery,
  MemoryNotificationPort,
  NotificationChannelResult,
  NotificationPort,
  SendNotificationOptions,
  SendNotificationResult,
} from "../notifications/index.js";
/**
 * Transactional outbox port exports.
 */
export type {
  ClaimedOutboxMessage,
  OutboxAdminPort,
  OutboxClaimBatchOptions,
  OutboxCountMessagesOptions,
  OutboxDeleteResult,
  OutboxEnqueueInput,
  OutboxListMessagesOptions,
  OutboxMarkDeliveredInput,
  OutboxMarkFailedInput,
  OutboxMessage,
  OutboxMessageKind,
  OutboxMessageQuery,
  OutboxMessageStatus,
  OutboxPort,
  OutboxPruneDeliveredInput,
  OutboxPurgeDeadLetteredInput,
  OutboxRequeueMessageInput,
} from "../outbox/index.js";
/**
 * Payments port exports.
 */
export type {
  BillingPortalSession,
  CheckoutSession,
  CreateBillingPortalSessionInput,
  CreateCheckoutSessionInput,
  CreateRefundInput,
  MemoryBillingPortalSession,
  MemoryCheckoutSession,
  MemoryPaymentsPort,
  MemoryRefund,
  PaymentCheckoutLineItem,
  PaymentCheckoutMode,
  PaymentMetadata,
  PaymentRefundReason,
  PaymentsPort,
  PaymentWebhookEvent,
  PaymentWebhookRawBody,
  Refund,
  VerifyPaymentWebhookInput,
} from "../payments/index.js";
/**
 * Payments helper exports.
 */
export {
  createMemoryPayments,
  createMemoryPaymentsProvider,
  PaymentProviderError,
} from "../payments/index.js";
/**
 * Search port exports.
 *
 * Search has a dedicated subpath. Re-export the common app port types and
 * helpers here so apps can import shared port surfaces from one place.
 */
export type {
  DefineSearchIndexOptions,
  MemorySearchIndexState,
  MemorySearchPort,
  MemorySearchProviderOptions,
  MemorySearchProviderPorts,
  SearchDeleteResult,
  SearchDocument,
  SearchDocumentBase,
  SearchFilters,
  SearchFilterValue,
  SearchIndexDef,
  SearchIndexResult,
  SearchPort,
  SearchPrimitive,
  SearchQuery,
  SearchResultPage,
  SearchResults,
  SearchSort,
  SearchValue,
} from "../search/index.js";
/**
 * Search helper exports.
 */
export {
  createMemorySearch,
  createMemorySearchProvider,
  defineSearchIndex,
  indexSearchDocuments,
  SearchOptionsError,
  searchDocuments,
} from "../search/index.js";
/**
 * Tenant scope exports.
 */
export type { TenantScope } from "../tenancy/index.js";
export {
  createTenantScope,
  requireTenantScope,
  tenantScopeId,
} from "../tenancy/index.js";
/**
 * Webhook exports.
 *
 * Webhooks have a dedicated subpath. Re-export the common app-facing
 * definitions and helpers here so production concerns can be imported from one
 * shared port toolbox when useful.
 */
export type {
  CreateHmacWebhookVerifierOptions,
  CreateMemoryWebhookVerifierOptions,
  DefineWebhookOptions,
  InferSchemaOutput,
  InferWebhookEvent,
  MemoryWebhookVerifier,
  VerifyWebhookInput,
  VerifyWebhookOptions,
  WebhookDef,
  WebhookEvent,
  WebhookEventSchemas,
  WebhookHeaders,
  WebhookRawBody,
  WebhookVerifier,
} from "../webhooks/index.js";
/**
 * Webhook helper exports.
 */
export {
  createHmacWebhookVerifier,
  createMemoryWebhookVerifier,
  defineWebhook,
  parseWebhookEvent,
  verifyWebhook,
  WebhookOptionsError,
  WebhookValidationError,
  WebhookVerificationError,
} from "../webhooks/index.js";
/**
 * Audit log port exports.
 */
export type {
  ActivityActor,
  ActivityActorType,
  ActivityMetadata,
  ActivityMetadataValue,
  ActivityResource,
  ActivityTenant,
  AuditLogEntry,
  AuditLogEntryInput,
  AuditLogOptions,
  AuditLogPort,
  AuditOutcome,
  InstrumentedAuditLogOptions,
  MemoryAuditLogPort,
} from "./audit.js";
/**
 * Audit log helper exports.
 */
export {
  createAnonymousActor,
  createInstrumentedAuditLog,
  createMemoryAuditLog,
  createRedactedAuditLog,
  createServiceActor,
  createSystemActor,
  createTenant,
  createUserActor,
  normalizeAuditLogEntry,
  redactAuditLogEntry,
} from "./audit.js";
/**
 * Auth port exports.
 */
export type {
  AuthPort,
  AuthRequestLike,
  AuthSession,
  RequireOptions,
  StaticAuthSessionFactory,
} from "./auth.js";
/**
 * Auth helper exports.
 */
export {
  AuthUnauthorizedError,
  createAnonymousAuth,
  createStaticAuth,
  requireSession,
  requireTenant,
  requireTenantId,
  requireUser,
  requireUserId,
  TenantRequiredError,
} from "./auth.js";
/**
 * Ports builder exports.
 */
export {
  createPortsBuilder,
  type PortsBuilder,
  type PortsOf,
} from "./builder.js";
/**
 * Cache port exports.
 */
export type { CachePort, CacheSetOptions } from "./cache.js";
/**
 * Cache helper exports.
 */
export { createMemoryCache } from "./cache.js";
/**
 * Clock port exports.
 */
export type { ClockPort, FrozenClockPort } from "./clock.js";
/**
 * Clock helper exports.
 */
export { createFrozenClock, createSystemClock } from "./clock.js";
/**
 * Event bus and job dispatcher port exports.
 */
export type {
  DomainEventDef,
  EventBusPort,
  InferEventPayload,
  InferJobPayload,
  JobDef,
  JobDispatcherPort,
} from "./events.js";
/**
 * ID generator port exports.
 */
export type {
  IdGeneratorPort,
  SequenceIdGeneratorPort,
} from "./id-generator.js";
/**
 * ID generator helper exports.
 */
export {
  createSequenceIdGenerator,
  createUuidIdGenerator,
} from "./id-generator.js";
/**
 * Logger port exports.
 */
export type {
  LoggerPort,
  LogLevel,
  MemoryLogEntry,
  MemoryLoggerPort,
} from "./logger.js";
/**
 * Logger helper exports.
 */
export { createMemoryLogger, createNoopLogger } from "./logger.js";
/**
 * Policy and authorization gate type exports.
 */
export type {
  BoundGate,
  CreateGateOptions,
  GateAllowedDecision,
  GateContext,
  GateDecision,
  GateDecisionObservation,
  GateDecisionObserver,
  GateDecisionSource,
  GateDeniedDecision,
  GateDenyHandler,
  GatePolicyResult,
  GatePort,
  PolicyBatch,
  PolicyBatchBooleanMap,
  PolicyBatchCheck,
  PolicyBatchDecisionMap,
  PolicyContextFromDefinitions,
  PolicyDefinition,
  PolicyMapFromDefinitions,
  PolicyResolver,
  PolicySubjectArgs,
} from "./policy.js";
/**
 * Policy and authorization gate helper exports.
 */
export {
  allow,
  createGate,
  definePolicy,
  deny,
  GateAuthorizationError,
} from "./policy.js";
/**
 * Rate limit port exports.
 */
export type {
  RateLimitHitOptions,
  RateLimitPort,
  RateLimitResult,
} from "./rate-limit.js";
/**
 * Rate limit helper exports.
 */
export { createMemoryRateLimiter } from "./rate-limit.js";
/**
 * Redaction helper exports.
 */
export {
  createRedactor,
  DEFAULT_CIRCULAR_VALUE,
  DEFAULT_REDACTED_VALUE,
  DEFAULT_SENSITIVE_KEY_TERMS,
  DEFAULT_SENSITIVE_KEYS,
  DEFAULT_TRUNCATED_VALUE,
  isSensitiveKey,
  type RedactableHeaders,
  type RedactionDecisionContext,
  type RedactionOptions,
  type Redactor,
  redactHeaders,
  redactValue,
} from "./redaction.js";
/**
 * Storage port exports.
 */
export type {
  CreateStoragePublicUrlOptions,
  MemoryStorageOptions,
  PrefixStorageKeyOptions,
  StorageBody,
  StorageMetadata,
  StorageObject,
  StorageObjectBody,
  StoragePort,
  StoragePutOptions,
  StorageVisibility,
} from "./storage.js";
/**
 * Storage helper exports.
 */
export {
  assertValidStorageKey,
  createMemoryStorage,
  createStoragePublicUrl,
  normalizeStorageKeyPrefix,
  prefixStorageKey,
} from "./storage.js";
/**
 * Unbound (deferred) port helper exports.
 */
export { createUnboundPort, isUnboundPort } from "./unbound.js";
/**
 * Unit of Work port exports.
 */
export {
  type BufferedDomainEventRecorder,
  createDomainEventRecorder,
  createNoopUnitOfWork,
  createObservedUnitOfWork,
  type DomainEventRecorderPort,
  type NoopUnitOfWorkOptions,
  type ObservedUnitOfWorkOptions,
  type RecordedDomainEvent,
  type UnitOfWorkCallback,
  type UnitOfWorkPort,
} from "./unit-of-work.js";
