import { IOGateway } from '@interopio/gateway';
import type { ManagementEndpoint } from './manage.d.ts';
import type { ServerConfigurer, ServerCorsConfig, ServerWebSocketOptions } from './web/server.d.ts'

/**
 * SSL/TLS configuration.
 * All key and certificate files must be in PEM format.
 */
export type SslConfig = {
    /** Path to server private key file (PEM format) */
    key?: string,
    /** Path to server certificate file (PEM format) */
    cert?: string,
    /** Path to CA certificate for client certificate verification (PEM format) */
    ca?: string,
    /**
     *  Passphrase for encrypted private key
     * @since 0.20.0
     */
    passphrase?: string,
    /**
     * Request client certificate during TLS handshake.
     * When false (default), clients will not send certificates.
     * When true, clients are asked to send a certificate.
     * @since 0.20.0
     */
    requestCert?: boolean,
    /**
     * Reject clients with invalid or missing certificates.
     * Only effective when requestCert is true.
     * When false, clients without valid certs are still allowed.
     * When true, enforces mutual TLS authentication.
     * @since 0.20.0
     */
    rejectUnauthorized?: boolean
}

export type AuthConfig = {
    type: 'none'
        | 'basic'
        | 'x509' // since 0.20.0
        | 'oauth2'
    ,
    /** X.509 client certificate authentication configuration
     * @since 0.20.0
     */
    x509?: {
        /** Path to CA private key file (PEM format), for generating client certificates and server certificates */
        key?: string,
        /** Passphrase for encrypted CA private key */
        passphrase?: string,
        /** Extract principal from Subject Alternative Name. Use 'email' to extract from email SAN. If undefined, uses subject (default). */
        principalAltName?: 'email'
    },
    /** Basic authentication configuration */
    basic?: {
        realm?: string
    },
    /** OAuth2 authentication configuration */
    oauth2?: {
        jwt: { issuerUri: string, issuer?: string, audience?: string | string[] }
    },
    // in-memory user for basic auth
    user?: { name: string, password?: string, readonly roles?: string[] }
};

export type ServerCustomizer = (configurer: ServerConfigurer, config: ServerConfig) => Promise<void>;

export type ServerConfig = {
    /**
     * The port to bind for network communication.
     * Accepts a single value or a range.
     * If a range is specified, will bind to the first available port in the range.
     *
     * @defaultValue 0 (random port)
     */
    port?: number | string
    /**
     * The network address.
     */
    host?: string
    ssl?: SslConfig,
    // http2?: {
    //     enabled: boolean
    // }
    // node:http server options
    http?: {
        maxHeaderSize?: number,
    },
    /**
     * Management configuratoni.
     */
    management?: {
        server: ManagementEndpoint & {
            // node:net listen options
        },
        commands?: {
            // shutdown, info, etc
            [command: string]: {
                enabled?: boolean,
                // command specific options
                [key: string]: unknown
            }
        }
    }

    auth?: AuthConfig,
    /**
     * CORS configuration.
     */
    cors?: false | ServerCorsConfig,

    memory?: {
        memory_limit?: number
        dump_location?: string,
        dump_prefix?: string,
        report_interval?: number,
        max_backups?: number,
    },

    app?: ServerCustomizer,
    resources?: {
        enabled?: boolean,
        locations: string[]
    },
    gateway?: IOGateway.GatewayConfig & ServerWebSocketOptions & {
        route?: string,
        /**
         * Gateway scope - determines how gateway instances are managed:
         * - 'principal': Each authenticated principal gets their own gateway instance.
         *                A default (shared) gateway instance handles all unauthenticated connections.
         * - 'singleton': All connections share the same gateway instance
         *
         * @defaultValue 'principal'
         * @since 0.20.0
         */
        scope?: 'singleton' | 'principal',
        mesh?: IOGateway.MeshConfig & {
            enabled?: boolean
        }
        metrics?: IOGateway.MetricsConfig & {
            enabled?: boolean
        }
    }
}

export function defineConfig(config: ServerConfig): ServerConfig;
