/**
 * ios-keychain-token-store.ts
 *
 * Token store backed by `react-native-keychain` for bare React Native on iOS.
 *
 * Uses `Keychain.setGenericPassword` / `getGenericPassword` /
 * `resetGenericPassword` to persist tokens in the iOS Keychain.
 *
 * `react-native-keychain` is an **optional peer dependency** — this module
 * does NOT import it at the top level.
 *
 * ## Installation
 *
 * ```sh
 * npm install react-native-keychain
 * npx pod-install   # iOS CocoaPods link
 * ```
 *
 * Error messages use the format: [what happened] · [why] · [what to do]
 */
import { GoodVibesSdkError } from '@pellux/goodvibes-errors';
const REACT_NATIVE_KEYCHAIN_MODULE = 'react-native-keychain';
let _mod = null;
async function loadKeychain() {
    if (_mod !== null)
        return _mod;
    try {
        _mod = (await import(REACT_NATIVE_KEYCHAIN_MODULE));
        return _mod;
    }
    catch {
        throw new GoodVibesSdkError('react-native-keychain is not installed — the iOS Keychain token store cannot be initialised. ' +
            'This optional peer dependency is required to persist tokens in the iOS Keychain. ' +
            'Run `npm install react-native-keychain && npx pod-install` and rebuild your app.', {
            code: 'RN_KEYCHAIN_NOT_INSTALLED',
            category: 'config',
            source: 'config',
            recoverable: false,
        });
    }
}
// ---------------------------------------------------------------------------
// Fixed username slot
// ---------------------------------------------------------------------------
const USERNAME_SLOT = 'goodvibes-sdk';
// ---------------------------------------------------------------------------
// Factory
// ---------------------------------------------------------------------------
/**
 * Create a `GoodVibesTokenStore` backed by the iOS Keychain via
 * `react-native-keychain`.
 *
 * Suitable for **bare React Native** iOS apps. For Expo-managed workflow, use
 * `createExpoSecureTokenStore` instead.
 *
 * Both the `token` and `expiresAt` values are serialised as a single JSON
 * blob in the keychain password slot. The username slot is fixed to
 * `'goodvibes-sdk'`.
 *
 * `react-native-keychain` is an **optional peer dependency** — install it with:
 *
 * ```sh
 * npm install react-native-keychain
 * npx pod-install
 * ```
 *
 * @example
 * ```ts
 * import { createIOSKeychainTokenStore, createReactNativeGoodVibesSdk } from '@pellux/goodvibes-sdk/react-native';
 *
 * const tokenStore = createIOSKeychainTokenStore({ service: 'com.myapp.gv' });
 * const sdk = createReactNativeGoodVibesSdk({ baseUrl: 'https://daemon.example.com', tokenStore });
 * ```
 */
export function createIOSKeychainTokenStore(options = {}, __loadModule) {
    const service = options.service ?? 'com.pellux.goodvibes-sdk';
    const accessible = options.accessible ?? 'WHEN_UNLOCKED_THIS_DEVICE_ONLY';
    const accessGroup = options.accessGroup;
    async function resolveModule() {
        if (__loadModule !== undefined) {
            return __loadModule();
        }
        return loadKeychain();
    }
    function buildOptions(mod) {
        const opts = { service };
        const accessibleValue = mod.ACCESSIBLE[accessible];
        if (accessibleValue !== undefined) {
            opts.accessible = accessibleValue;
        }
        else {
            throw new Error(`react-native-keychain does not expose ACCESSIBLE.${accessible}; choose a supported keychain accessibility constant.`);
        }
        if (accessGroup !== undefined) {
            opts.accessGroup = accessGroup;
        }
        return opts;
    }
    async function readPayload() {
        const mod = await resolveModule();
        const result = await mod.getGenericPassword(buildOptions(mod));
        if (result === false)
            return null;
        try {
            return JSON.parse(result.password);
        }
        catch (err) {
            await mod.resetGenericPassword(buildOptions(mod));
            throw new GoodVibesSdkError('iOS keychain 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.resetGenericPassword(buildOptions(mod));
            return;
        }
        await mod.setGenericPassword(USERNAME_SLOT, JSON.stringify(payload), buildOptions(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 };
        },
    };
}
