import * as express from 'express';
import { Express, Application } from 'express';
import { EventEmitter } from 'node:events';
import { BodyParser, OptionsJson, OptionsText, OptionsUrlencoded } from 'body-parser';
import { CompressionOptions } from 'compression';
import { CookieParseOptions } from 'cookie-parser';
import { CorsOptions } from 'cors';
import { DotenvConfigOptions } from 'dotenv';
import { Options } from 'express-rate-limit';
import { SessionOptions } from 'express-session';

declare function companion(
  options: companion.CompanionOptions
): companion.CompanionReturn;

/**
 * Configuration interface for the Companion plugin.
 */
interface CompanionOptions {
  /**
   * Name of the application.
   */
  name: string;

  /**
   * Hostname or IP address to listen on (defaults to 'localhost').
   */
  host?: string;

  /**
   * Port number to listen on (defaults to 3000).
   */
  port?: number;

  /**
   * Secret key used for session management and other security features.
   * Required if using session middleware.
   */
  secretKey?: string;

  /**
   * Directory for serving static files (defaults to 'public').
   */
  publicDir?: string;

  /**
   * Directory for storing view templates (defaults to 'views').
   */
  viewsDir?: string;

  /**
   * View engine to use (defaults to 'ejs'). Can be disabled (false) or any supported engine.
   */
  viewEngine?: false | string;

  /**
   * Allowed HTTP methods for the application (defaults to ['GET', 'POST', 'PUT', 'DELETE']).
   */
  allowedMethods?: Array<"GET" | "POST" | "PUT" | "DELETE">;

  /**
   * Flag to enable/distable automatic express server creation (defaults to true).
   * Can be disabled (false) if you want to use your own express server.
   */
  express?: true | Express;

  /**
   * Configuration options for custom request/response headers.
   */
  headers?: OptionsHeaders;

  /**
   * Configuration options for various middleware functionalities.
   */
  middlewares?: OptionsMiddlewares;
}

/**
 * Interface for custom request/response header configuration.
 */
interface OptionsHeaders {
  /**
   * Value for the X-Powered-By header. Can be disabled (false) or a custom string.
   */
  xPoweredBy?: boolean | string;

  /**
   * Function to generate a unique request ID or a boolean (true/false) to enable/distable.
   */
  xRequestId?: boolean | (() => string);

  /**
   * Flag to enable/distable including the user-agent header (defaults to true).
   */
  xUserAgent?: boolean;

  /**
   * Flag to enable/distable including the real IP address (defaults to true).
   */
  xRealIp?: boolean;

  /**
   * Flag to enable/distable including the X-Forwarded-For header (defaults to true).
   */
  xForwardedFor?: boolean;
}

/**
 * Interface for configuration options of various middleware functionalities.
 */
interface OptionsMiddlewares {
  /**
   * Options for loading environment variables via the `dotenv` library.
   */
  env?: DotenvConfigOptions;

  /**
   * Configuration for rate limiting requests using the `express-rate-limit` library.
   */
  rateLimit?: Options;

  /**
   * Options for enabling CORS (Cross-Origin Resource Sharing) using the `cors` library.
   */
  cors: CorsOptions;

  /**
   * Configuration for compressing responses using the `compression` library.
   */
  compression?: CompressionOptions;

  /**
   * Options for CSRF (Cross-Site Request Forgery) protection.
   * Specific types depend on the chosen library.
   */
  csrf?: unknown;

  /**
   * Configuration for session management using the `express-session` library.
   */
  session?: boolean | SessionOptions;

  /**
   * Configuration for parsing cookies using the `cookie-parser` library.
   */
  cookieParser?: boolean | CookieParseOptions;

  /**
   * Configuration for parsing request bodies using the `body-parser` library.
   */
  bodyParser?: boolean | BodyParser;

  /**
   * Options for parsing JSON request bodies.
   */
  jsonParser?: boolean | OptionsJson;

  /**
   * Options for parsing text request bodies.
   */
  textParser?: boolean | OptionsText;

  /**
   * Options for parsing urlencoded request bodies.
   */
  urlencodedParser?: boolean | OptionsUrlencoded;

  /**
   * Configuration for custom middleware functions.
   */
  custom?: OptionsCustomMiddleware[];
}

/**
 * Interface for defining custom middleware functionalities.
 */
interface OptionsCustomMiddleware {
  /**
   * Name for the custom middleware.
   */
  name: string;

  /**
   * Placement of the middleware in the request processing pipeline.
   * Can be "pre-middleware" or "post-middleware".
   */
  place: "pre-middleware" | "post-middleware";

  /**
   * Options object or function that defines the custom middleware behavior.
   * The type of options can vary depending on the specific middleware implementation.
   */
  options:
    | unknown
    | ((
        req: express.Request,
        res: express.Response,
        next: express.NextFunction
      ) => void);
}

/**
 * Return type for the companion plugin function.
 */
interface CompanionReturn {
  /**
   * The configured Express application instance.
   */
  server: Application;

  /**
   * Accessor for environment variables (if `env` middleware is used).
   */
  readonly env: unknown; // Separate interface for environment variables

  /**
   * The loaded configuration object.
   */
  readonly config: CompanionOptions;

  /**
   * Error object encountered during plugin setup (optional).
   */
  error?: Error;

  /**
   * Function for logging messages (optional).
   */
  logger?: (message: string) => void;

  /**
   * Function for channel-specific debugging messages (optional).
   */
  debug?: (channel: string, message: string) => void;

  /**
   * Event emitter for plugin events (optional).
   */
  events?: EventEmitter; // Utilize the EventEmitter library
}

export { type CompanionOptions, type CompanionReturn, type OptionsCustomMiddleware, type OptionsHeaders, type OptionsMiddlewares, companion as default };
