// Type declarations for ioredis
declare module "ioredis" {
  import { EventEmitter } from "events";

  export interface ClusterNode {
    host: string;
    port: number;
    password?: string;
  }

  export interface RedisOptions {
    host?: string;
    port?: number;
    password?: string | ((err: Error | null) => string | null | Promise<string | null>);
    db?: number;
    keyPrefix?: string;
    lazyConnect?: boolean;
    retryStrategy?: (times: number) => number | null | void;
    maxRetriesPerRequest?: number;
    enableReadyCheck?: boolean;
    connectTimeout?: number;
    maxMemory?: number;
    showFriendlyErrorStack?: boolean;
    enableOfflineQueue?: boolean;
  }

  export interface ClusterOptions {
    lazyConnect?: boolean;
    redisOptions?: RedisOptions;
    clusterRetryStrategy?: (times: number) => number | null | void;
    maxRetriesPerRequest?: number;
  }

  export interface Pipeline {
    get(key: string): this;
    set(key: string, value: string, exMode?: string, exTime?: number): this;
    del(...keys: string[]): this;
    expire(key: string, seconds: number): this;
    scan(cursor: string, match?: string, count?: number): this;
    exec(): Promise<Array<[Error | null, unknown]>>;
  }

  export default class Redis extends EventEmitter {
    constructor(url?: string, options?: RedisOptions);
    get(key: string): Promise<string | null>;
    set(key: string, value: string, exSeconds?: number): Promise<string>;
    setex(key: string, seconds: number, value: string): Promise<string>;
    del(...keys: string[]): Promise<number>;
    expire(key: string, seconds: number): Promise<number>;
    scan(cursor: string, ...args: (string | number)[]): Promise<[string, string[]]>;
    pipeline(): Pipeline;
    on(event: string | symbol, listener: (...args: unknown[]) => void): this;
    quit(): Promise<void>;
  }

  export class Cluster extends EventEmitter {
    constructor(nodes: ClusterNode[], options?: ClusterOptions);
    get(key: string): Promise<string | null>;
    set(key: string, value: string, exSeconds?: number): Promise<string>;
    setex(key: string, seconds: number, value: string): Promise<string>;
    del(...keys: string[]): Promise<number>;
    expire(key: string, seconds: number): Promise<number>;
    scan(cursor: string, ...args: (string | number)[]): Promise<[string, string[]]>;
    pipeline(): Pipeline;
    on(event: string | symbol, listener: (...args: unknown[]) => void): this;
    quit(): Promise<void>;
  }
}
