// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

import { EventEmitter } from 'node:events';
import type {
  ClientConfig,
  ClientConfigOrString,
  ClientCredentials, CommandResponse,
  PasswordCredentials, RawClient, SendCommandOptions,
  TokenCredentials
} from '../client/client.type.js';
import { ResponseError, responseError } from '../wire/error.utils.js';
import { debug } from './client.debug.js';
import {
  endpointKey,
  type Endpoint,
  IggyConnection
} from './client.connection.js';
import { LOGIN, LOGIN_WITH_TOKEN, LOGOUT, PING } from '../wire/index.js';
import { GET_CLUSTER_METADATA } from '../wire/cluster/get-cluster-metadata.command.js';
import { COMMAND_CODE } from '../wire/command.code.js';
import {
  decodeVsrResponse,
  prepareVsrCommand,
  readRegisteredSession,
  VsrEvictionError,
  VsrSession,
} from '../wire/vsr/index.js';
import { normalizeClientConfig } from './client.config.js';

const VSR_RESPONSE_TIMEOUT_MS = 30_000;
const VSR_RETRY_INTERVAL_MS = 50;
const LEADERLESS_WAIT_BUDGET_MS = 5_000;
const LEADERLESS_POLL_INTERVAL_MS = 250;
const MAX_LEADER_REDIRECTS = 3;
const TRANSIENT_NOT_COMMITTED = 57;
const TRANSIENT_NOT_ACCEPTED = 58;
/**
 * How long a `TRANSIENT_NOT_ACCEPTED` request replays on the same connection
 * before the roster is re-read. A node that stopped being primary refuses
 * forever, so replaying alone never recovers. Matches the Rust SDK.
 */
const VSR_FAILOVER_CHECK_MS = 2_000;

/**
 * Whether a request's budget still holds enough for another attempt. One
 * exchange needs at least a replay interval to be worth starting; below that
 * the attempt can only end in a timeout, which would hide the refusal that
 * actually came back.
 */
const worthAnotherAttempt = (deadline: number): boolean =>
  deadline - Date.now() > VSR_RETRY_INTERVAL_MS;

/**
 * A request the current node keeps refusing as not-admitted. Carries the
 * refusal so the caller can surface it when the roster turns out to still name
 * this node as the leader. Never escapes `sendCommand`.
 */
class LeaderMovedError extends Error {
  constructor(readonly refusal: ResponseError) {
    super('the node refused the request as not-admitted; re-reading the roster');
  }
}

/**
 * How a leader move resolved: onto the metadata leader, onto the next roster
 * node (for a request the metadata leader itself keeps refusing), or not at
 * all.
 */
type RosterWalkVerdict = {
  endpoint: Endpoint,
  moved: boolean
};
type LeaderMoveVerdict = 'leader' | RosterWalkVerdict | false;

/**
 * Command codes that can be executed without authentication.
 */
const UNLOGGED_COMMAND_CODE = [
  PING.code,
  LOGIN.code,
  LOGIN_WITH_TOKEN.code
];

/**
 * Represents a queued command job waiting to be executed.
 */
type Job = {
  /** Command code */
  command: number,
  /** Command payload */
  payload: Buffer,
  /** Whether to parse the response */
  handleResponse: boolean,
  /** Whether the command is appended rather than prepended to the queue */
  last: boolean,
  /** Whether a not-admitted refusal re-checks the leader and re-issues */
  followsLeaderMoves: boolean,
  /** When the whole request gives up, however often it is re-issued */
  deadline: number,
  /** Promise resolve function */
  resolve: (v: CommandResponse | PromiseLike<CommandResponse>) => void,
  /** Promise reject function */
  reject: (e: unknown) => void
};

type ExchangeState = {
  written: boolean
};

export class VsrResponseTimeoutError extends Error {
  constructor(timeout: number) {
    super(`timed out after ${timeout} ms waiting for VSR response`);
    this.name = 'VsrResponseTimeoutError';
    Object.setPrototypeOf(this, VsrResponseTimeoutError.prototype);
  }
}

/**
 * Manages command execution and response handling for the Iggy server.
 * Implements command queuing, authentication, and heartbeat functionality.
 */
export class CommandResponseStream extends EventEmitter {
  /** Client configuration */
  private options: ClientConfig;
  /** Underlying connection to the server */
  private connection: IggyConnection;
  /** Queue of pending command jobs */
  private _execQueue: Job[];
  /** Consensus session used by VSR framing */
  private vsrSession: VsrSession;
  /** Shared authentication attempt for concurrent callers */
  private authenticationPromise?: Promise<boolean>;
  /** Whether a login is already being moved to the leader */
  private settlingLeader: boolean;
  /**
   * The leader re-check a refused request started, shared with every other
   * request refused by the same node so one demotion moves the client once.
   */
  private leaderMoveInFlight?: Promise<LeaderMoveVerdict>;
  /**
   * Set when a roster walk just redirected this client, so the login that
   * re-authenticates it stays on the dialed node instead of settling back on
   * the metadata leader whose partition replica refused the request.
   */
  private walkSettleSuppressed = false;
  /**
   * Refusals handed out to callers that have not decided what to do with them
   * yet. The queue holds while any are outstanding: the caller of a refused
   * command re-checks the leader, and a command written in the meantime goes
   * out on the socket that check is about to replace.
   */
  private leaderMovesUndecided: number;
  /** How long a leaderless roster is polled before settling in place */
  private leaderlessWaitBudget: number;
  /** Delay between roster reads while the cluster elects */
  private leaderlessPollInterval: number;
  /** Calls that have acquired this stream but have not fully settled */
  private pendingSubmissions: number;
  /** Whether the stream is currently processing a command */
  public busy: boolean;
  /** Whether the client has been authenticated */
  isAuthenticated: boolean;
  /** Authenticated user ID */
  userId?: number;
  /** Heartbeat interval timer handle */
  heartbeatIntervalHandler?: NodeJS.Timeout;
  /** Whether a heartbeat ping is still awaiting its response */
  private heartbeatInFlight: boolean;

  /**
   * Creates a new CommandResponseStream.
   *
   * @param options - Client configuration
   */
  constructor(options: ClientConfigOrString) {
    super();
    const normalizedConfig = normalizeClientConfig(options);
    this.options = normalizedConfig;
    this.connection = new IggyConnection(normalizedConfig);
    this.busy = false;
    this.isAuthenticated = false;
    this._execQueue = [];
    this.vsrSession = new VsrSession();
    this.authenticationPromise = undefined;
    this.settlingLeader = false;
    this.leaderMovesUndecided = 0;
    this.leaderlessWaitBudget = LEADERLESS_WAIT_BUDGET_MS;
    this.leaderlessPollInterval = LEADERLESS_POLL_INTERVAL_MS;
    this.pendingSubmissions = 0;
    this.heartbeatInFlight = false;
    this._init();
  };

  /**
   * Initializes the stream by setting up heartbeat and connection event handlers.
   */
  _init() {
    this.heartbeat(this.options.heartbeatInterval);
    this.connection.on('error', (error: Error) => {
      this._failQueue(error);
    });
    this.connection.on('eviction', (error: VsrEvictionError) => {
      this._resetSession();
      this.emit('eviction', error);
    });
    this.connection.on('disconnected', () => {
      this._resetSession();
      if (this.connection.redirecting) {
        // The client is moving to the leader, which is its own doing: a queued
        // command has not been written, so it belongs on the node being moved
        // to rather than in an error.
        this._reissueQueue();
        return;
      }
      this._failQueue(
        new Error('connection closed before queued commands were sent')
      );
    });
  }

  /**
   * Re-submits queued commands through the full send path, so each one
   * reconnects, re-authenticates and re-checks the leader as if it had just
   * been called.
   *
   * Only for a drop the client caused. Nothing here was written, so there is no
   * outcome in doubt: a command still in the queue when the socket is replaced
   * would otherwise fail with a lost-connection error the caller can do nothing
   * about.
   */
  private _reissueQueue(): void {
    const queued = this._execQueue;
    this._execQueue = [];
    for (const job of queued) {
      debug('re-issuing a queued command after a leader move', job.command);
      // The whole job, not just the payload: a fresh budget would let a command
      // caught in a move take twice the response timeout, and a roster read
      // re-issued as leader-following would answer a leader check with another
      // leader check.
      this.sendCommand(job.command, job.payload, {
        handleResponse: job.handleResponse,
        last: job.last,
        followsLeaderMoves: job.followsLeaderMoves,
        deadline: job.deadline
      }).then(job.resolve, job.reject);
    }
  }

  /**
   * Sends a command to the server.
   * Automatically handles connection, authentication and leader settlement.
   *
   * @param command - Command code to send
   * @param payload - Command payload buffer
   * @param options - Response and queue options
   * @returns Promise resolving to the command response
   */
  async sendCommand(
    command: number,
    payload: Buffer,
    options: SendCommandOptions = {}
  ): Promise<CommandResponse> {
    this.pendingSubmissions += 1;
    try {
      const {
        handleResponse = true,
        last = true,
        followsLeaderMoves = true
      } = options;

      if (!this.connection.connected)
        await this.connection.connect()

      if (!this.isAuthenticated && !this.isUnloggedCommand(command))
        await this.authenticate(this.options.credentials);

      // The roster read is itself a queued command and the queue is
      // single-flighted, so the leader re-check cannot happen inside
      // `_processVsr`. The refusal comes back out here instead, where the
      // queue is free, and the command is re-issued on the node that now
      // leads.
      //
      // A not-admitted refusal means the request was never applied, so it is
      // re-issued for the whole request budget rather than given up on after
      // one window: the roster can still name this node -- an election in
      // flight, a leader that has not moved yet -- and that is a wait, not a
      // verdict.
      //
      // One budget for the whole request: the transient replays on a
      // connection, the leader re-checks, and the re-issues after a move all
      // spend it, so a request cannot outlive it by moving. A command re-issued
      // after a move keeps the budget it was first submitted with, rather than
      // opening a second one.
      const deadline = options.deadline ?? Date.now() + VSR_RESPONSE_TIMEOUT_MS;
      let response: CommandResponse;
      let walkingRoster = false;
      const visitedRosterEndpoints = new Set<string>();
      for (;;) {
        try {
          response = await this._queueCommand(command, payload, handleResponse,
            last, followsLeaderMoves, deadline);
          break;
        } catch (error) {
          if (!(error instanceof LeaderMovedError))
            throw error;
          // The roster read that a re-check runs is itself a command that can
          // be refused this way, and answering a leader check with another
          // leader check would recurse. Its caller reads a failure as "stay
          // where you are".
          //
          // A budget too small to carry another attempt ends it here, with the
          // refusal the server actually gave: re-issued into what is left, the
          // request would time out instead and the caller would see a timeout
          // where the answer was "not admitted".
          let moved: LeaderMoveVerdict = false;
          try {
            if (!followsLeaderMoves || !worthAnotherAttempt(deadline))
              throw responseError(command, error.refusal.errorCode);
            // Once this request starts walking the roster it keeps walking: a
            // leader recheck between hops would put it straight back on the
            // metadata leader whose partition replica refused it, and the
            // walk would bounce between two nodes without reaching the rest.
            moved = await this._followLeaderMove(
              walkingRoster,
              visitedRosterEndpoints
            );
            if (typeof moved === 'object') {
              walkingRoster = true;
              visitedRosterEndpoints.add(endpointKey(moved.endpoint));
            }
          } finally {
            // Released as soon as the move is decided, before the pace below
            // and before any re-authentication: those go through the queue
            // themselves, and a queue still held for this refusal would never
            // reach them.
            if (followsLeaderMoves)
              this._releaseUndecidedMove();
          }
          const connectionMoved = moved === 'leader' ||
            (typeof moved === 'object' && moved.moved);
          if (!connectionMoved) {
            // Nowhere else to go yet: the roster still names this node, or it
            // could not be read. Paced, because the in-connection replay
            // window belongs to the request's budget and has already been
            // spent -- re-issuing straight away would spin.
            await delay(Math.min(
              VSR_FAILOVER_CHECK_MS,
              Math.max(0, deadline - Date.now())
            ));
          }
          if (!worthAnotherAttempt(deadline))
            throw responseError(command, error.refusal.errorCode);
          // A move drops the session with the socket it was bound to, so the
          // re-issue would otherwise go out under no session: a replicated
          // command fails client-side, a non-replicated one goes out with
          // session 0.
          if (!this.isAuthenticated && !this.isUnloggedCommand(command))
            await this.authenticate(this.options.credentials);
        }
      }
      if (!isLoginCommand(command) || this.settlingLeader)
        return response;
      // A login that re-authenticates a roster walk stays on the dialed node:
      // settling would put the client back on the metadata leader whose
      // partition replica refused the walked request. One login only.
      if (this.walkSettleSuppressed) {
        this.walkSettleSuppressed = false;
        return response;
      }
      this.settlingLeader = true;
      try {
        const settled = await this._settleOnLeader(command, payload);
        return settled ?? response;
      } finally {
        this.settlingLeader = false;
      }
    } finally {
      this.pendingSubmissions -= 1;
      this._emitFinishQueue();
    }
  }

  private _queueCommand(
    command: number,
    payload: Buffer,
    handleResponse: boolean,
    last: boolean,
    followsLeaderMoves: boolean,
    deadline: number
  ): Promise<CommandResponse> {
    return new Promise<CommandResponse>((resolve, reject) => {
      const job: Job = {
        command,
        payload,
        handleResponse,
        last,
        followsLeaderMoves,
        deadline,
        resolve,
        reject
      };
      if (last)
        this._execQueue.push(job);
      else
        this._execQueue.unshift(job);
      this._processQueue();
    });
  }

  /**
   * Re-reads the roster and moves to the leader it names.
   *
   * Best effort: an unreadable roster, or one that still names this node,
   * leaves the client where it is and the refused request is re-issued anyway.
   *
   * Single-flighted, and concurrent callers share the outcome instead of
   * failing: several commands are refused by the same demoted node, and each
   * starting its own redirect would move the client once per command. The
   * first redirect's `'disconnected'` also fails the others' roster reads, so
   * a caller that raced one would report a refusal it never had to.
   *
   * @returns Whether the client moved
   */
  private _followLeaderMove(
    walkPastLeader = false,
    visitedRosterEndpoints = new Set<string>()
  ): Promise<LeaderMoveVerdict> {
    const inFlight = this.leaderMoveInFlight;
    if (inFlight)
      return inFlight;

    const move = (async (): Promise<LeaderMoveVerdict> => {
      try {
        if (!walkPastLeader) {
          const leader = await this._readLeaderEndpoint();
          if (leader && !this.connection.isConnectedTo(leader.host, leader.port)) {
            debug(`the leader moved to ${leader.host}:${leader.port}, following it`);
            await this.connection.redirect(leader.host, leader.port);
            return 'leader';
          }
        }
        // The roster names this node as the metadata leader (or said nothing
        // usable), yet it keeps refusing to admit the request: its replica of
        // the target partition group is not that group's primary, because
        // metadata and partition consensus groups elect independently. Walk
        // the roster instead of re-issuing into the same refusal.
        const next = this.connection.nextRosterEndpoint(visitedRosterEndpoints);
        if (!next)
          return false;
        debug(
          'the request keeps being refused here, walking the roster to ' +
          `${next.host}:${next.port}`
        );
        // The re-authentication after this redirect runs a login, and a login
        // normally settles on the metadata leader, which would put the walk
        // right back on the node that refused. One login only.
        this.walkSettleSuppressed = true;
        try {
          await this.connection.redirect(next.host, next.port);
        } catch (error) {
          // The suppression belongs to the redirect above. If that redirect
          // never lands, a later unrelated login must settle normally.
          this.walkSettleSuppressed = false;
          debug('the roster endpoint could not be reached', error);
          return { endpoint: next, moved: false };
        }
        return { endpoint: next, moved: true };
      } catch (error) {
        debug('the leader could not be re-checked, staying on this node', error);
        return false;
      }
    })();
    this.leaderMoveInFlight = move;
    void move.finally(() => {
      if (this.leaderMoveInFlight !== move)
        return;
      this.leaderMoveInFlight = undefined;
      // The drain stopped while the move was being decided. A move that
      // happened re-issues what was held back on the new socket; one that did
      // not leaves it here, with nothing else due to pick it up.
      if (!this.connection.redirecting)
        void this._processQueue();
    });
    return move;
  }

  /** Whether a leader move is being decided or carried out. */
  private _movePending(): boolean {
    return this.leaderMovesUndecided > 0 || this.leaderMoveInFlight !== undefined;
  }

  /**
   * Releases the queue hold one refusal took, and drains what was held back
   * once the last of them is decided.
   */
  private _releaseUndecidedMove(): void {
    if (this.leaderMovesUndecided > 0)
      this.leaderMovesUndecided -= 1;
    if (this._movePending() || this.connection.redirecting)
      return;
    void this._processQueue();
  }

  private _rememberRoster(response: CommandResponse): void {
    try {
      const metadata = GET_CLUSTER_METADATA.deserialize(response);
      this.connection.rememberRoster(
        metadata.nodes
          .filter((node) => node.endpoints.tcp !== 0)
          .map((node) => ({ host: node.ip, port: node.endpoints.tcp }))
      );
    } catch (error) {
      debug('an unreadable roster leaves the redial candidates as they are',
        error);
    }
  }

  /**
   * Processes queued commands sequentially.
   * Emits 'finishQueue' when all commands are processed.
   *
   */
  async _processQueue(): Promise<void> {
    if (this.busy)
      return;
    this.busy = true;
    while (this._execQueue.length > 0 && this.connection.socket.writable) {
      // While a leader move is being decided, only the roster read the move
      // itself runs goes out -- it is what decides where the client lands, and
      // it is the one command that does not follow moves. Draining the rest
      // would write them to the socket `redirect()` is about to replace, and a
      // command in flight when that happens dies with a lost-connection error
      // instead of being re-issued on the node the move lands on.
      const index = this._movePending()
        ? this._execQueue.findIndex((job) => !job.followsLeaderMoves)
        : 0;
      if (index < 0) break;
      const [next] = this._execQueue.splice(index, 1);
      if (!next) break;
      const { command, payload, handleResponse, deadline, resolve, reject } = next;
      try {
        resolve(await this._processNext(command, payload, handleResponse, deadline));
      } catch (err) {
        if (err instanceof LeaderMovedError && next.followsLeaderMoves)
          // Counted before the rejection is handed out, not after: the caller
          // resumes as a microtask, so this loop would otherwise write the next
          // command before the re-check it is about to start has begun.
          this.leaderMovesUndecided += 1;
        reject(err);
      }
    }
    if (this._execQueue.length > 0) {
      // The same distinction as on 'disconnected': the socket a leader move
      // replaced stops being writable, and what is still queued belongs on the
      // node being moved to.
      if (this.connection.redirecting)
        this._reissueQueue();
      else if (!this._movePending())
        this._failQueue(new Error('connection is not writable'));
      // Otherwise the move is still being decided: these commands were never
      // written, and they are drained again once it settles -- here if the
      // client stays, on the new socket if it moves.
    }
    this.busy = false;
    this._emitFinishQueue();
  }

  private _emitFinishQueue(): void {
    if (this.pendingSubmissions === 0 &&
        !this.busy &&
        this._execQueue.length === 0)
      this.emit('finishQueue');
  }

  /**
   * Processes a single command by writing it to the connection and waiting for response.
   *
   * @param command - Command code
   * @param payload - Command payload
   * @param handleResp - Whether to parse the response
   * @param deadline - When the whole request gives up, shared with the leader
   * re-checks and the re-issues after a move
   * @returns Promise resolving to the command response
   */
  _processNext(
    command: number,
    payload: Buffer,
    handleResp = true,
    deadline = Date.now() + VSR_RESPONSE_TIMEOUT_MS
  ): Promise<CommandResponse> {
    if (isLoginCommand(command) && this.isAuthenticated)
      return this._processVsrLogin(command, payload, handleResp, deadline);
    return this._processVsr(command, payload, handleResp, deadline);
  }

  private async _processVsrLogin(
    command: number,
    payload: Buffer,
    handleResp: boolean,
    deadline: number
  ): Promise<CommandResponse> {
    await this._processVsr(LOGOUT.code, LOGOUT.serialize(), true, deadline);
    return this._processVsr(command, payload, handleResp, deadline);
  }

  private async _processVsr(
    command: number,
    payload: Buffer,
    handleResp: boolean,
    deadline: number
  ): Promise<CommandResponse> {
    let requestWritten = false;
    try {
      const prepared = prepareVsrCommand(command, payload);
      // A transient retry must preserve all request identity fields.
      const frame = this.vsrSession.encode(prepared.command, prepared.payload);
      // Derived from the request's own budget rather than read off the clock,
      // so one request spends one budget however many times it is re-issued.
      const notAcceptedDeadline =
        deadline - VSR_RESPONSE_TIMEOUT_MS + VSR_FAILOVER_CHECK_MS;
      let lastTransientError: ResponseError | undefined;
      let parsed: CommandResponse;
      while (true) {
        const remaining = deadline - Date.now();
        if (remaining <= 0) {
          if (lastTransientError)
            throw lastTransientError;
          throw new VsrResponseTimeoutError(VSR_RESPONSE_TIMEOUT_MS);
        }
        const exchangeState = { written: false };
        let response: Buffer;
        try {
          response = await this._exchange(
            () => this.connection.writeFrame(frame),
            remaining,
            exchangeState
          );
        } finally {
          requestWritten ||= exchangeState.written;
        }
        if (!handleResp)
          return response as unknown as CommandResponse;
        try {
          parsed = decodeVsrResponse(response, command);
          break;
        } catch (error) {
          if (!(error instanceof ResponseError) ||
              !isTransientVsrError(error.errorCode))
            throw error;
          lastTransientError = error;
          // A not-admitted refusal is a statement about who leads, not about
          // load: a node that stopped being primary refuses forever, so
          // replaying on this connection never recovers. Hand it back for a
          // roster re-read once the window is spent. Not-committed (57) stays
          // here: the request is in flight on this very node, and its outcome
          // is unknown anywhere else.
          if (error.errorCode === TRANSIENT_NOT_ACCEPTED &&
              !isLoginCommand(command) &&
              Date.now() >= notAcceptedDeadline)
            throw new LeaderMovedError(error);
          const retryDelay = Math.min(
            VSR_RETRY_INTERVAL_MS,
            Math.max(0, deadline - Date.now())
          );
          if (retryDelay === 0)
            throw error;
          await delay(retryDelay);
        }
      }

      if (prepared.command === COMMAND_CODE.LoginRegister ||
          prepared.command === COMMAND_CODE.LoginRegisterWithAccessToken) {
        this.vsrSession.bind(readRegisteredSession(parsed));
        this.isAuthenticated = true;
        this.userId = parsed.data.readUInt32LE(0);
      }
      if (prepared.command === COMMAND_CODE.LogoutUser) {
        this._resetSession();
      }
      // Every roster read feeds the redial candidates, whoever asked for it
      // and whatever it says: a node dies together with its address, the
      // roster is unreachable exactly when it is needed, and reading it only
      // during a login would leave the candidates stale between logins.
      if (handleResp && command === GET_CLUSTER_METADATA.code)
        this._rememberRoster(parsed);
      return parsed;
    } catch (error) {
      // A not-admitted refusal is an answer, so the session is not in doubt
      // and the request was never applied.
      if (error instanceof LeaderMovedError)
        throw error;
      // Once bytes were handed to the socket, a local transport or decode
      // failure leaves the request outcome ambiguous. Register a fresh session
      // rather than replaying that request under a different client identity.
      if (!(error instanceof ResponseError) && requestWritten)
        this._resetSession();
      if (error instanceof VsrEvictionError)
        throw error;
      if (error instanceof ResponseError)
        throw responseError(command, error.errorCode);
      throw error;
    }
  }

  private _exchange(
    write: () => void,
    timeout?: number,
    state?: ExchangeState
  ): Promise<Buffer> {
    return new Promise((resolve, reject) => {
      let timeoutHandler: NodeJS.Timeout | undefined;
      const cleanup = () => {
        if (timeoutHandler)
          clearTimeout(timeoutHandler);
        this.connection.removeListener('error', errorCallback);
        this.connection.removeListener('disconnected', disconnectedCallback);
        this.connection.removeListener('eviction', evictionCallback);
        this.connection.removeListener('response', responseCallback);
      };
      const errorCallback = (error: unknown) => {
        cleanup();
        reject(error);
      };
      const disconnectedCallback = () => {
        cleanup();
        reject(new Error('connection closed while waiting for response'));
      };
      const evictionCallback = (error: VsrEvictionError) => {
        cleanup();
        reject(error);
      };
      const responseCallback = (response: Buffer) => {
        cleanup();
        resolve(response);
      };
      if (timeout !== undefined) {
        timeoutHandler = setTimeout(() => {
          cleanup();
          this.connection.abort();
          reject(new VsrResponseTimeoutError(timeout));
        }, timeout);
      }
      this.connection.once('error', errorCallback);
      this.connection.once('disconnected', disconnectedCallback);
      this.connection.once('eviction', evictionCallback);
      this.connection.once('response', responseCallback);
      try {
        write();
        if (state)
          state.written = true;
      } catch (error) {
        cleanup();
        reject(error);
      }
    });
  }

  // `GetClusterMetadata` is deliberately absent: the server auth-gates it,
  // so the client authenticates before reading the topology. A login dialed
  // at a backup still succeeds because the server forwards the register to
  // the primary.
  private isUnloggedCommand(command: number): boolean {
    return UNLOGGED_COMMAND_CODE.includes(command);
  }

  /**
   * Moves a freshly authenticated session to the cluster leader.
   *
   * Only the leader accepts replicated commands, and the roster read is
   * auth-gated, so the topology cannot be inspected before a login binds a
   * session. The redirect drops that session along with the socket, so the
   * login is replayed on the leader and its answer supersedes the one from the
   * node the client dialed. Leadership can move between the roster read and
   * the replay, so each freshly bound hop rechecks the roster under a bounded
   * redirect budget.
   *
   * @returns The leader's login response, or undefined when the client stays
   */
  private async _settleOnLeader(
    loginCommand: number,
    loginPayload: Buffer
  ): Promise<CommandResponse | undefined> {
    let settledResponse: CommandResponse | undefined;
    for (let redirects = 0; redirects < MAX_LEADER_REDIRECTS; redirects += 1) {
      const leader = await this._readLeaderEndpoint();
      if (!leader || this.connection.isConnectedTo(leader.host, leader.port))
        return settledResponse;
      await this.connection.redirect(leader.host, leader.port);
      settledResponse = await this.sendCommand(
        loginCommand,
        loginPayload,
        { last: false }
      );
    }
    debug(
      `leader settlement reached its ${MAX_LEADER_REDIRECTS}-hop budget, ` +
      'staying on the current node'
    );
    return settledResponse;
  }

  /**
   * Reads the cluster roster and picks the endpoint to settle on.
   *
   * Best effort: an unreadable roster, `Unauthenticated` included (the session
   * died between the login and this read), keeps the client on its current
   * node instead of failing a login that already succeeded.
   */
  private async _readLeaderEndpoint(): Promise<Endpoint | undefined> {
    // A cluster can be transiently leaderless: a restarted node cedes the
    // primaryship its stale view assigns it, and the roster reports no leader
    // until the peers' election completes. That window is roughly one heartbeat
    // timeout, so poll through it rather than settling on a replica that denies
    // every replicated command for its whole retry budget.
    const deadline = Date.now() + this.leaderlessWaitBudget;
    while (true) {
      // Reading without a session would re-enter authentication, which awaits
      // the very login this settlement runs inside of. The session can also die
      // between polls, so this holds for every pass, not just the first.
      if (!this.isAuthenticated)
        return undefined;
      try {
        // Queue the metadata fetch instead of writing directly: a bare write
        // would race an in-flight exchange and both would wake on the same
        // response event.
        const response = await this.sendCommand(
          GET_CLUSTER_METADATA.code,
          GET_CLUSTER_METADATA.serialize(),
          { last: false, followsLeaderMoves: false }
        );
        // The redial candidates are fed by `_processVsr` for every roster
        // read, leaderless ones included: a roster with no leader still names
        // where the nodes are.
        const metadata = GET_CLUSTER_METADATA.deserialize(response);
        if (metadata.nodes.length <= 1)
          return undefined;
        const leader = metadata.nodes.find(
          (node) => node.role === 'Leader' && node.status === 'Healthy'
        );
        if (leader)
          return { host: leader.ip, port: leader.endpoints.tcp };
      } catch (error) {
        debug('cluster metadata is unreadable, staying on this node', error);
        return undefined;
      }
      if (Date.now() >= deadline) {
        debug(
          'cluster metadata named no healthy leader within ' +
          `${this.leaderlessWaitBudget} ms, staying on this node`
        );
        return undefined;
      }
      await delay(this.leaderlessPollInterval);
    }
  }

  /**
   * Fails all queued commands with the given error.
   *
   * @param err - Error to reject all queued commands with
   */
  _failQueue(err: Error) {
    this._execQueue.forEach(({ reject }) => reject(err));
    this._execQueue = [];
  }

  private _resetSession(): void {
    if (!this.isAuthenticated &&
        this.userId === undefined &&
        !this.vsrSession.hasActivity)
      return;
    this.isAuthenticated = false;
    this.userId = undefined;
    this.vsrSession.reset();
    this.emit('sessionReset');
  }

  hold(): () => void {
    this.pendingSubmissions += 1;
    let released = false;
    return () => {
      if (released)
        return;
      released = true;
      this.pendingSubmissions -= 1;
      this._emitFinishQueue();
    };
  }

  /**
   * Authenticates the client with the server.
   *
   * @param creds - Authentication credentials (token or password)
   * @returns True if authentication succeeded
   */
  async authenticate(creds: ClientCredentials): Promise<boolean> {
    if (this.isAuthenticated)
      return true;
    if (this.authenticationPromise)
      return this.authenticationPromise;

    this.authenticationPromise = this._authenticate(creds);
    try {
      return await this.authenticationPromise;
    } finally {
      this.authenticationPromise = undefined;
    }
  }

  private async _authenticate(creds: ClientCredentials): Promise<boolean> {
    const r = ('token' in creds) ?
      await this._authWithToken(creds) :
      await this._authWithPassword(creds);
    this.isAuthenticated = true;
    this.userId = r.userId;
    return this.isAuthenticated;
  }

  /**
   * Authenticates using username and password.
   *
   * @param creds - Password credentials
   * @returns Login response with user ID
   */
  async _authWithPassword(creds: PasswordCredentials) {
    const pl = LOGIN.serialize(creds);
    const logr = await this.sendCommand(LOGIN.code, pl, { last: false });
    return LOGIN.deserialize(logr);
  }

  /**
   * Authenticates using a token.
   *
   * @param creds - Token credentials
   * @returns Login response with user ID
   */
  async _authWithToken(creds: TokenCredentials) {
    const pl = LOGIN_WITH_TOKEN.serialize(creds);
    const logr = await this.sendCommand(
      LOGIN_WITH_TOKEN.code,
      pl,
      { last: false }
    );
    return LOGIN_WITH_TOKEN.deserialize(logr);
  }

  /**
   * Sends a ping command to the server.
   *
   * @returns Ping response
   */
  async ping() {
    const pl = PING.serialize();
    const pingR = await this.sendCommand(PING.code, pl);
    return PING.deserialize(pingR);
  }

  /**
   * Starts sending periodic heartbeat pings to keep the connection alive.
   *
   * @param interval - Heartbeat interval in milliseconds
   */
  heartbeat(interval?: number) {
    if (!interval)
      return

    this.heartbeatIntervalHandler = setInterval(async () => {
      if (this.connection.connected && !this.heartbeatInFlight) {
        this.heartbeatInFlight = true;
        debug(`sending heartbeat ping (interval: ${interval} ms)`);
        try {
          await this.ping()
          this.emit('heartbeat');
        } catch (error) {
          debug('heartbeat ping failed', error);
        } finally {
          this.heartbeatInFlight = false;
        }
      }
    }, interval);
    // A pending heartbeat must not be the reason the process stays up: a script
    // that never calls destroy() would otherwise hang on exit.
    this.heartbeatIntervalHandler.unref();
  }

  /**
   * Returns the underlying socket as a readable stream.
   *
   * @returns The connection socket
   */
  getReadStream() {
    return this.connection.socket;
  }

  /**
   * Destroys the stream and cleans up resources.
   * Stops heartbeat and destroys the connection.
   */
  destroy() {
    if (this.heartbeatIntervalHandler)
      clearInterval(this.heartbeatIntervalHandler);
    return this.connection._destroy();
  }
};


/**
 * Creates a new RawClient instance.
 *
 * @param options - Client configuration
 * @returns RawClient instance
 */
export function getRawClient(options: ClientConfigOrString): RawClient {
  return new CommandResponseStream(options);
}

const isLoginCommand = (command: number): boolean =>
  command === COMMAND_CODE.LoginUser ||
  command === COMMAND_CODE.LoginWithAccessToken;

const delay = (milliseconds: number): Promise<void> =>
  new Promise((resolve) => setTimeout(resolve, milliseconds));

const isTransientVsrError = (errorCode: number): boolean =>
  errorCode === TRANSIENT_NOT_COMMITTED ||
  errorCode === TRANSIENT_NOT_ACCEPTED;
