import { FhirClient } from '@outburn/fhir-client';
import { FumeMappingProvider } from '@outburn/fume-mapping-provider';
import { FhirStructureNavigator } from '@outburn/structure-navigator';
import { Logger, EvaluateVerboseReport, FhirVersion, FhirPackageIdentifier } from '@outburn/types';
export { DiagnosticEntry, DiagnosticLevel, EvaluateVerboseReport, FhirPackageIdentifier, FhirRelease, FhirVersion, FhirVersionMinor, FumeHttpEvaluationError, Logger } from '@outburn/types';
import { FhirSnapshotGenerator } from 'fhir-snapshot-generator';
import { FhirTerminologyRuntime } from 'fhir-terminology-runtime';
import { FumifierOptions } from 'fumifier';
import express, { Application, RequestHandler } from 'express';
import { OpenAPIV3 } from 'openapi-types';
import { z } from 'zod';

/**
 * © Copyright Outburn Ltd. 2022-2024 All Rights Reserved
 *   Project name: FUME-COMMUNITY
 */
interface ICache<T> {
    get: (key: string) => T | undefined;
    set: (key: string, value: T) => void;
    remove: (key: string) => void;
    keys: () => string[];
    reset: () => void;
    populate: (dict: Record<string, T>) => void;
    getDict: () => Record<string, T>;
}

/**
 * © Copyright Outburn Ltd. 2022-2024 All Rights Reserved
 *   Project name: FUME-COMMUNITY
 */
interface IConfig {
    SERVER_PORT: number;
    FUME_REQUEST_BODY_LIMIT?: string;
    FUME_EVAL_THROW_LEVEL?: number;
    FUME_EVAL_LOG_LEVEL?: number;
    FUME_EVAL_DIAG_COLLECT_LEVEL?: number;
    FUME_EVAL_VALIDATION_LEVEL?: number;
    FHIR_SERVER_BASE: string;
    FHIR_SERVER_TIMEOUT: number;
    FHIR_VERSION: string;
    FHIR_PACKAGES: string;
    FHIR_SERVER_AUTH_TYPE: string;
    FHIR_SERVER_UN: string;
    FHIR_SERVER_PW: string;
    FHIR_CONNECTIONS_FILE?: string;
    FHIR_CONNECTIONS_URL_POOL_SIZE?: number;
    FHIR_PACKAGE_REGISTRY_URL?: string;
    FHIR_PACKAGE_REGISTRY_TOKEN?: string;
    FHIR_PACKAGE_CACHE_DIR?: string;
    FHIR_PACKAGE_REGISTRY_ALLOW_HTTP?: boolean;
    MAPPINGS_FOLDER?: string;
    MAPPINGS_FILE_EXTENSION?: string;
    MAPPINGS_FILE_POLLING_INTERVAL_MS?: number;
    MAPPINGS_SERVER_POLLING_INTERVAL_MS?: number;
    MAPPINGS_FORCED_RESYNC_INTERVAL_MS?: number;
    FUME_COMPILED_EXPR_CACHE_MAX_ENTRIES?: number;
}

/**
 * © Copyright Outburn Ltd. 2022-2024 All Rights Reserved
 *   Project name: FUME-COMMUNITY
 */
type ConnectionAuthType = 'NONE' | 'BASIC';
interface ConnectionConfig {
    name: string;
    baseUrl: string;
    fhirVersion?: string;
    authType?: ConnectionAuthType;
    username?: string;
    password?: string;
    timeout?: number;
}
interface ConnectionsFile {
    fhir: ConnectionConfig[];
}

/**
 * © Copyright Outburn Ltd. 2022-2024 All Rights Reserved
 *   Project name: FUME-COMMUNITY
 */

type IAppBinding = unknown;
/**
 * Transport-agnostic engine interface.
 * Implemented by {@link FumeEngine}.
 */
interface IFumeEngine<ConfigType extends IConfig = IConfig> {
    registerBinding: (key: string, binding: IAppBinding) => void;
    getBindings: () => Record<string, IAppBinding>;
    getConfig: () => ConfigType;
    getLogger: () => Logger;
    getFhirClient: () => FhirClient;
    getMappingProvider: () => FumeMappingProvider;
    convertInputToJson: (input: unknown, contentType?: string) => Promise<unknown>;
    /**
     * Evaluate a mapping and return a full verbose report.
     *
     * `extraBindings` are merged *after* the engine's global bindings and therefore override them.
     * This is the supported way for JS/module consumers to override fumifier policy thresholds per call:
     * - `throwLevel`
     * - `logLevel`
     * - `collectLevel`
     * - `validationLevel`
     *
     * Note: the HTTP API does not currently allow arbitrary bindings to be provided by clients.
     */
    transformVerbose: (input: unknown, expression: string, extraBindings?: Record<string, IAppBinding>) => Promise<EvaluateVerboseReport>;
    /**
     * Evaluate a mapping and return only the transformed result (throws on fatal/unhandled failures).
     *
     * See `transformVerbose` for how `extraBindings` overrides global bindings (including threshold overrides).
     */
    transform: (input: unknown, expression: string, extraBindings?: Record<string, IAppBinding>) => Promise<unknown>;
}

/**
 * © Copyright Outburn Ltd. 2022-2024 All Rights Reserved
 *   Project name: FUME-COMMUNITY
 */

type FumeEngineCreateOptions<ConfigType extends IConfig = IConfig> = {
    /** Required runtime config (validated & normalized). */
    config: Partial<ConfigType> | ConfigType;
    /** Optional injections (set once). */
    logger?: Logger;
    astCache?: NonNullable<FumifierOptions['astCache']>;
    /** Initial global bindings (set once during create). */
    bindings?: Record<string, IAppBinding>;
};

/**
 * © Copyright Outburn Ltd. 2022-2024 All Rights Reserved
 *   Project name: FUME-COMMUNITY
 */

/**
 * HTTP/Express wrapper around a {@link IFumeEngine}.
 *
 * The server should not expose engine capabilities directly; downstream consumers
 * can access the engine via {@link getEngine}.
 */
interface IFumeServer<ConfigType extends IConfig = IConfig> {
    getExpressApp: () => Application;
    getEngine: () => IFumeEngine<ConfigType>;
    registerAppMiddleware: (middleware: RequestHandler) => void;
    registerBinding: (key: string, binding: unknown) => void;
    shutDown: () => Promise<void>;
}

/**
 * © Copyright Outburn Ltd. 2022-2024 All Rights Reserved
 *   Project name: FUME-COMMUNITY
 */

type OpenApiSpec = OpenAPIV3.Document;
type OpenApiSpecFactory = (base: OpenApiSpec) => OpenApiSpec;
type FumeServerCreateOptions<ConfigType extends IConfig = IConfig> = {
    config: Partial<ConfigType> | ConfigType;
    engine?: Omit<FumeEngineCreateOptions<ConfigType>, 'config'>;
    /**
     * Optional hook that runs BEFORE the built-in FUME HTTP router is mounted.
     * Allows downstream routes/middleware to take precedence.
     */
    configureApp?: (app: Application, server: IFumeServer<ConfigType>) => void;
    /** Optional initial app middleware (license gates, auth, etc.). */
    appMiddleware?: RequestHandler;
    /**
     * Override or extend the OpenAPI spec served at GET /api-docs/swagger.json and used by /api-docs.
     * Can be a static object or a factory function that takes the default spec as input
     * and returns a modified version.
     * Useful for adding custom endpoints, metadata, or modifying the spec
     * without changing the source YAML file.
     */
    openApiSpec?: OpenApiSpec | OpenApiSpecFactory;
};

/**
 * © Copyright Outburn Ltd. 2022-2024 All Rights Reserved
 *   Project name: FUME-COMMUNITY
 */

interface GlobalFhirContext {
    navigator: FhirStructureNavigator | null;
    generator: FhirSnapshotGenerator | null;
    terminologyRuntime: FhirTerminologyRuntime | null;
    contextPackages: FhirPackageIdentifier[];
    normalizedPackages: FhirPackageIdentifier[];
    fhirVersion: FhirVersion;
    cachePath?: string;
    registryUrl?: string;
    registryToken?: string;
    isInitialized: boolean;
}
declare class FumeEngine<ConfigType extends IConfig = IConfig> {
    private readonly config;
    private bindings;
    private readonly logger;
    private fhirClient?;
    private namedConnectionNames;
    private namedClients;
    private urlClientPool?;
    private mappingProvider?;
    private globalFhirContext;
    private readonly compiledExpressionCacheMaxEntries;
    private compiledExpressionCache;
    private astCache?;
    private formatConverter?;
    private startupTime;
    private constructor();
    static create<ConfigType extends IConfig = IConfig>(options: FumeEngineCreateOptions<ConfigType>): Promise<FumeEngine<ConfigType>>;
    private getEngineLogger;
    private getChildLogger;
    getLogger(): Logger;
    registerBinding(key: string, binding: IAppBinding): void;
    getBindings(): Record<string, unknown>;
    getFhirClient(): FhirClient;
    getMappingProvider(): FumeMappingProvider;
    getConfig(): ConfigType;
    getFhirVersion(): FhirVersion;
    getGlobalFhirContext(): GlobalFhirContext;
    getUptime(): string;
    getContextPackages(): FhirPackageIdentifier[];
    getNormalizedPackages(): FhirPackageIdentifier[];
    resetGlobalFhirContext(): void;
    private initialize;
    private static normalizeFhirServerBase;
    private static normalizeMappingsFolder;
    private getOrCreateFormatConverter;
    convertInputToJson(input: unknown, contentType?: string): Promise<any>;
    private createFhirClient;
    private createNamedFhirClient;
    private initializeGlobalFhirContext;
    private createMappingCache;
    private createConnectionResolver;
    private getFumifierOptions;
    private compileExpression;
    private getCompiledExpressionCacheKey;
    private getStaticValueBindings;
    private getEvaluationBindings;
    transformVerbose(input: unknown, expression: string, extraBindings?: Record<string, IAppBinding>): Promise<EvaluateVerboseReport>;
    transform(input: unknown, expression: string, extraBindings?: Record<string, IAppBinding>): Promise<unknown>;
    recacheFromServer(): Promise<boolean>;
}

declare class FumeServer<ConfigType extends IConfig> implements IFumeServer<ConfigType> {
    private readonly app;
    private server?;
    private readonly engine;
    private bodyParserCache?;
    private appMiddleware;
    private constructor();
    static create<ConfigType extends IConfig = IConfig>(options: FumeServerCreateOptions<ConfigType>): Promise<FumeServer<ConfigType>>;
    shutDown(): Promise<void>;
    registerBinding(key: string, binding: unknown): void;
    /**
     * Access the underlying, transport-agnostic engine.
     * Downstream projects should use this instead of server-level proxy methods.
     */
    getEngine(): IFumeEngine<ConfigType>;
    /**
       * @returns express application
       */
    getExpressApp(): express.Application;
    /**
     * Register application level middleware to intercept all requests
     * @param middleware
     */
    registerAppMiddleware(middleware: RequestHandler): void;
}

/**
 * © Copyright Outburn Ltd. 2022-2024 All Rights Reserved
 *   Project name: FUME-COMMUNITY
 */

declare const FumeConfigSchema: z.ZodObject<{
    SERVER_PORT: z.ZodPreprocess<z.ZodDefault<z.ZodNumber>>;
    FUME_REQUEST_BODY_LIMIT: z.ZodDefault<z.ZodString>;
    FUME_EVAL_THROW_LEVEL: z.ZodPreprocess<z.ZodDefault<z.ZodNumber>>;
    FUME_EVAL_LOG_LEVEL: z.ZodPreprocess<z.ZodDefault<z.ZodNumber>>;
    FUME_EVAL_DIAG_COLLECT_LEVEL: z.ZodPreprocess<z.ZodDefault<z.ZodNumber>>;
    FUME_EVAL_VALIDATION_LEVEL: z.ZodPreprocess<z.ZodDefault<z.ZodNumber>>;
    FHIR_SERVER_BASE: z.ZodPreprocess<z.ZodDefault<z.ZodUnion<[z.ZodString, z.ZodLiteral<"n/a">]>>>;
    FHIR_SERVER_AUTH_TYPE: z.ZodDefault<z.ZodString>;
    FHIR_SERVER_UN: z.ZodDefault<z.ZodString>;
    FHIR_SERVER_PW: z.ZodDefault<z.ZodString>;
    FHIR_CONNECTIONS_FILE: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
    FHIR_CONNECTIONS_URL_POOL_SIZE: z.ZodPreprocess<z.ZodDefault<z.ZodNumber>>;
    FHIR_SERVER_TIMEOUT: z.ZodPreprocess<z.ZodDefault<z.ZodNumber>>;
    FHIR_VERSION: z.ZodDefault<z.ZodString>;
    FHIR_PACKAGES: z.ZodDefault<z.ZodString>;
    FHIR_PACKAGE_REGISTRY_URL: z.ZodOptional<z.ZodPreprocess<z.ZodUnion<[z.ZodString, z.ZodLiteral<"n/a">]>>>;
    FHIR_PACKAGE_REGISTRY_TOKEN: z.ZodOptional<z.ZodString>;
    FHIR_PACKAGE_CACHE_DIR: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
    MAPPINGS_FOLDER: z.ZodPreprocess<z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodLiteral<"n/a">]>>>;
    MAPPINGS_FILE_EXTENSION: z.ZodPreprocess<z.ZodOptional<z.ZodString>>;
    MAPPINGS_FILE_POLLING_INTERVAL_MS: z.ZodOptional<z.ZodPreprocess<z.ZodNumber>>;
    MAPPINGS_SERVER_POLLING_INTERVAL_MS: z.ZodOptional<z.ZodPreprocess<z.ZodNumber>>;
    MAPPINGS_FORCED_RESYNC_INTERVAL_MS: z.ZodOptional<z.ZodPreprocess<z.ZodNumber>>;
    FUME_COMPILED_EXPR_CACHE_MAX_ENTRIES: z.ZodPreprocess<z.ZodDefault<z.ZodNumber>>;
}, z.core.$strip>;

export { type ConnectionAuthType, type ConnectionConfig, type ConnectionsFile, FumeConfigSchema, FumeEngine, type FumeEngineCreateOptions, FumeServer, type FumeServerCreateOptions, type IAppBinding, type ICache, type IConfig, type IFumeEngine, type IFumeServer, type OpenApiSpec, type OpenApiSpecFactory };
