import { CreateSessionOptions } from '@incodetech/core/session';
import { FC } from 'preact/compat';
import { FinishStatus } from '@incodetech/core/flow';
import { FlowEvent } from '@incodetech/core/flow-events';
import { WasmConfig } from '@incodetech/core/wasm';

declare type ApiKeySessionBootstrap = {
    apiKey: string;
    clientId?: string;
};

declare type ClientIdSessionBootstrap = {
    apiKey?: string;
    clientId: string;
};

declare type FlowBaseConfig = {
    authHint?: string;
    wasmConfig?: WasmConfig;
    lang?: string;
    disableDashboardTheme?: boolean;
    enableHome?: boolean;
    useCPF?: boolean;
};

export declare type FlowConfig = FlowRuntimeConfig & FlowUiConfig;

declare type FlowRuntimeConfig = TokenFlowRuntimeConfig | SelfLoadingFlowRuntimeConfig;

declare type FlowUiConfig = {
    onModuleLoading?: (moduleKey: string) => void;
    onModuleLoaded?: (moduleKey: string) => void;
    /**
     * Receives curated flow milestones from this flow instance.
     *
     * Use this local-only stream for integration milestones such as
     * `flow.started`, `flow.ready`, `flow.module.started`,
     * `flow.module.completed`, `flow.completed`, and `flow.error`.
     * For raw analytics events, use `subscribeEvent` from
     * `@incodetech/core/events`.
     */
    onFlowEvent?: (event: FlowEvent) => void;
    onWasmWarmup?: (pipelines: string[]) => void;
    onUrlUuidRefreshed?: (urlUuid: string) => void;
    spinnerConfig?: SpinnerConfig;
};

export declare const IncodeFlow: FC<IncodeFlowProps>;

declare type IncodeFlowProps = IncodeModuleProps<FlowConfig, FinishStatus>;

declare type IncodeModuleProps<TConfig, TResult = void, TManager = unknown> = {
    /**
     * Module configuration required to render the flow.
     * For Web Components, this is typically assigned via `element.config = ...`.
     */
    config?: TConfig;
    /**
     * Optional pre-built manager. When provided, the module does not create or manage the manager lifecycle.
     */
    manager?: TManager;
    /**
     * Callback invoked when the module completes successfully.
     * @param result - Optional result data from the module completion
     */
    onFinish?: (result?: TResult) => void;
    /**
     * Callback invoked when a fatal module error occurs.
     *
     * @param error - Human-readable error message.
     * @param errorCode - Optional numeric code (e.g. HTTP status). Populated by
     *   the workflow and flow modules on QR validation failures —
     *   `4026` (`expiredUUID`), `4081` (`invalidQRuuid`) or `4083` (`onboardingUrlAlreadyUsed`).
     * @param moduleErrorCode - Optional machine-readable error code (e.g. a
     *   `FaceErrorCode` such as `NONEXISTENT_CUSTOMER`). Lets an orchestrator
     *   branch on the specific terminal error without parsing the message string.
     */
    onError?: (error: string | undefined, errorCode?: number, moduleErrorCode?: string) => void;
};

/**
 * Preload runs before the Flow component mounts and only prefetches the flow
 * config + theme — it never burns a urlUuid. Allowing one would silently skip
 * phishing-resistance rotation on mount (the consume path bypasses the init
 * useEffect), so the field is forbidden at the type and runtime boundaries.
 * Topology B (mobile leg of a desktop→mobile redirect) cannot use preload —
 * pass `urlUuid` to `<IncodeFlow>` directly instead.
 */
declare type PreloadConfig = Omit<TokenFlowRuntimeConfig, 'urlUuid'> & {
    urlUuid?: never;
};

export declare type PreloadHandle = {
    get isReady(): boolean;
    get error(): string | null;
    waitUntilReady(): Promise<void>;
    cancel(): void;
};

export declare function preloadIncodeFlow(config: PreloadConfig): PreloadHandle;

declare type SelfLoadingFlowRuntimeConfig = FlowBaseConfig & SelfLoadingSessionOptions & (ApiKeySessionBootstrap | ClientIdSessionBootstrap) & {
    token?: never;
};

declare type SelfLoadingSessionOptions = Pick<CreateSessionOptions, 'configurationId' | 'externalId' | 'externalCustomerId' | 'customFields' | 'uuid' | 'urlUuid' | 'interviewId' | 'loginHint'>;

declare type SpinnerConfig = {
    title?: string;
    subtitle?: string;
    size?: SpinnerSize;
};

declare type SpinnerSize = 'small' | 'medium' | 'large';

declare type TokenFlowRuntimeConfig = FlowBaseConfig & {
    token: string;
    /** QR anti-phishing token from the incoming URL (mobile leg of a desktop→mobile redirect).
     *  When provided, the SDK rotates it on mount via `validateQrUuid` and invokes
     *  `onUrlUuidRefreshed` so the host can update the address bar. Validation
     *  failures abort initialization via `onError` (with the HTTP status as
     *  `errorCode`). */
    urlUuid?: string;
    apiKey?: never;
    clientId?: never;
    configurationId?: never;
    externalId?: never;
    externalCustomerId?: never;
    customFields?: never;
    uuid?: never;
    interviewId?: never;
};

export { }

declare global {
    interface HTMLElementTagNameMap {
        'incode-flow': HTMLElement & IncodeModuleProps<FlowConfig, FinishStatus>;
    }
}
