import * as plugins from '../../../plugins.js';
import type { WrappedSocket } from '../../../core/models/wrapped-socket.js';
// Certificate types removed - define IAcmeOptions locally
export interface IAcmeOptions {
  enabled?: boolean;
  email?: string; // Required when any route uses certificate: 'auto'
  environment?: 'production' | 'staging';
  accountEmail?: string; // Alias for email
  port?: number; // Port for HTTP-01 challenges (default: 80)
  useProduction?: boolean; // Use Let's Encrypt production (default: false)
  renewThresholdDays?: number; // Days before expiry to renew (default: 30)
  autoRenew?: boolean; // Enable automatic renewal (default: true)
  skipConfiguredCerts?: boolean;
  renewCheckIntervalHours?: number; // How often to check for renewals (default: 24)
  routeForwards?: any[];
}

/**
 * Consumer-provided certificate storage.
 * SmartProxy never writes certs to disk — the consumer owns all persistence.
 */
export interface ISmartProxyCertStore {
  /** Load all stored certs on startup (called once before cert provisioning) */
  loadAll: () => Promise<Array<{ domain: string; publicKey: string; privateKey: string; ca?: string }>>;
  /** Save a cert after successful provisioning */
  save: (domain: string, publicKey: string, privateKey: string, ca?: string) => Promise<void>;
  /** Remove a cert (optional) */
  remove?: (domain: string) => Promise<void>;
}
import type { IRouteConfig } from './route-types.js';

export interface ISmartProxySecurityPolicy {
  blockedIps?: string[];
  blockedCidrs?: string[];
}

export interface ISmartProxyChallengeOptions {
  /** Runtime-only cookie signing key. If omitted, SmartProxy generates an ephemeral key. */
  cookieSigningKey?: string;
  pendingCookieName?: string;
  clearanceCookieName?: string;
  reservedPathPrefix?: string;
  relaySocketPath?: string;
  relayTimeoutMs?: number;
  pendingTtlSeconds?: number;
}

/**
 * Provision object for static or HTTP-01 certificate
 */
export interface ISmartProxyCertProvisionCertificate extends plugins.tsclass.network.ICert {
  ca?: string;
}

export type TSmartProxyCertProvisionObject = ISmartProxyCertProvisionCertificate | 'http01';

/**
 * Communication channel passed as second argument to certProvisionFunction.
 * Allows the callback to report metadata back to SmartProxy for event emission.
 */
export interface ICertProvisionEventComms {
  /** Informational log */
  log: (message: string) => void;
  /** Warning (non-fatal) */
  warn: (message: string) => void;
  /** Error */
  error: (message: string) => void;
  /** Set the certificate expiry date (for the issued event) */
  setExpiryDate: (date: Date) => void;
  /** Set the source/method used for provisioning (e.g. 'smartacme-dns-01') */
  setSource: (source: string) => void;
}

/** Payload for 'certificate-issued' and 'certificate-renewed' events */
export interface ICertificateIssuedEvent {
  domain: string;
  expiryDate?: string;   // ISO 8601
  source: string;        // e.g. 'certProvisionFunction', 'smartacme-dns-01'
  isRenewal?: boolean;
}

/** Payload for 'certificate-failed' event */
export interface ICertificateFailedEvent {
  domain: string;
  error: string;
  source: string;
}

export interface IActiveConnectionSnapshotOptions {
  /** Maximum number of snapshots to return. Defaults to 1000, capped by Rust at 10000. */
  limit?: number;
  /** Optional route id filter. */
  routeId?: string;
}

export interface IActiveConnectionSnapshot {
  id: number;
  sourceIp: string;
  sourcePort: number | null;
  localPort: number;
  domain: string | null;
  routeId: string | null;
  targetHost: string | null;
  targetPort: number | null;
  protocol: string | null;
  state: string;
  startedAtMs: number;
  ageMs: number;
  bytesIn: number;
  bytesOut: number;
}

// Legacy options and type checking functions have been removed

/**
 * SmartProxy configuration options
 */
export interface ISmartProxyOptions {
  // The unified configuration array (required)
  routes: IRouteConfig[];

  // Port configuration
  preserveSourceIP?: boolean;  // Preserve client IP when forwarding

  // PROXY protocol configuration
  trustedProxyIPs?: string[];  // Global trusted IP/CIDR list for inbound PROXY protocol
  sendProxyProtocol?: boolean;  // Global option to send PROXY protocol to all targets

  // Global/default settings
  defaults?: {
    target?: {
      host: string; // Default host to use when not specified in routes
      port: number; // Default port to use when not specified in routes
    };
    security?: {
      ipAllowList?: string[]; // Default allowed IPs
      ipBlockList?: string[]; // Default blocked IPs
      maxConnections?: number; // Default max connections
    };
    preserveSourceIP?: boolean; // Default source IP preservation
  };

  // TLS options
  pfx?: Buffer;
  key?: string | Buffer | Array<Buffer | string>;
  passphrase?: string;
  cert?: string | Buffer | Array<string | Buffer>;
  ca?: string | Buffer | Array<string | Buffer>;
  ciphers?: string;
  honorCipherOrder?: boolean;
  rejectUnauthorized?: boolean;
  secureProtocol?: string;
  servername?: string;
  minVersion?: string;
  maxVersion?: string;

  // Timeout settings
  connectionTimeout?: number; // Timeout for establishing connection to backend (ms), default: 60000 (60s)
  initialDataTimeout?: number; // Timeout for initial data/SNI (ms), default: 60000 (60s)
  socketTimeout?: number; // Socket inactivity timeout (ms), default: 60000 (60s)
  inactivityCheckInterval?: number; // How often to check for inactive connections (ms), default: 60000 (60s)
  maxConnectionLifetime?: number; // Max connection lifetime (ms), default: 3600000 (1h)
  inactivityTimeout?: number; // Inactivity timeout (ms), default: 75000 (75s)

  gracefulShutdownTimeout?: number; // (ms) maximum time to wait for connections to close during shutdown

  // Socket optimization settings
  noDelay?: boolean; // Disable Nagle's algorithm (default: true)
  keepAlive?: boolean; // Enable TCP keepalive (default: true)
  keepAliveInitialDelay?: number; // Initial delay before sending keepalive probes (ms)
  maxPendingDataSize?: number; // Maximum bytes to buffer during connection setup

  // Enhanced features
  disableInactivityCheck?: boolean; // Disable inactivity checking entirely
  enableKeepAliveProbes?: boolean; // Enable TCP keep-alive probes
  enableDetailedLogging?: boolean; // Enable detailed connection logging
  enableTlsDebugLogging?: boolean; // Enable TLS handshake debug logging
  enableRandomizedTimeouts?: boolean; // Randomize timeouts slightly to prevent thundering herd

  // Rate limiting and security
  maxConnectionsPerIP?: number; // Maximum simultaneous connections from a single IP
  connectionRateLimitPerMinute?: number; // Max new connections per minute from a single IP
  securityPolicy?: ISmartProxySecurityPolicy; // Global ingress block policy, enforced before routing

  /** Runtime-only challenge enforcement settings. Never store this in route configs. */
  challenge?: ISmartProxyChallengeOptions;

  // Enhanced keep-alive settings
  keepAliveTreatment?: 'standard' | 'extended' | 'immortal'; // How to treat keep-alive connections
  keepAliveInactivityMultiplier?: number; // Multiplier for inactivity timeout for keep-alive connections
  extendedKeepAliveLifetime?: number; // Extended lifetime for keep-alive connections (ms)

  // Metrics configuration
  metrics?: {
    enabled?: boolean;
    sampleIntervalMs?: number;
    retentionSeconds?: number;
  };

  /**
   * Global ACME configuration options for SmartProxy
   * 
   * When set, these options will be used as defaults for all routes
   * with certificate: 'auto' that don't have their own ACME configuration.
   * Route-specific ACME settings will override these defaults.
   * 
   * Example:
   * ```ts
   * acme: {
   *   email: 'ssl@example.com',
   *   useProduction: false,
   *   port: 80
   * }
   * ```
   */
  acme?: IAcmeOptions;

  /**
   * Optional certificate provider callback. Return 'http01' to use HTTP-01 challenges,
   * or a static certificate object for immediate provisioning.
   */
  certProvisionFunction?: (domain: string, eventComms: ICertProvisionEventComms) => Promise<TSmartProxyCertProvisionObject>;
  
  /**
   * Whether to fallback to ACME if custom certificate provision fails.
   * Default: true
   */
  certProvisionFallbackToAcme?: boolean;

  /**
   * Per-domain timeout in ms for certProvisionFunction calls.
   * If a single domain's provisioning takes longer than this, it's aborted
   * and a certificate-failed event is emitted.
   * Default: 300000 (5 minutes)
   */
  certProvisionTimeout?: number;

  /**
   * Maximum number of domains to provision certificates for concurrently.
   * Prevents overwhelming ACME providers when many domains provision at once.
   * Default: 4
   */
  certProvisionConcurrency?: number;

  /**
   * Disable the default self-signed fallback certificate.
   * When false (default), a self-signed cert is generated at startup and loaded
   * as '*' so TLS handshakes never fail due to missing certs.
   */
  disableDefaultCert?: boolean;

  /**
   * Consumer-provided cert storage. SmartProxy never writes certs to disk.
   * On startup, loadAll() is called to pre-load persisted certs.
   * After each successful cert provision, save() is called.
   */
  certStore?: ISmartProxyCertStore;

  /**
   * Path to the RustProxy binary. If not set, the binary is located
   * automatically via env var, platform package, local build, or PATH.
   */
  rustBinaryPath?: string;
}

export type TChallengeProviderRegistry = Map<string, plugins.smartchallenge.IChallengeProvider>;

/**
 * Enhanced connection record
 */
export interface IConnectionRecord {
  id: string; // Unique connection identifier
  incoming: plugins.net.Socket | WrappedSocket;
  outgoing: plugins.net.Socket | WrappedSocket | null;
  incomingStartTime: number;
  outgoingStartTime?: number;
  outgoingClosedTime?: number;
  lockedDomain?: string; // Used to lock this connection to the initial SNI
  connectionClosed: boolean; // Flag to prevent multiple cleanup attempts
  cleanupTimer?: NodeJS.Timeout | null; // Timer for max lifetime/inactivity
  alertFallbackTimeout?: NodeJS.Timeout; // Timer for fallback after alert
  lastActivity: number; // Last activity timestamp for inactivity detection
  pendingData: Buffer[]; // Buffer to hold data during connection setup
  pendingDataSize: number; // Track total size of pending data

  // Enhanced tracking fields
  bytesReceived: number; // Total bytes received
  bytesSent: number; // Total bytes sent
  remoteIP: string; // Remote IP (cached for logging after socket close)
  remotePort: number; // Remote port (cached for logging after socket close)
  localPort: number; // Local port (cached for logging)
  isTLS: boolean; // Whether this connection is a TLS connection
  tlsHandshakeComplete: boolean; // Whether the TLS handshake is complete
  hasReceivedInitialData: boolean; // Whether initial data has been received
  routeConfig?: IRouteConfig; // Associated route config for this connection
  routeId?: string; // ID of the route this connection is associated with

  // Target information (for dynamic port/host mapping)
  targetHost?: string; // Resolved target host
  targetPort?: number; // Resolved target port
  tlsVersion?: string; // TLS version (for routing context)

  // Keep-alive tracking
  hasKeepAlive: boolean; // Whether keep-alive is enabled for this connection
  inactivityWarningIssued?: boolean; // Whether an inactivity warning has been issued
  incomingTerminationReason?: string | null; // Reason for incoming termination
  outgoingTerminationReason?: string | null; // Reason for outgoing termination

  // NetworkProxy tracking
  usingNetworkProxy?: boolean; // Whether this connection is using a NetworkProxy

  // Renegotiation handler
  renegotiationHandler?: (chunk: Buffer) => void; // Handler for renegotiation detection

  // Browser connection tracking
  isBrowserConnection?: boolean; // Whether this connection appears to be from a browser
  domainSwitches?: number; // Number of times the domain has been switched on this connection
  
  // NFTables tracking
  nftablesHandled?: boolean; // Whether this connection is being handled by NFTables at kernel level
  
  // HTTP-specific information (extracted from protocol detection)
  httpInfo?: {
    method?: string;
    path?: string;
    headers?: Record<string, string>;
  };
}
