import * as _koa_router from '@koa/router';
import * as express_serve_static_core from 'express-serve-static-core';
import * as koa from 'koa';
import { Context, Next } from 'koa';
import * as http from 'http';
import { FastifyRequest } from 'fastify/types/request';
import * as fastify from 'fastify';
import { FastifyReply, HookHandlerDoneFunction } from 'fastify';
import * as express from 'express';
import { Request, Response, NextFunction } from 'express';
import { Schema } from 'mongoose';

interface ExtendedFastifyRequest extends FastifyRequest {
    startTime: number;
    userId: string;
}

type TActionMap = {
    auth: "login" | "logout" | "signup" | "password_reset" | "password_update" | "token_refreshed" | "session_expired" | "2fa_requested" | "2fa_verified" | "unauthorized" | "account_locked" | "email_verified" | "email_verification_sent";
    billing: "payment_success" | "payment_failed" | "subscription_created" | "subscription_cancelled";
    system: "start" | "stop" | "restart";
    error: "server_error" | "client_error" | "validation_error";
};
type TMessages = {
    login: "User logged in successfully.";
    logout: "User logged out.";
    signup: "New user signed up.";
    password_reset: "Password reset requested.";
    password_update: "User updated their password.";
    token_refreshed: "Authentication token was refreshed.";
    session_expired: "User session has expired.";
    "2fa_requested": "Two-factor authentication requested.";
    "2fa_verified": "Two-factor authentication verified.";
    unauthorized: "Unauthorized access attempt detected.";
    account_locked: "User account has been locked.";
    email_verified: "Email address successfully verified.";
    email_verification_sent: "Verification email sent to user.";
    payment_success: "Payment completed successfully.";
    payment_failed: "Payment attempt failed.";
    subscription_created: "New subscription created.";
    subscription_cancelled: "Subscription has been cancelled.";
    start: "System has started.";
    stop: "System has stopped.";
    restart: "System has been restarted.";
    server_error: "A server error has occurred.";
    client_error: "A client-side error has occurred.";
    validation_error: "Validation failed for the provided data.";
};
type TDestinations = "console" | "file" | "remote";
type TKnownEvent = {
    [K in keyof TActionMap]: TActionMap[K] extends infer Actions ? Actions extends keyof TMessages ? {
        [A in Actions]: {
            type: K;
            action: A;
            message: TMessages[A];
        };
    }[Actions] : never : never;
}[keyof TActionMap];
type TAuditOptions<F extends Framework> = {
    destinations?: TDestinations[];
    logger?: Logger;
    dbType?: 'none' | 'mongoose';
    framework?: F;
    useTimeStamp?: boolean;
    splitFiles?: boolean;
    captureSystemErrors?: boolean;
    useUI?: boolean;
};
type TCustomEvent = {
    type: Exclude<string, keyof TActionMap>;
    action: string;
    message: string;
};
type TEvent = TKnownEvent | TCustomEvent;
type TFileConfig = {
    fileName: string;
    folderName: string;
    fullPath: string;
};
type ExpressLogger = (req: Request, res: Response, next: NextFunction) => void;
type KoaLogger = (ctx: Context, next: Next) => Promise<void>;
type FastifyLogger = {
    onRequest: (request: ExtendedFastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => void;
    onResponse: (request: ExtendedFastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => void;
};
type SupportedLoggersRequest = {
    express: ExpressLogger;
    koa: KoaLogger;
    fastify: FastifyLogger;
};
type Framework = keyof SupportedLoggersRequest;
type Logger = {
    info: (...args: any[]) => void;
    error: (...args: any[]) => void;
    warn: (...args: any[]) => void;
};

declare class Audit<F extends Framework = "express"> {
    private options?;
    private logFilePath;
    private defaultFileConfigs;
    private fileConfig;
    private isInitialized;
    private auditOptions;
    /**
     * Creates an instance of the Auditor class with the provided options.
     *
     * @param options - Optional configuration object for the auditor.
     *   - `logger`: Custom logger to use; defaults to `console` if not provided.
     *   - `dbType`: Type of database to use; defaults to `"none"`.
     *   - `destinations`: Array of destinations for audit logs; defaults to `["console"]`.
     *   - `framework`: The framework being used (e.g., "express"); defaults to `"express"`.
     *   - `useTimeStamp`: Whether to include timestamps in logs; defaults to `true`.
     *   - `splitFiles`: Whether to split logs into multiple files; defaults to `false`.
     *   - `captureSystemErrors`: Whether to capture system errors; defaults to `false`.
     *
     * Initializes the `auditOptions` property by merging the provided options with sensible defaults.
     */
    constructor(options?: TAuditOptions<F> | undefined);
    /**
     * Initializes the auditor by creating the necessary file location and logging a success message.
     *
     * This method sets up the audit configuration by invoking `CreateFileLocation` with the current file configuration,
     * and logs a confirmation message using the configured logger.
     *
     * @remarks
     * Should be called before performing any audit operations to ensure the environment is properly configured.
     */
    Setup(): Promise<void>;
    /**
     * Logs an event to the configured destinations (console and/or file).
     *
     * Depending on the configuration, this method will:
     * - Add a timestamp to the event if `useTimeStamp` is enabled.
     * - Log the event to the console if "console" is included in `destinations`.
     * - Log the event to a file if "file" is included in `destinations`.
     *   - If `splitFiles` is enabled, logs to a specific action log file.
     *   - Otherwise, logs to the default file configuration.
     * - If the file path is not set when logging to a file, logs an error.
     *
     * @param event - The event object to be logged.
     */
    Log(event: TEvent): void;
    /**
        * Logs an error event to the configured destinations (console and/or file).
        * @example
        * LogError(new Error("Unexpected failure"))
        * Logs error details to the console and file depending on configuration.
        * @param {any} error - The error object to be logged.
        * @description
        *   - Extracts the error stack trace to capture informative details.
        *   - Compiles additional user context such as IP and user agent when available.
        *   - Handles uninitialized state by printing a warning message.
        *   - Utilizes timestamp inclusion and log destination logic based on audit options.
        */
    LogError(error: any): void;
    /**
     * Audits a given schema model by invoking the `auditModel` function with the current configuration,
     * a generated timestamp, and the provided schema.
     *
     * @template T - The type of the schema being audited.
     * @param schema - The schema object to be audited.
     */
    AuditModel<T>(schema: Schema<T>): void;
    /**
     * Configures the file logging settings for the auditor.
     *
     * This method sets up the file configuration used for logging audit events to a file.
     * It checks if "file" is included in the destinations and if split file logging is disabled.
     * If these conditions are not met, it logs appropriate warnings and returns early.
     * Otherwise, it sets up the file configuration with the provided options or defaults.
     *
     * @param config - Optional configuration object for the file logger, excluding the `fullPath` property.
     *   - `folderName` (optional): The folder where the log file will be stored. Defaults to `"audit"`.
     *   - `fileName` (optional): The name of the log file. Defaults to `"audit.log"`.
     */
    SetFileConfig(config: Omit<TFileConfig, "fullPath">): void;
    /**
     * Logs all incoming requests using the configured logger.
     *
     * Depending on the `splitFiles` configuration, this method will either:
     * - Log requests to a dedicated "request.log" file if `splitFiles` is enabled.
     * - Log requests to the default log file otherwise.
     *
     * @returns The result of the `requestLogger` function, which handles the actual logging process.
     */
    RequestLogger(): SupportedLoggersRequest[F];
    /**
     * Logs all errors using the configured error logger.
     *
     * If the `splitFiles` option is enabled in the configuration, errors are logged to a separate
     * "error.log" file as specified in the default file configurations. Otherwise, errors are logged
     * to the main file configuration.
     *
     * @returns The result of the error logger function, which handles error logging based on the current configuration.
     */
    ErrorLogger(): {
        express: (err: any, req: express.Request, res: express.Response, next: express.NextFunction) => void;
        fastify: (error: fastify.FastifyError, request: ExtendedFastifyRequest, reply: fastify.FastifyReply) => fastify.FastifyReply<fastify.RouteGenericInterface, fastify.RawServerDefault, http.IncomingMessage, http.ServerResponse<http.IncomingMessage>, unknown, fastify.FastifySchema, fastify.FastifyTypeProviderDefault, unknown>;
        koa: (ctx: koa.Context, next: koa.Next) => Promise<void>;
    }[F];
    /**
     * Asynchronously creates and returns the UI component or handler based on the specified framework
     * in the audit options.
     *
     * @returns {Promise<any>} A promise that resolves to the UI component or handler corresponding to the selected framework.
     */
    CreateUI(): {
        express: () => Promise<((req: any, res: any, next: any) => any) | express_serve_static_core.Router>;
        fastify: () => Promise<(fastify: any, opts: any) => Promise<void>>;
        koa: () => Promise<koa.Middleware<koa.DefaultState, koa.DefaultContext & _koa_router.RouterParamContext<koa.DefaultState, koa.DefaultContext>, any>>;
    }[F];
    private CreateFileLocation;
    private GenerateFile;
    /**
        * Sets up system error handling and logging for audit purposes.
        * @example
        * handleSystemErrors()
        * Initializes processes to log exceptions, rejections, signals, and exits.
        * @description
        *   - Listens for Node.js process events such as uncaught exceptions, unhandled rejections, SIGTERM, SIGINT, and exit.
        *   - Utilizes the `generateAuditContent` utility to format the logs.
        *   - Logs generated content using `handleLog` with the error file configuration.
        *   - Only activates if `captureSystemErrors` is true within audit options.
        */
    private HandleSystemErrors;
}

export { Audit as Auditor, type TAuditOptions, type TEvent, type TFileConfig };
