export type X402JsonPrimitive = string | number | boolean | null;

export type X402JsonValue =
  | X402JsonPrimitive
  | X402JsonValue[]
  | X402JsonObject;

export type X402JsonObject = {
  [key: string]: X402JsonValue;
};

export type X402Awaitable<Value> = Value | PromiseLike<Value>;
export type X402Digest = `sha256:${string}`;
export type X402EvmAddress = `0x${string}`;
export type X402TransactionHash = `0x${string}`;
export type X402Eip155Network = `eip155:${string}`;
export type X402EmptyExtensions = Record<string, never>;

export const X402_GATE_ADAPTER_VERSION: "2.0.0";
export const X402_EXECUTION_PROFILE:
  "MANDATESHIELD_X402_V2_EXACT_EIP3009_V1";
export const X402_PROVIDER_PERMIT_PROFILE: "X402_V2_EXACT";
export const SIGNED_EXECUTION_PERMIT_MODE:
  "SIGNED_EXECUTION_PERMIT_V1";

export interface MandateShieldX402ErrorOptions {
  cause?: unknown;
  code?: string;
  retryable?: boolean;
  details?: unknown;
}

export class MandateShieldX402Error extends Error {
  constructor(message: string, options?: MandateShieldX402ErrorOptions);
  code: string;
  retryable: boolean;
  details: unknown | null;
}

export type X402HttpMethod =
  | "GET"
  | "HEAD"
  | "POST"
  | "PUT"
  | "PATCH"
  | "DELETE";

export type X402RequirementExtra = {
  assetTransferMethod?: "eip3009";
  name: string;
  version: string;
};

export type X402PaymentRequirement = {
  scheme: "exact";
  network: X402Eip155Network;
  asset: X402EvmAddress;
  amount: string;
  payTo: X402EvmAddress;
  maxTimeoutSeconds: number;
  extra: X402RequirementExtra;
};

export type X402ResourceDescription = {
  url: string;
};

export type X402PaymentRequired = {
  x402Version: 2;
  resource: X402ResourceDescription;
  accepts: X402PaymentRequirement[];
  extensions?: X402EmptyExtensions;
};

export type X402Eip3009Authorization = {
  from: X402EvmAddress;
  to: X402EvmAddress;
  value: string;
  validAfter: string;
  validBefore: string;
  nonce: `0x${string}`;
};

export type X402Eip3009Payload = {
  signature: `0x${string}`;
  authorization: X402Eip3009Authorization;
};

export type X402PaymentPayload = {
  x402Version: 2;
  resource: X402ResourceDescription;
  accepted: X402PaymentRequirement;
  payload: X402Eip3009Payload;
  extensions?: X402EmptyExtensions;
};

export interface X402V2Client {
  createPaymentPayload(
    paymentRequired: X402PaymentRequired,
  ): X402Awaitable<unknown>;
}

export interface X402TrustedAsset {
  network: X402Eip155Network;
  asset: X402EvmAddress;
  name: string;
  version: string;
  asset_decimals: number;
}

export interface X402TrustedPayee {
  merchant_id: string;
  network: X402Eip155Network;
  pay_to: X402EvmAddress;
  resource_origin: string;
}

export interface X402TrustedPayer {
  network: X402Eip155Network;
  asset: X402EvmAddress;
  payer: X402EvmAddress;
}

export type X402RequestProjection = {
  url: string;
  method: X402HttpMethod;
  headers: Record<string, string>;
  body_base64?: string;
  body_sha256: X402Digest;
  headers_sha256: X402Digest;
};

export type X402HttpRequestBody =
  | string
  | Uint8Array
  | ArrayBuffer;

export interface X402HttpRequestBindingInput {
  url: string;
  method: X402HttpMethod;
  headers?: Record<string, string>;
  body?: X402HttpRequestBody;
  allowedRequestHeaders?: Iterable<string>;
  allowInsecureLocalhost?: boolean;
}

export interface X402HttpRequestBinding {
  readonly request: Readonly<X402RequestProjection>;
  readonly http_request: Readonly<X402EnvelopeHttpRequest>;
}

export function createX402HttpRequestBinding(
  input: X402HttpRequestBindingInput,
): Promise<Readonly<X402HttpRequestBinding>>;

export type X402ProviderInput = {
  profile: typeof X402_EXECUTION_PROFILE;
  payment_required: X402PaymentRequired;
  selected_accept_index: number;
  request: X402RequestProjection;
};

export type X402PayeeIdentity = {
  profile: "MANDATESHIELD_PAYEE_IDENTITY_V1";
  provider: "X402";
  merchant_id: string;
  binding: {
    network: X402Eip155Network;
    pay_to: X402EvmAddress;
  };
  verification: {
    method: "TRUSTED_MERCHANT_MAPPING";
    verifier: string;
    evidence_ref: string;
  };
};

export type X402EnvelopeAmount = {
  atomic_units: string;
  asset_decimals: number;
};

export type X402EnvelopeHttpRequest = {
  profile: typeof X402_EXECUTION_PROFILE;
  url: string;
  method: X402HttpMethod;
  redirect_policy: "ERROR";
  body_sha256: X402Digest;
  headers_sha256: X402Digest;
};

export type X402GatewayEnvelope = {
  protocol: "X402";
  merchant_id: string;
  amount: X402EnvelopeAmount;
  asset_id: X402EvmAddress;
  network: X402Eip155Network;
  resource: string;
  payee_identity: X402PayeeIdentity;
  http_request: X402EnvelopeHttpRequest;
};

export interface X402ProviderBindingContext {
  receipt_id: string;
  envelope: X402GatewayEnvelope;
  expected_audience: string;
  create_idempotency_key: string;
  confirm_idempotency_key: string;
  provider_input: X402ProviderInput;
}

export type X402ProviderPermitBinding = {
  profile: typeof X402_PROVIDER_PERMIT_PROFILE;
  environment: "test" | "live";
  account: string;
  request_id: string;
  /** Exact pay_to address from the validated signed payee_identity. */
  payee_destination: X402EvmAddress;
  method: "GET" | "POST" | "PUT" | "PATCH";
  resource: string;
  body_digest: X402Digest;
};

export type X402ExecutionPermit = {
  format: "application/mandateshield-execution-permit+jwt";
  compact: string;
  permit_id: `msp_${string}`;
  key_id: string;
  jwks_uri: "https://mandateshield.com/.well-known/jwks.json";
  verify_uri:
    "https://mandateshield.com/api/v2/execution-permits/verify";
  redemption_uri:
    "https://mandateshield.com/api/v2/execution-permits/redeem";
  expires_at: number;
  online_redemption_required: true;
  offline_one_use_enforced: false;
};

export interface X402ValidatedProviderBindingContext
  extends X402ProviderBindingContext {
  execution_mode: typeof SIGNED_EXECUTION_PERMIT_MODE;
  provider_binding: X402ProviderPermitBinding;
}

export interface X402ProviderExecutionContext
  extends X402ValidatedProviderBindingContext {
  settlement_deadline_at: number;
  recovery_started_at: string;
  execution_permit: X402ExecutionPermit;
  provider_submission_permitted: boolean;
  provider_idempotency_key?: string;
  permit_claim_id?: `mspc_${string}`;
  provider_reference?: string;
}

export interface X402ProviderSubmissionContext
  extends X402ProviderExecutionContext {
  provider_submission_permitted: true;
  provider_idempotency_key: string;
  permit_claim_id: `mspc_${string}`;
}

export type X402ArtifactState =
  | "SIGNED"
  | "TRANSMITTING"
  | "RESPONSE_REPORTED"
  | "PENDING"
  | "CONFIRMED"
  | "UNUSED_EXPIRED"
  | "UNKNOWN";

export type X402ReportedSettlement = {
  success: boolean;
  transaction: string;
  network: string;
  payer?: string;
  amount?: string;
};

export interface X402ArtifactRecord {
  id: string;
  version: number;
  state: X402ArtifactState;
  binding_digest: X402Digest;
  receipt_id: string;
  payload_digest: X402Digest;
  authorization_digest: X402Digest;
  authorization_claim_key: string;
  request_digest: X402Digest;
  payer: X402EvmAddress;
  nonce: `0x${string}`;
  valid_after: string;
  valid_before: string;
  settlement_deadline_at: number;
  submission_anchor_requested_at: string;
  submission_anchor_accepted_at: string;
  submission_anchor: X402SubmissionAnchor;
  payment_payload: X402PaymentPayload;
  transmission_started_at?: string;
  reconciliation_started_at?: string;
  response_status?: number;
  settlement_response?: X402ReportedSettlement | null;
  verifier_result?: X402SettlementVerification;
  provider_reference?: string;
  created_at: string;
  updated_at: string;
}

export interface X402ArtifactBeginResult {
  created: boolean;
  record: X402ArtifactRecord;
}

export interface X402ArtifactCompareAndSetInput {
  id: string;
  expected_version: number;
  expected_state: X402ArtifactState;
  record: X402ArtifactRecord;
}

export interface X402UniqueAuthorizationClaimInput {
  authorization_claim_key: string;
  artifact_id: string;
  binding_digest: X402Digest;
  receipt_id: string;
  claimed_at: string;
}

export interface X402UniqueAuthorizationClaimResult {
  authorization_claim_key: string;
  owner_artifact_id: string;
}

/**
 * Customer-provided storage contract for signed payment credentials. The
 * declaration describes the required callback semantics but cannot establish
 * storage durability, encryption, isolation, or atomicity.
 */
export interface DurableX402ArtifactJournal {
  readonly durable: true;
  /**
   * A customer declaration that every executor uses one globally shared,
   * linearizable namespace. Omission fails closed. The declaration is not an
   * independent storage attestation; split-brain deployments remain unsafe.
   */
  readonly consistency: "GLOBAL_SHARED_LINEARIZABLE";
  /**
   * Atomically inserts a missing nonce claim and returns its current owner.
   * Returning the same owner makes a retry idempotent; a different owner
   * prevents this execution from reusing that signed authorization.
   */
  claimUniqueAuthorization(
    input: X402UniqueAuthorizationClaimInput,
  ): Promise<X402UniqueAuthorizationClaimResult>;
  begin(record: X402ArtifactRecord): Promise<X402ArtifactBeginResult>;
  get(id: string): Promise<X402ArtifactRecord | null>;
  compareAndSet(
    input: X402ArtifactCompareAndSetInput,
  ): Promise<X402ArtifactRecord | null>;
}

export interface X402AuthorizationExpectation {
  network: X402Eip155Network;
  asset: X402EvmAddress;
  token_name: string;
  token_version: string;
  payer: X402EvmAddress;
  pay_to: X402EvmAddress;
  amount: string;
  nonce: `0x${string}`;
  valid_after: string;
  valid_before: string;
  authorization_digest: X402Digest;
}

export interface X402AuthorizationVerifierInput {
  profile: typeof X402_EXECUTION_PROFILE;
  payment_payload: X402PaymentPayload;
  selected_requirement: X402PaymentRequirement;
  expected: X402AuthorizationExpectation;
}

export type X402AuthorizationVerifierResult =
  | {
      valid: true;
      recovered_payer: X402EvmAddress;
    }
  | {
      valid: false;
      recovered_payer?: X402EvmAddress;
    };

export type X402AuthorizationVerifier = (
  input: X402AuthorizationVerifierInput,
) => X402Awaitable<X402AuthorizationVerifierResult>;

export type X402SubmissionAnchor = {
  status: "NONCE_UNUSED_ANCHOR";
  canonical: true;
  latest_canonical_block: true;
  nonce_unused: true;
  nonce_state_query: "BLOCK_HASH_REQUIRE_CANONICAL";
  block_number: string;
  block_hash: X402TransactionHash;
  block_timestamp: string;
  network: X402Eip155Network;
  asset: X402EvmAddress;
  payer: X402EvmAddress;
  pay_to: X402EvmAddress;
  amount: string;
  nonce: `0x${string}`;
  valid_after: string;
  valid_before: string;
  authorization_digest: X402Digest;
  payload_digest: X402Digest;
  observed_at: string;
};

export type X402SubmissionAnchorExpectation = Pick<
  X402SubmissionAnchor,
  | "network"
  | "asset"
  | "payer"
  | "pay_to"
  | "amount"
  | "nonce"
  | "valid_after"
  | "valid_before"
  | "authorization_digest"
  | "payload_digest"
>;

export interface X402SubmissionAnchorVerifierInput {
  profile: typeof X402_EXECUTION_PROFILE;
  payment_payload: X402PaymentPayload;
  selected_requirement: X402PaymentRequirement;
  expected: X402SubmissionAnchorExpectation;
}

/**
 * Reads the current canonical head and queries nonce state at that exact block
 * hash with a require-canonical guard. It must have no payment side effects.
 */
export type X402SubmissionAnchorVerifier = (
  input: X402SubmissionAnchorVerifierInput,
) => X402Awaitable<X402SubmissionAnchor>;

export interface X402SettlementExpectation {
  network: X402Eip155Network;
  asset: X402EvmAddress;
  payer: X402EvmAddress;
  pay_to: X402EvmAddress;
  amount: string;
  nonce: `0x${string}`;
  valid_after: string;
  valid_before: string;
  authorization_digest: X402Digest;
  minimum_confirmations: number;
  payload_digest: X402Digest;
  settlement_deadline_at: number;
  submission_anchor: X402SubmissionAnchor;
}

export type X402ConfirmedSettlement = {
  status: "CONFIRMED";
  canonical: true;
  authorization_consumed: true;
  transfer_method: "transferWithAuthorization";
  confirmations: number;
  transaction: X402TransactionHash;
  block_number: string;
  block_hash: X402TransactionHash;
  block_timestamp: string;
  network: X402Eip155Network;
  asset: X402EvmAddress;
  payer: X402EvmAddress;
  pay_to: X402EvmAddress;
  amount: string;
  nonce: `0x${string}`;
  valid_after: string;
  valid_before: string;
  authorization_digest: X402Digest;
  payload_digest: X402Digest;
  submission_anchor_block_number: string;
  submission_anchor_block_hash: X402TransactionHash;
  submission_anchor_canonical_ancestor: true;
  observed_at: string;
};

export type X402UnusedExpiredAuthorization = {
  status: "UNUSED_EXPIRED";
  canonical: true;
  nonce_unused: true;
  confirmations: number;
  block_number: string;
  block_hash: X402TransactionHash;
  block_timestamp: string;
  network: X402Eip155Network;
  asset: X402EvmAddress;
  payer: X402EvmAddress;
  pay_to: X402EvmAddress;
  amount: string;
  nonce: `0x${string}`;
  valid_after: string;
  valid_before: string;
  authorization_digest: X402Digest;
  payload_digest: X402Digest;
  submission_anchor_block_number: string;
  submission_anchor_block_hash: X402TransactionHash;
  submission_anchor_canonical_ancestor: true;
  observed_at: string;
};

export type X402UnresolvedSettlement = {
  status: "PENDING" | "UNKNOWN";
  observed_at: string;
};

export type X402SettlementVerification =
  | X402ConfirmedSettlement
  | X402UnusedExpiredAuthorization
  | X402UnresolvedSettlement;

export interface X402SettlementVerifierInput {
  profile: typeof X402_EXECUTION_PROFILE;
  payment_payload: X402PaymentPayload;
  selected_requirement: X402PaymentRequirement;
  reported_settlement: X402ReportedSettlement | null;
  expected: X402SettlementExpectation;
}

export type X402SettlementVerifier = (
  input: X402SettlementVerifierInput,
) => X402Awaitable<X402SettlementVerification>;

export type X402ProviderOutcome =
  | "COMMITTED"
  | "FAILED"
  | "NOT_SUBMITTED"
  | "PENDING"
  | "UNKNOWN";

export type X402CommittedOrPendingProviderResult = {
  outcome: "COMMITTED" | "PENDING";
  reference: string;
  occurred_at: string;
  submission_fenced?: never;
};

export type X402FailedProviderResult = {
  outcome: "FAILED" | "NOT_SUBMITTED";
  reference: string;
  occurred_at: string;
  submission_fenced?: true;
};

export type X402UnknownProviderResult = {
  outcome: "UNKNOWN";
  reference?: string;
  occurred_at: string;
  submission_fenced?: never;
};

export type X402ProviderResult =
  | X402CommittedOrPendingProviderResult
  | X402FailedProviderResult
  | X402UnknownProviderResult;

export interface X402ResourceHandlingContext {
  artifact_id: string;
  payment_payload_digest: X402Digest;
  settlement_response: X402ReportedSettlement | null;
}

export type X402ResourceHandler = (
  response: Response,
  context: X402ResourceHandlingContext,
) => X402Awaitable<void>;

export interface X402V2ExactEip3009AdapterOptions {
  providerEnvironment: "test" | "live";
  /**
   * Stable, non-secret identifier for the customer-controlled x402 processing
   * account/configuration bound into every execution permit.
   */
  providerAccount: string;
  x402Client: X402V2Client;
  artifactJournal: DurableX402ArtifactJournal;
  verifyAuthorization: X402AuthorizationVerifier;
  captureSubmissionAnchor: X402SubmissionAnchorVerifier;
  verifySettlement: X402SettlementVerifier;
  trustedAssets: X402TrustedAsset[];
  trustedPayees: X402TrustedPayee[];
  trustedPayers: X402TrustedPayer[];
  fetch?: typeof globalThis.fetch;
  handleResource?: X402ResourceHandler;
  clock?: () => number;
  timeoutMs?: number;
  minimumConfirmations?: number;
  allowedRequestHeaders?: Iterable<string>;
  allowInsecureLocalhost?: boolean;
}

export interface X402V2ExactEip3009Adapter {
  readonly name: "MANDATESHIELD_X402_V2_EXACT_EIP3009";
  readonly payeeIdentityProvider: "X402";
  readonly executionMode: typeof SIGNED_EXECUTION_PERMIT_MODE;
  readonly referenceFreeReconcileAfterDeadline: true;
  createProviderBinding(
    context: X402ProviderBindingContext,
  ): Readonly<X402ProviderPermitBinding>;
  validateBinding(
    context: X402ValidatedProviderBindingContext,
  ): void;
  submit(
    context: X402ProviderSubmissionContext,
  ): Promise<X402ProviderResult>;
  reconcile(
    context: X402ProviderExecutionContext,
  ): Promise<X402ProviderResult>;
}

export function createX402V2ExactEip3009Adapter(
  options: X402V2ExactEip3009AdapterOptions,
): X402V2ExactEip3009Adapter;

export default createX402V2ExactEip3009Adapter;
