import React, { ButtonHTMLAttributes, ReactNode } from 'react';

interface KYCSubmission {
    verificationId: string;
    status: 'pending';
    metadata: Record<string, string>;
    submittedAt: string;
}
/**
 * Typed, documented technical-error categories surfaced through `onError`.
 * These are IDENTICAL to the Flutter SDK's codes so integrators get one
 * consistent contract across platforms.
 *
 * - `network_error`            — connection failure / timeout (after retries)
 * - `invalid_api_key`          — server returned 401
 * - `insufficient_credits`     — server returned 402 (see `details`)
 * - `upload_failed`            — `POST /api/kyc/upload` failed (after retries)
 * - `camera_permission_denied` — the user denied (or the OS/browser blocks)
 *                                camera access; capture cannot proceed
 * - `feature_disabled`         — server returned 403 (ID type or a verification
 *                                feature is not enabled for the org)
 * - `unknown`                  — anything else
 *
 * > Voice guidance is text-to-speech *output* — it never records audio, so
 * > there is no microphone-permission error code.
 */
type KYCErrorCode = 'network_error' | 'invalid_api_key' | 'insufficient_credits' | 'upload_failed' | 'camera_permission_denied' | 'feature_disabled' | 'unknown';
interface KYCErrorDetails {
    required?: number;
    balance?: number;
    currency?: string;
}
/**
 * The error instance passed to `onError`. It is a real `Error` (so existing
 * `onError: (error: Error) => void` handlers keep working) that additionally
 * carries a typed `code` and optional `details`. Narrow with `instanceof
 * KYCError` (or read `error.code`) to branch on the category.
 */
declare class KYCError extends Error {
    readonly code: KYCErrorCode;
    readonly details?: KYCErrorDetails;
    constructor(code: KYCErrorCode, message: string, details?: KYCErrorDetails);
}
type ApiStatus = 'idle' | 'loading' | 'success' | 'error';

type SupportedCountry = 'NG' | 'GH' | 'KE' | 'ZA' | 'CI';
type NigeriaIdType = 'bvn' | 'bvn-premium' | 'nin' | 'vnin' | 'tax-id' | 'passport' | 'drivers-license' | 'pvc';
type GhanaIdType = 'ghana-card' | 'voters' | 'drivers-license' | 'ssnit' | 'passport';
type KenyaIdType = 'national-id' | 'passport';
type SouthAfricaIdType = 'national-id';
type IvoryCoastIdType = 'cni' | 'residence-card';
type IdType = NigeriaIdType | GhanaIdType | KenyaIdType | SouthAfricaIdType | IvoryCoastIdType;
/** Maps a country code to the ID types available in that country. */
type IdTypeForCountry<C extends SupportedCountry> = C extends 'NG' ? NigeriaIdType : C extends 'GH' ? GhanaIdType : C extends 'KE' ? KenyaIdType : C extends 'ZA' ? SouthAfricaIdType : C extends 'CI' ? IvoryCoastIdType : never;
type KYCStep = 'consent' | 'id-type' | 'id-input' | 'document-capture' | 'liveness' | 'submitted';
interface KYCAppearance {
    /** Brand color — drives buttons, selected states, focus rings (`--primary`/`--ring`). */
    primaryColor?: string;
    /** Text/icon color rendered on top of `primaryColor` (e.g. button labels) (`--primary-foreground`). */
    primaryTextColor?: string;
    /** Accent color for subtle hover/active surfaces (`--accent`). */
    accentColor?: string;
    /** Modal background color (`--background`). */
    backgroundColor?: string;
    /** Elevated surface color for cards/panels (`--secondary` + `--muted`). */
    surfaceColor?: string;
    /** Border + input outline color (`--border` + `--input`). */
    borderColor?: string;
    /** Primary text color (`--foreground`). */
    textColor?: string;
    companyName?: string;
    /**
     * Logo to show in the flow.
     * - An image URL renders that logo.
     * - The literal `'default'` renders the org's own logo from the server config
     *   response (falls back to the built-in shield if the org has none set).
     * - Omitted renders the built-in shield badge.
     */
    logo?: string;
    /** Initial light/dark mode. Applied on mount; the theme toggle can flip it. */
    theme?: 'light' | 'dark';
}
interface KYCConsentContent {
    /**
     * Heading on the consent (welcome) screen. Supports `{firstName}` and
     * `{lastName}` tokens, which are replaced with the values from `userData`
     * (empty string when absent). Defaults to `Welcome, {firstName}` when a first
     * name is known, otherwise `Identity Verification`.
     */
    title?: string;
    /**
     * Sub-text under the heading. Supports the same `{firstName}` / `{lastName}`
     * tokens. Defaults to the built-in regulatory copy.
     */
    description?: string;
}
interface KYCSuccessContent {
    /**
     * Heading on the success screen shown after a verification is submitted.
     * Supports `{firstName}` and `{lastName}` tokens, replaced with the values
     * from `userData` (empty string when absent). Defaults to
     * `Verification Submitted!`.
     */
    title?: string;
    /**
     * Sub-text under the heading. Supports the same `{firstName}` / `{lastName}`
     * tokens. Defaults to the built-in "submitted for review" copy.
     */
    description?: string;
}
/**
 * Configuration for the spoken liveness instructions ("nod your head",
 * "blink", …). This is text-to-speech **output** played to the user for
 * accessibility — it never records audio, so no microphone permission is
 * involved.
 *
 * Structured as an object (rather than a bare boolean) so a `language` can be
 * added later without a breaking change — Myaza operates across NG/GH/KE/ZA/CI,
 * and French guidance for CI is a likely future need.
 */
interface VoiceGuidanceConfig {
    /** Whether spoken guidance plays. Default `true` (on for accessibility). */
    enabled?: boolean;
    /**
     * BCP-47 language tag for the spoken voice (e.g. `'en-US'`, `'fr-FR'`).
     * Defaults to `'en-US'`. Currently selects the TTS voice only; the spoken
     * text still mirrors the on-screen English instruction (localized strings
     * are a planned follow-up).
     */
    language?: string;
}
/**
 * `voiceGuidance` prop value. Accepts a bare boolean for ergonomics
 * (`voiceGuidance={false}`) or the full {@link VoiceGuidanceConfig} object.
 */
type VoiceGuidanceOption = boolean | VoiceGuidanceConfig;
interface MyazaKYCConfig<C extends SupportedCountry = SupportedCountry> {
    /**
     * Bearer token sent as the Authorization header. The key prefix is the single
     * source of truth for the environment — the SDK derives it (and the base URL)
     * automatically: `pk_dev_…` → development, `pk_test_…` → sandbox,
     * `pk_live_…` → production. An unrecognized prefix throws.
     */
    apiKey: string;
    /**
     * Dev-only base-URL override. Only applied for **development** keys
     * (`pk_dev_…`); defaults to `http://localhost:3001`. Ignored for sandbox /
     * production keys.
     */
    devUrl?: string;
    /** Two-letter country code */
    country: C;
    /** Subset of ID types to offer. Only types valid for the given country are accepted. */
    idTypes?: IdTypeForCountry<C>[];
    /** Pre-populated user data. Fields provided here won't be collected again. */
    userData?: {
        firstName?: string;
        lastName?: string;
        dateOfBirth?: string;
    };
    /** Enable the live-selfie capture step */
    enableSelfie?: boolean;
    /** Enable the document-photo capture step */
    enableDocumentCapture?: boolean;
    /**
     * Allow picking a document photo from the device (gallery / file picker /
     * drag-and-drop) as an alternative to the live camera capture. Default `true`.
     * When `false`, all "upload a photo instead" affordances are hidden and the
     * user must capture with the camera.
     */
    allowDocumentUpload?: boolean;
    /** Enable liveness detection during selfie capture (default: true) */
    enableLiveness?: boolean;
    /**
     * Spoken liveness instructions (accessibility). `true`/omitted = on,
     * `false` = off, or a {@link VoiceGuidanceConfig} for finer control
     * (e.g. `{ enabled: true, language: 'fr-FR' }`). TTS output only — no
     * microphone is used. Default: on.
     */
    voiceGuidance?: VoiceGuidanceOption;
    /** Show a light/dark mode toggle button inside the modal header. Default `true`. */
    showThemeToggle?: boolean;
    /**
     * Offer "continue on your phone" device handoff. On **desktop**, before the
     * flow starts, the SDK shows a screen with a QR code + copyable link/code so
     * the user can finish on their phone (useful when the desktop has no webcam),
     * plus a "Continue on this device" CTA. When the phone submits, the desktop
     * auto-advances and fires {@link onSubmit}. Mobile devices skip the screen and
     * start the flow directly. Default `true`; set `false` to disable entirely.
     */
    deviceHandoff?: boolean;
    /**
     * Hide the close (X) button and block all user-initiated dismissal of the
     * modal — backdrop tap, Escape key, and (on mobile) swipe-down. When `true`,
     * the flow can only be closed programmatically via the `close()` returned by
     * {@link useMyazaKYC}. Default `false`. The terminal "Submitted" step is
     * already non-dismissible regardless of this flag.
     */
    disableClose?: boolean;
    /** Visual customisation */
    appearance?: KYCAppearance;
    /** Override the consent (welcome) screen copy. */
    consent?: KYCConsentContent;
    /** Override the success (submitted) screen copy. */
    success?: KYCSuccessContent;
    /**
     * Base path (or absolute URL) where the SDK's gesture GIF assets are served
     * from. These are used by the liveness step to animate each challenge gesture.
     *
     * - Set to an **absolute URL** (e.g. `'https://cdn.example.com/kyc-assets'`)
     *   to serve from a CDN — requires no files in your `public/` folder.
     * - Set to a **relative path** (e.g. `'/kyc-assets'`) to serve locally; copy
     *   the `gifs/` folder from `node_modules/@myazahq/kyc-sdk-react/gifs/` to
     *   that path in your public directory.
     *
     * Defaults to `'/kyc-assets'`.
     */
    assetsBasePath?: string;
    /** Arbitrary metadata forwarded with every verification request */
    metadata?: Record<string, string>;
    onStart?: () => void;
    onStepChange?: (step: KYCStep) => void;
    /**
     * Fires immediately after the user submits their verification.
     * The submission is always status: 'pending' — results arrive async via webhook.
     */
    onSubmit?: (submission: KYCSubmission) => void;
    onClose?: () => void;
    /**
     * Fires for technical errors only. Receives a {@link KYCError} — a real
     * `Error` that also carries a typed `code` (e.g. `camera_permission_denied`,
     * `upload_failed`, `network_error`). Verification *outcomes* never come
     * through here — they arrive via webhook / status polling.
     */
    onError?: (error: KYCError) => void;
}
/**
 * Props for the `<MyazaKYC />` component: the full SDK config plus standard
 * `<button>` attributes for the built-in trigger button.
 *
 * The trigger renders a real `<button>`, so you can:
 * - pass `children` to set the button label/content (defaults to
 *   `Verify with {companyName}` / `Verify Identity`),
 * - pass `className` to restyle it (merged via `tailwind-merge`, so your
 *   classes override the defaults),
 * - forward any other button attribute (`disabled`, `aria-*`, `type`, …).
 *
 * `onClick` is owned by the SDK (it opens the modal) and is therefore omitted.
 * To build your own trigger element instead, use the `useMyazaKYC()` hook and
 * wire its `open()` to whatever you render.
 */
type MyazaKYCProps<C extends SupportedCountry = SupportedCountry> = MyazaKYCConfig<C> & Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof MyazaKYCConfig<C> | 'onClick'>;
interface UseMyazaKYCReturn {
    open: () => void;
    close: () => void;
    isOpen: boolean;
    currentStep: KYCStep | null;
}

declare function MyazaKYC<C extends SupportedCountry>(props: MyazaKYCProps<C>): React.JSX.Element;
declare function useMyazaKYC<C extends SupportedCountry>(config: MyazaKYCConfig<C>): UseMyazaKYCReturn;

interface MyazaKYCHostedProps {
    /**
     * The raw handoff session token from the hosted-page URL
     * (`/verify/<token>`). The SDK presents it as a `hs_<token>` bearer.
     */
    token: string;
}
/**
 * Hosted "continue on your phone" entry point. Rendered by the Myaza-hosted
 * verification page (`/verify/<token>`), NOT by customers directly. It bootstraps
 * the flow from the session token and runs the SAME steps as `<MyazaKYC />`,
 * authenticating every upload/verify with the session token (relative base URL,
 * so requests go through the hosting origin's API proxy).
 */
declare function MyazaKYCHosted({ token }: MyazaKYCHostedProps): React.JSX.Element;

interface KYCUserData {
    firstName: string;
    lastName: string;
    dateOfBirth: string;
}
interface MediaIds {
    documentFront?: string;
    documentBack?: string;
    selfie?: string;
    documentFrontVideo?: string;
    documentBackVideo?: string;
    livenessVideo?: string;
}
interface KYCState {
    currentStep: KYCStep;
    status: ApiStatus;
    isOpen: boolean;
    selectedIdType: IdType | null;
    documentFrontImage: string | null;
    documentBackImage: string | null;
    mediaIds: MediaIds;
    idNumber: string;
    userData: KYCUserData;
    selfieImage: string | null;
    documentFrontVideoBlob: Blob | null;
    documentBackVideoBlob: Blob | null;
    livenessVideoBlob: Blob | null;
    verificationId: string | null;
    /**
     * Last technical error (submission failures). Carries the typed `code` so the
     * consumer's `onError` receives a `KYCError`, not a bare string. Capture-step
     * errors (camera permission, upload-after-retries) report to `onError`
     * directly and do not set this — they have their own inline UI.
     */
    error: KYCError | null;
}
type KYCAction = {
    type: 'OPEN_MODAL';
} | {
    type: 'CLOSE_MODAL';
} | {
    type: 'SET_STEP';
    payload: KYCStep;
} | {
    type: 'SELECT_ID_TYPE';
    payload: IdType;
} | {
    type: 'SET_ID_NUMBER';
    payload: string;
} | {
    type: 'SET_USER_DATA';
    payload: Partial<KYCUserData>;
} | {
    type: 'SET_DOCUMENT_FRONT';
    payload: string;
} | {
    type: 'SET_DOCUMENT_BACK';
    payload: string;
} | {
    type: 'CLEAR_DOCUMENT_FRONT';
} | {
    type: 'CLEAR_DOCUMENT_BACK';
} | {
    type: 'CLEAR_DOCUMENT_ALL';
} | {
    type: 'SET_MEDIA_ID';
    payload: {
        mediaType: keyof MediaIds;
        mediaId: string;
    };
} | {
    type: 'CLEAR_MEDIA_IDS';
} | {
    type: 'SET_SELFIE_IMAGE';
    payload: string;
} | {
    type: 'CLEAR_SELFIE_IMAGE';
} | {
    type: 'SET_DOCUMENT_FRONT_VIDEO';
    payload: Blob;
} | {
    type: 'SET_DOCUMENT_BACK_VIDEO';
    payload: Blob;
} | {
    type: 'SET_LIVENESS_VIDEO';
    payload: Blob;
} | {
    type: 'CLEAR_LIVENESS_VIDEO';
} | {
    type: 'SUBMIT_VERIFICATION';
} | {
    type: 'SUBMISSION_SUCCESS';
    payload: string;
} | {
    type: 'SET_ERROR';
    payload: KYCError;
} | {
    type: 'CLEAR_ERROR';
} | {
    type: 'RETRY';
} | {
    type: 'RESET';
};

interface KYCContextValue {
    state: KYCState;
    dispatch: React.Dispatch<KYCAction>;
}
declare function KYCProvider({ children }: {
    children: ReactNode;
}): React.JSX.Element;
declare function useKYCContext(): KYCContextValue;

export { type IdType, type KYCAppearance, type KYCConsentContent, KYCError, type KYCErrorCode, type KYCErrorDetails, KYCProvider, type KYCStep, type KYCSubmission, type KYCSuccessContent, MyazaKYC, type MyazaKYCConfig, MyazaKYCHosted, type MyazaKYCHostedProps, type MyazaKYCProps, type SupportedCountry, type UseMyazaKYCReturn, type VoiceGuidanceConfig, type VoiceGuidanceOption, useKYCContext, useMyazaKYC };
