import { Provider } from '@near-js/providers';
import { SerializedReturnValue, BlockReference, TxExecutionStatus } from '@near-js/types';

interface TcbInfo {
    mrtd: string;
    rtmr0: string;
    rtmr1: string;
    rtmr2: string;
    rtmr3: string;
    os_image_hash: string;
    compose_hash: string;
    device_id: string;
    app_compose: string;
    event_log: EventLog[];
}
interface EventLog {
    imr: number;
    event_type: number;
    digest: string;
    event: string;
    event_payload: string;
}

interface DstackAttestationForContract {
    quote: number[];
    collateral: {
        pck_crl_issuer_chain: string;
        root_ca_crl: string;
        pck_crl: string;
        tcb_info_issuer_chain: string;
        tcb_info: string;
        tcb_info_signature: string;
        qe_identity_issuer_chain: string;
        qe_identity: string;
        qe_identity_signature: string;
    };
    tcb_info: TcbInfo;
}

interface Measurements {
    /** MRTD (Measurement of Root of Trust for Data) - identifies the virtual firmware. */
    mrtd: string;
    /** RTMR0 (Runtime Measurement Register 0) - typically measures the bootloader, virtual firmware data, and configuration. */
    rtmr0: string;
    /** RTMR1 (Runtime Measurement Register 1) - typically measures the OS kernel, boot parameters, and initrd (initial ramdisk). */
    rtmr1: string;
    /** RTMR2 (Runtime Measurement Register 2) - typically measures the OS application. */
    rtmr2: string;
}
interface FullMeasurements {
    /** Expected RTMRs (Runtime Measurement Registers). */
    rtmrs: Measurements;
    /** Expected digest for the key-provider event. */
    key_provider_event_digest: string;
    /** Expected app_compose hash payload. */
    app_compose_hash_payload: string;
}
/**
 * Configuration object for creating a ShadeClient instance
 */
interface ShadeConfig {
    /** Network ID ('testnet' or 'mainnet'), defaults to 'testnet' if not provided */
    networkId?: "testnet" | "mainnet";
    /** The NEAR contract ID for the agent contract */
    agentContractId?: string;
    /** Sponsor account configuration for funding the agent account */
    sponsor?: {
        /** The sponsor's NEAR account ID */
        accountId: string;
        /** The sponsor's private key */
        privateKey: string;
    };
    /** Custom NEAR RPC provider. If not provided, a default provider will be created based on networkId */
    rpc?: Provider;
    /** Number of keys to use for the agent (1-100), defaults to 1 if not provided */
    numKeys?: number;
    /** Derivation path for deterministic key generation for local testing (needs to be a randomly unique string)*/
    derivationPath?: string;
}
declare class ShadeClient {
    private config;
    private dstackClient;
    private agentAccountId;
    private agentPrivateKeys;
    private currentKeyIndex;
    private keysDerivedWithRandom;
    private keysChecked;
    private constructor();
    /**
     * Creates a new ShadeClient instance asynchronously
     * @param config - Configuration object for the Shade client (see ShadeConfig interface for details)
     * @returns Promise that resolves to a ShadeClient instance
     * @throws Error if configuration is invalid, network ID mismatch, or key generation fails
     */
    static create(config: ShadeConfig): Promise<ShadeClient>;
    /**
     * Gets the NEAR account ID of the agent
     * @returns The agent's account ID
     */
    accountId(): string;
    /**
     * Gets the NEAR balance of the agent account in human readable format (e.g. 1 = one NEAR)
     * @returns Promise that resolves to the account balance in NEAR tokens, if the agent account does not exist, returns 0
     * @throws Error if network request fails
     */
    balance(): Promise<number>;
    /**
     * Registers the agent in the agent contract.
     *
     * @param params
     * @param params.deposit Attached deposit in yoctoNEAR when storage is required or when `forceDeposit` is `true` (defaults to `5000000000000000000000` — 0.005 NEAR)
     * @param params.forceDeposit If `true`, always attach `deposit` (or the default) and skip `get_agent`. If `false`, attach no deposit and skip `get_agent`. If omitted, use `get_agent` to decide.
     * @returns Promise that resolves to true if registration was successful
     * @throws Error if agentContractId is not configured, if fetching attestation fails, or if the contract call fails
     */
    register(params?: {
        deposit?: bigint | string | number;
        forceDeposit?: boolean;
    }): Promise<boolean>;
    /**
     * Call a view function on the agent contract and return the result
     * @param params
     * @param params.methodName The method that will be called
     * @param params.args Arguments as a valid JSON Object
     * @param params.blockQuery (optional) Block reference for the query
     * @returns A promise that resolves with the result of the view function call
     * @throws Error if agentContractId is not configured or if RPC call fails
     */
    view<T extends SerializedReturnValue>(params: {
        methodName: string;
        args: Record<string, unknown>;
        blockQuery?: BlockReference;
    }): Promise<T>;
    /**
     * Call a function on the agent contract and return the result
     * @param params
     * @param params.methodName The method that will be called
     * @param params.args Arguments, either as a valid JSON Object or a raw Uint8Array
     * @param params.deposit (optional) Amount of NEAR Tokens to attach to the call
     * @param params.gas (optional) Amount of GAS to use attach to the call
     * @param params.waitUntil (optional) Transaction finality to wait for
     * @returns A promise that resolves with the result of the contract function call
     * @throws Error if agentContractId is not configured, if key derivation fails, or if transaction fails
     */
    call<T extends SerializedReturnValue>(params: {
        methodName: string;
        args: Uint8Array | Record<string, any>;
        deposit?: bigint | string | number;
        gas?: bigint | string | number;
        waitUntil?: TxExecutionStatus;
    }): Promise<T>;
    /**
     * Gets the TEE attestation for the agent in contract format (ready to be sent to the contract)
     * @returns Promise that resolves to the contract-formatted attestation object
     * @throws Error if fetching quote collateral fails (network errors, HTTP errors, timeouts)
     */
    getAttestation(): Promise<DstackAttestationForContract>;
    /**
     * Funds the agent account with NEAR tokens from the sponsor account
     * @param fundAmount - Amount of NEAR tokens to transfer to the agent account in human readable format (e.g. 1 = one NEAR)
     * @returns Promise that resolves when funding is complete
     * @throws Error if sponsor is not configured or if transfer fails after retries
     */
    fund(fundAmount: number): Promise<void>;
    /**
     * Gets the agent's private keys (use with caution)
     * @param params - Must pass `{ acknowledgeRisk: true }`
     * @returns Array of private key strings
     */
    getPrivateKeys(params: {
        acknowledgeRisk: true;
    }): string[];
    /**
     * Checks if the agent is whitelisted for local mode
     * @returns Promise that resolves to true if the agent is whitelisted, false if the agent is not whitelisted, or null if the agent contract requires TEE
     * @throws Error if agentContractId is not configured or if view call fails
     */
    isWhitelisted(): Promise<boolean | null>;
}

/**
 * Error / sanitisation utilities. The single trust boundary for secret leak
 * prevention in shade-agent-js: every catch in the package should rethrow
 * via `toThrowable(e)` so that sensitive fields and recognised secret value
 * patterns are redacted before the error escapes.
 *
 * Fail-closed rule: if any value can't be safely processed (hostile getter,
 * throwing Proxy, deep-redact crash, …), it is replaced with the
 * `[unsanitisable]` placeholder string so operators can see that
 * something was there but couldn't be sanitised. The unsanitised
 * original is NEVER propagated. The only exception is the final
 * `toThrowable` boundary, which must return a real Error — there it
 * falls back to a generic "An error occurred" message.
 *
 * File layout — six sections, top to bottom:
 *   1. Redaction policy   — which field names + value patterns count as secrets.
 *   2. Redactor engine    — the mutable deep-redact instance + extension API.
 *   3. Sanitiser          — walks any value, redacts secrets, marks unsanitisables.
 *   4. Public throw API   — toThrowable + genericError.
 *   5. Retry              — defaultRetryable + withRetry + helpers.
 *   6. Safe key parsing   — safeParseKeyPair / safeParseSigner.
 */

/** Shape of a value-pattern entry: a regex to test, plus a replacer function. */
interface StringTest {
    pattern: RegExp;
    replacer: (value: string, pattern: RegExp) => string;
}
/**
 * Extend the redaction config at runtime. After this returns, subsequent
 * sanitize/toThrowable calls also redact the new field names and apply
 * the new value patterns. Mutation is process-global — call once at boot.
 */
declare function addSensitive(opts: {
    keys?: string[];
    patterns?: StringTest[];
}): void;
/**
 * Sanitise any value. Type-routed:
 *   - primitives (number, boolean, bigint, symbol, null, undefined)
 *     → returned as-is (nothing to redact)
 *   - string  → value-pattern redaction applied
 *   - Error   → routed through `sanitizeError`
 *   - object  → deep-redact walks string keys; symbol-keyed properties are dropped
 *
 * Marks on uncertainty: if the value is so exotic the redactor can't
 * process it (hostile Proxy, throwing prototype trap), returns the
 * `"[unsanitisable]"` placeholder string instead of the original value.
 * The unsanitised value is never propagated.
 */
declare function sanitize(value: unknown): unknown;
/**
 * Take any thrown value, return a safe Error to rethrow.
 *
 *     try { ... } catch (e) { throw toThrowable(e); }
 *
 * Never throws, even on circular structures, BigInt
 * values, hostile Proxies, or other exotic shapes. If sanitisation
 * dropped the input entirely, returns `new Error("An error occurred")`
 * rather than echoing anything potentially unsafe.
 */
declare function toThrowable(error: unknown): Error;

export { type DstackAttestationForContract, type FullMeasurements, type Measurements, ShadeClient, type ShadeConfig, addSensitive, sanitize, toThrowable };
