/**
 * expo-secure-token-store.ts
 *
 * Token store backed by `expo-secure-store` — Expo's hardware-backed secure
 * storage layer (iOS Keychain / Android Keystore behind the scenes).
 *
 * `expo-secure-store` is an **optional peer dependency** — this module does
 * NOT eagerly import it. The module is loaded lazily so the SDK remains
 * loadable in environments where the native module is absent.
 *
 * ## Installation
 *
 * ```sh
 * expo install expo-secure-store
 * ```
 *
 * Error messages use the format: [what happened] · [why] · [what to do]
 */
import { GoodVibesSdkError } from '@pellux/goodvibes-errors';
const EXPO_SECURE_STORE_MODULE = 'expo-secure-store';
let _mod = null;
async function loadExpoSecureStore() {
    if (_mod !== null)
        return _mod;
    try {
        _mod = (await import(EXPO_SECURE_STORE_MODULE));
        return _mod;
    }
    catch {
        throw new GoodVibesSdkError('expo-secure-store is not installed — the Expo secure token store cannot be initialised. ' +
            'This optional peer dependency is required to persist tokens in native hardware-backed storage. ' +
            'Run `expo install expo-secure-store` and rebuild your app.', {
            code: 'EXPO_SECURE_STORE_NOT_INSTALLED',
            category: 'config',
            source: 'config',
            recoverable: false,
        });
    }
}
// ---------------------------------------------------------------------------
// Factory
// ---------------------------------------------------------------------------
/**
 * Create a `GoodVibesTokenStore` backed by `expo-secure-store`.
 *
 * Both the `token` and `expiresAt` values are serialised as a single JSON
 * blob into one secure-store entry, keeping the keychain tidy.
 *
 * `expo-secure-store` is an **optional peer dependency** — install it with:
 *
 * ```sh
 * expo install expo-secure-store
 * ```
 *
 * @example
 * ```ts
 * import { createExpoSecureTokenStore, createExpoGoodVibesSdk } from '@pellux/goodvibes-sdk/expo';
 *
 * const tokenStore = createExpoSecureTokenStore({ key: 'gv-token' });
 * const sdk = createExpoGoodVibesSdk({ baseUrl: 'https://daemon.example.com', tokenStore });
 * ```
 */
export function createExpoSecureTokenStore(options = {}, __loadModule) {
    const key = options.key?.trim() || 'goodvibes-sdk-token';
    const accessible = options.accessible ?? 'WHEN_UNLOCKED_THIS_DEVICE_ONLY';
    const keychainService = options.keychainService;
    async function resolveModule() {
        if (__loadModule !== undefined) {
            return __loadModule();
        }
        return loadExpoSecureStore();
    }
    function buildStoreOptions(mod) {
        const opts = {};
        const accessibleValue = mod[accessible];
        if (accessibleValue !== undefined) {
            opts.keychainAccessible = accessibleValue;
        }
        else {
            throw new Error(`expo-secure-store does not expose ${accessible}; choose a supported SecureStore accessibility constant.`);
        }
        if (keychainService !== undefined) {
            opts.keychainService = keychainService;
        }
        return opts;
    }
    async function readPayload() {
        const mod = await resolveModule();
        const raw = await mod.getItemAsync(key, buildStoreOptions(mod));
        if (raw === null || raw === '')
            return null;
        try {
            return JSON.parse(raw);
        }
        catch (err) {
            await mod.deleteItemAsync(key, buildStoreOptions(mod));
            throw new GoodVibesSdkError('Expo secure token store payload is corrupt and was cleared.', {
                code: 'SDK_TOKEN_STORE_CORRUPT',
                category: 'authentication',
                source: 'runtime',
                recoverable: true,
                cause: err,
            });
        }
    }
    async function writePayload(payload) {
        const mod = await resolveModule();
        if (payload === null) {
            await mod.deleteItemAsync(key, buildStoreOptions(mod));
            return;
        }
        await mod.setItemAsync(key, JSON.stringify(payload), buildStoreOptions(mod));
    }
    return {
        async getToken() {
            const payload = await readPayload();
            return payload?.token ?? null;
        },
        async setToken(token) {
            if (token === null) {
                await writePayload(null);
                return;
            }
            await writePayload({ token, expiresAt: null });
        },
        async clearToken() {
            await writePayload(null);
        },
        async setTokenEntry(token, expiresAt) {
            if (token === null) {
                await writePayload(null);
                return;
            }
            await writePayload({ token, expiresAt: expiresAt ?? null });
        },
        async getTokenEntry() {
            const payload = await readPayload();
            if (payload === null)
                return { token: null };
            const expiresAt = payload.expiresAt ?? undefined;
            return expiresAt !== undefined ? { token: payload.token, expiresAt } : { token: payload.token };
        },
    };
}
