/**
 * SDK State Stores (Zustand)
 *
 * Provides reactive state management for the SDK.
 * Each store is created via a factory function to support multi-instance SDKs.
 */
import { create } from 'zustand';
import { TransactionStatus } from '../types';
export function createSDKStore() {
    return create((set) => ({
        initialized: false,
        chainId: null,
        setInitialized: (initialized) => set({ initialized }),
        setChainId: (chainId) => set({ chainId }),
        reset: () => set({ initialized: false, chainId: null }),
    }));
}
export function createWalletStore() {
    return create((set) => ({
        isConnected: false,
        isAuthenticated: false,
        address: null,
        privacyAddress: null,
        mpk: null,
        setConnected: (connected, address) => set({
            isConnected: connected,
            address: connected ? address || null : null,
        }),
        setAuthenticated: (authenticated, privacyAddress, mpk) => set({
            isAuthenticated: authenticated,
            privacyAddress: authenticated ? privacyAddress || null : null,
            mpk: authenticated ? mpk || null : null,
        }),
        setAddress: (address) => set({ address }),
        reset: () => set({
            isConnected: false,
            isAuthenticated: false,
            address: null,
            privacyAddress: null,
            mpk: null,
        }),
    }));
}
export function createBalanceStore() {
    return create((set, get) => ({
        balances: new Map(),
        loading: false,
        lastSynced: null,
        setBalance: (tokenAddress, balance) => set((state) => {
            const newBalances = new Map(state.balances);
            newBalances.set(tokenAddress.toLowerCase(), balance);
            return { balances: newBalances, lastSynced: Date.now() };
        }),
        setBalances: (balances) => set(() => {
            const newBalances = new Map();
            for (const balance of balances) {
                newBalances.set(balance.tokenAddress.toLowerCase(), balance);
            }
            return { balances: newBalances, lastSynced: Date.now() };
        }),
        setLoading: (loading) => set({ loading }),
        getBalance: (tokenAddress) => get().balances.get(tokenAddress.toLowerCase()),
        reset: () => set({ balances: new Map(), loading: false, lastSynced: null }),
    }));
}
export function createTransactionStore() {
    return create((set, get) => ({
        transactions: [],
        pending: [],
        loading: false,
        addTransaction: (tx) => set((state) => {
            // Check if transaction already exists
            const exists = state.transactions.some((t) => t.txHash === tx.txHash);
            if (exists) {
                return state;
            }
            const newTransactions = [tx, ...state.transactions];
            // Update pending list
            const newPending = tx.status === TransactionStatus.pending || tx.status === TransactionStatus.preconfirmed
                ? [tx, ...state.pending]
                : state.pending;
            return {
                ...state,
                transactions: newTransactions,
                pending: newPending,
            };
        }),
        updateTransaction: (txHash, update, newHash) => set((state) => {
            const idx = state.transactions.findIndex((t) => t.txHash === txHash);
            if (idx === -1) {
                return state;
            }
            const existing = state.transactions[idx];
            const updatedTx = {
                ...existing,
                ...update,
                txHash: (newHash || existing.txHash),
                // Preserve old hash so lookups by original pending hash still work
                ...(newHash && newHash !== existing.txHash ? { previousHash: existing.txHash } : {}),
            };
            const newTransactions = [...state.transactions];
            newTransactions[idx] = updatedTx;
            return {
                ...state,
                transactions: newTransactions,
                pending: newTransactions.filter((t) => t.status === TransactionStatus.pending || t.status === TransactionStatus.preconfirmed),
            };
        }),
        setTransactions: (transactions) => set(() => ({
            transactions,
            pending: transactions.filter((t) => t.status === TransactionStatus.pending || t.status === TransactionStatus.preconfirmed),
        })),
        mergeTransactions: (fetchedTransactions) => set((state) => {
            const fetchedHashes = new Set(fetchedTransactions.map((t) => t.txHash));
            // Preserve ALL local txs (pending or resolved) that aren't in the fetched
            // set. A just-resolved tx often hasn't propagated to the indexer yet, so
            // if we only kept local pending txs here, the UI would briefly lose the
            // completed tx and fall back to "pending" until the next history fetch.
            const localNotInFetched = state.transactions.filter((t) => !fetchedHashes.has(t.txHash));
            const localByHash = new Map(state.transactions.map((t) => [t.txHash, t]));
            const updatedPending = [];
            for (const pending of state.pending) {
                const fetched = fetchedTransactions.find((f) => f.txHash === pending.txHash);
                if (fetched) {
                    updatedPending.push({ ...pending, ...fetched });
                }
                else {
                    updatedPending.push(pending);
                }
            }
            // Spread local first so fetched fields win, but local-only fields
            // (e.g. `to` populated at submission time before the indexer surfaces
            // a counterparty) are preserved across the refresh.
            const mergedFetched = fetchedTransactions.map((fetched) => {
                const local = localByHash.get(fetched.txHash);
                return local ? { ...local, ...fetched } : fetched;
            });
            const merged = [...localNotInFetched, ...mergedFetched];
            merged.sort((a, b) => b.createdAt - a.createdAt);
            const stillPending = updatedPending.filter((t) => t.status === TransactionStatus.pending || t.status === TransactionStatus.preconfirmed);
            return {
                ...state,
                transactions: merged,
                pending: stillPending,
            };
        }),
        getTransaction: (txHash) => get().transactions.find((t) => t.txHash === txHash || t.requestId === txHash || t.previousHash === txHash),
        getPending: () => get().pending,
        reset: () => set({ transactions: [], pending: [], loading: false }),
    }));
}
export function createTokenStore() {
    return create((set, get) => ({
        tokens: new Map(),
        setToken: (token) => set((state) => {
            const newTokens = new Map(state.tokens);
            newTokens.set(token.address.toLowerCase(), token);
            return { tokens: newTokens };
        }),
        getToken: (address) => get().tokens.get(address.toLowerCase()),
        reset: () => set({ tokens: new Map() }),
    }));
}
// ============================================
// SDKStores: Per-instance store bundle
// ============================================
/**
 * Bundle of all stores for a single SDK instance.
 * Enables multi-instance SDK usage where each instance has independent state.
 */
export class SDKStores {
    sdk;
    wallet;
    balance;
    transaction;
    token;
    owned;
    constructor(overrides = {}) {
        this.sdk = overrides.sdk ?? createSDKStore();
        this.wallet = overrides.wallet ?? createWalletStore();
        this.balance = overrides.balance ?? createBalanceStore();
        this.transaction = overrides.transaction ?? createTransactionStore();
        this.token = overrides.token ?? createTokenStore();
        this.owned = {
            sdk: overrides.sdk == null,
            wallet: overrides.wallet == null,
            balance: overrides.balance == null,
            transaction: overrides.transaction == null,
            token: overrides.token == null,
        };
    }
    /** Reset all stores to initial state */
    resetAll() {
        if (this.owned.sdk)
            this.sdk.getState().reset();
        if (this.owned.wallet)
            this.wallet.getState().reset();
        if (this.owned.balance)
            this.balance.getState().reset();
        if (this.owned.transaction)
            this.transaction.getState().reset();
        if (this.owned.token)
            this.token.getState().reset();
    }
}
//# sourceMappingURL=stores.js.map