import { Account } from '@asentum/types';

/**
 * ClassicLevelDB-backed state store for AsentumChain accounts.
 *
 * Each account is stored at key `a:` + 20 raw address bytes, with the
 * value being the SSZ-encoded `Account`. Keys and values are both raw
 * bytes — no JSON, no hex encoding at the storage layer.
 *
 * This is a thin wrapper over `classic-level`. State commitment is
 * computed separately by `computeStateRoot` in `root.ts`.
 */

interface StateStoreOptions {
    /** Filesystem path to the ClassicLevelDB directory. */
    path: string;
}
/**
 * Persistent account state store. Use `open()` to initialize, `close()` to
 * release resources. Not safe for concurrent use from multiple processes.
 */
declare class StateStore {
    private readonly db;
    constructor(options: StateStoreOptions);
    /** Opens the underlying database. Must be called before any other operation. */
    open(): Promise<void>;
    /** Closes the underlying database. Safe to call multiple times. */
    close(): Promise<void>;
    /**
     * Returns the account at `address`, or `null` if none exists.
     *
     * @param address 20 raw address bytes.
     */
    getAccount(address: Uint8Array): Promise<Account | null>;
    /**
     * Convenience: returns the account at `address`, or a fresh empty account
     * if none exists. Use this when you want "read-or-default" semantics.
     */
    getOrCreate(address: Uint8Array): Promise<Account>;
    /**
     * Writes `account` as the state at `address`, overwriting any existing
     * value.
     *
     * @param address 20 raw address bytes.
     */
    setAccount(address: Uint8Array, account: Account): Promise<void>;
    /**
     * Deletes the account at `address`. Throws if no such account exists.
     *
     * @param address 20 raw address bytes.
     */
    deleteAccount(address: Uint8Array): Promise<void>;
    /**
     * Iterates all accounts in byte-lexicographic order of address.
     *
     * @dev Loads the entire account set into memory. Will need a streaming
     * or paginated variant once state grows large.
     */
    allAccounts(): Promise<Array<{
        address: Uint8Array;
        account: Account;
    }>>;
    /**
     * Computes the deterministic state root over all stored accounts.
     * Equivalent to collecting every entry and passing it to
     * `computeStateRoot`.
     */
    stateRoot(): Promise<Uint8Array>;
    /**
     * Returns the number of accounts currently stored. O(n) — iterates the
     * full account range.
     */
    accountCount(): Promise<number>;
    /**
     * Store contract source code keyed by its hash. Content-addressed: the
     * same source deployed twice shares storage.
     */
    putCode(codeHash: Uint8Array, source: Uint8Array): Promise<void>;
    /**
     * Retrieve contract source by its hash. Returns `null` if unknown.
     */
    getCode(codeHash: Uint8Array): Promise<Uint8Array | null>;
    /**
     * Read a single storage slot for a contract. Returns `null` if the key
     * is not set.
     */
    getStorageValue(contractAddr: Uint8Array, key: string): Promise<string | null>;
    /**
     * Write a single storage slot for a contract.
     */
    setStorageValue(contractAddr: Uint8Array, key: string, value: string): Promise<void>;
    /**
     * Delete a single storage slot for a contract. No-op if the key is not set.
     */
    deleteStorageValue(contractAddr: Uint8Array, key: string): Promise<void>;
    /**
     * List all storage entries for a contract, in byte-sorted key order.
     */
    allStorageForContract(contractAddr: Uint8Array): Promise<Array<{
        key: string;
        value: string;
    }>>;
    /**
     * Compute a deterministic 32-byte root over the contract's storage.
     * Used to populate the contract account's `storageRoot` field after
     * a contract invocation mutates state.
     */
    computeContractStorageRoot(contractAddr: Uint8Array): Promise<Uint8Array>;
}

/**
 * An in-memory pair of raw key bytes and raw value bytes representing a
 * single state entry. Keys are expected to already be in canonical form
 * (e.g. 20-byte address bytes) and values are expected to be SSZ-encoded
 * account bytes.
 */
interface StateEntry {
    key: Uint8Array;
    value: Uint8Array;
}
/**
 * Compute a deterministic 32-byte state root over a set of entries.
 *
 * Entries are sorted by key (byte-lexicographic) before hashing, so the
 * order in which they're passed in does not matter.
 */
declare function computeStateRoot(entries: Iterable<StateEntry>): Uint8Array;

/** Base error class for state-store operations. */
declare class StateError extends Error {
    constructor(message: string, options?: ErrorOptions);
}
/** Thrown (or used as a marker) when a requested key doesn't exist. */
declare class NotFoundError extends StateError {
    constructor(key: string, options?: ErrorOptions);
}

export { NotFoundError, type StateEntry, StateError, StateStore, type StateStoreOptions, computeStateRoot };
