import { ReasonCode } from '../types/index.js';
import { asNimiError, createNimiError } from '../runtime/errors.js';
import { asRecord, normalizeText, nowIso, readString } from '../internal/utils.js';
export const DEFAULT_REALM_TIMEOUT_MS = 10000;
export { asRecord, normalizeText, nowIso };
export function hasValue(value) {
    return value !== undefined && value !== null;
}
export function resolveBaseUrl(value) {
    const baseUrl = normalizeText(value);
    if (!baseUrl) {
        throw createNimiError({
            message: 'realm endpoint (baseUrl) is required',
            reasonCode: ReasonCode.SDK_REALM_ENDPOINT_REQUIRED,
            actionHint: 'set_realm_base_url',
            source: 'sdk',
        });
    }
    return baseUrl.replace(/\/+$/, '');
}
function isAbortLikeError(error) {
    if (!error) {
        return false;
    }
    if (typeof DOMException !== 'undefined' && error instanceof DOMException) {
        return error.name === 'AbortError';
    }
    const record = asRecord(error);
    const name = normalizeText(record.name);
    const code = normalizeText(record.code);
    if (name === 'AbortError' || code === 'ABORT_ERR') {
        return true;
    }
    const message = normalizeText(record.message).toLowerCase();
    return message.includes('aborted');
}
function mapRealmStatusReasonCode(status) {
    if (status === 401) {
        return ReasonCode.AUTH_TOKEN_INVALID;
    }
    if (status === 403) {
        return ReasonCode.PRINCIPAL_UNAUTHORIZED;
    }
    if (status === 404) {
        return ReasonCode.REALM_NOT_FOUND;
    }
    if (status === 409) {
        return ReasonCode.REALM_CONFLICT;
    }
    if (status === 429) {
        return ReasonCode.REALM_RATE_LIMITED;
    }
    if (status === 400 || status === 422) {
        return ReasonCode.CONFIG_INVALID;
    }
    if (status >= 500) {
        return ReasonCode.REALM_UNAVAILABLE;
    }
    return ReasonCode.ACTION_INPUT_INVALID;
}
function mapRealmStatusActionHint(status) {
    if (status === 401) {
        return 'refresh_realm_token_or_reauthenticate';
    }
    if (status === 403) {
        return 'check_principal_permissions_or_resource_visibility';
    }
    if (status === 404) {
        return 'check_realm_path_or_resource_id';
    }
    if (status === 409) {
        return 'resolve_realm_conflict_then_retry';
    }
    if (status === 429) {
        return 'retry_after_backoff';
    }
    if (status === 400 || status === 422) {
        return 'fix_realm_config_or_request_payload';
    }
    if (status >= 500) {
        return 'retry_or_check_realm_status';
    }
    return 'check_realm_request_payload';
}
export function isResponse(value) {
    return typeof Response !== 'undefined' && value instanceof Response;
}
export function readErrorBody(value) {
    if (!value) {
        return {};
    }
    if (typeof value === 'string') {
        try {
            const parsed = JSON.parse(value);
            return asRecord(parsed);
        }
        catch {
            return { message: value };
        }
    }
    if (typeof value === 'object') {
        return asRecord(value);
    }
    return {};
}
export function extractResponseReasonCode(body, response) {
    const nestedError = asRecord(body.error);
    const rawReasonCode = readString(body, ['reasonCode', 'reason_code'])
        || readString(nestedError, ['reasonCode', 'reason_code'])
        || normalizeText(response.headers.get('x-reason-code'));
    const statusReasonCode = mapRealmStatusReasonCode(response.status);
    const reasonCode = response.status === 403 ? statusReasonCode : rawReasonCode || statusReasonCode;
    const code = mapRealmStatusReasonCode(response.status);
    const rawActionHint = readString(body, ['actionHint', 'action_hint'])
        || readString(nestedError, ['actionHint', 'action_hint'])
        || normalizeText(response.headers.get('x-action-hint'));
    const statusActionHint = mapRealmStatusActionHint(response.status);
    const actionHint = response.status === 403 ? statusActionHint : rawActionHint || statusActionHint;
    const traceId = readString(body, ['traceId', 'trace_id'])
        || readString(nestedError, ['traceId', 'trace_id'])
        || normalizeText(response.headers.get('x-trace-id'));
    const message = readString(body, ['message'])
        || readString(nestedError, ['message'])
        || `${response.status} ${response.statusText}`;
    const retryable = response.status === 429 || response.status >= 500;
    const details = {
        httpStatus: response.status,
    };
    if (rawReasonCode) {
        details.rawReasonCode = rawReasonCode;
    }
    if (rawActionHint) {
        details.rawActionHint = rawActionHint;
    }
    return {
        rawReasonCode,
        reasonCode,
        code,
        actionHint,
        traceId,
        message,
        retryable,
        details,
    };
}
export function mapRealmError(error) {
    if (isAbortLikeError(error)) {
        return createNimiError({
            message: normalizeText(asRecord(error).message) || 'realm request aborted',
            code: ReasonCode.OPERATION_ABORTED,
            reasonCode: ReasonCode.OPERATION_ABORTED,
            actionHint: 'retry_if_needed',
            source: 'realm',
        });
    }
    const normalized = asNimiError(error, {
        code: ReasonCode.REALM_UNAVAILABLE,
        reasonCode: ReasonCode.REALM_UNAVAILABLE,
        actionHint: 'retry_or_check_realm_network',
        source: 'realm',
    });
    const message = normalizeText(normalized.message).toLowerCase();
    if (message.includes('aborted')) {
        return createNimiError({
            message: normalized.message,
            code: ReasonCode.OPERATION_ABORTED,
            reasonCode: ReasonCode.OPERATION_ABORTED,
            actionHint: 'retry_if_needed',
            traceId: normalized.traceId || undefined,
            source: 'realm',
            retryable: false,
        });
    }
    return normalized;
}
//# sourceMappingURL=client-helpers.js.map