/**
 * The daemon endpoint delegate requests dial, and how each one authenticates.
 *
 * Split from `delegate-runtime.ts` because credential resolution is a policy
 * of its own: WHICH source outranks which, and which of them must be re-read
 * per request rather than frozen at detection time.
 */

import {
  loadDaemonAuth,
  readDaemonConfigAuthToken,
  readUnitAuthToken,
  type BridgeConfig,
  type DaemonAuthToken,
  type DelegateDaemonTarget,
} from "./bridge.js";

/**
 * Bind a resolved bridge to its endpoint and credential.
 *
 * The credential is bound to the config or unit the resolved endpoint came
 * from, so a deployment with two daemons sends each its OWN token instead of
 * whichever one discovery happened to read first — and every source is
 * re-read per request, because a token rotated behind a daemon restart must
 * not 401 every delegated route until the gateway restarts too.
 */
export function daemonTargetFor(bridge: BridgeConfig): DelegateDaemonTarget {
  const invalidatedCredentials = new Set<string>();
  const invalidated = (token: string): boolean =>
    invalidatedCredentials.has(`daemon configuration\0${token}`);
  return {
    host: bridge.daemonHost,
    port: bridge.daemonPort,
    invalidateAuthToken: (auth: DaemonAuthToken) => {
      invalidatedCredentials.add(`${auth.source}\0${auth.token}`);
    },
    resolveAuthToken: () => {
      if (
        bridge.daemonAuthTokenOverride !== undefined &&
        !invalidated(bridge.daemonAuthTokenOverride)
      ) {
        // A unit-supplied credential is re-read from its unit — including its
        // drop-ins and `EnvironmentFile=`.
        const unit =
          bridge.daemonAuthUnit === undefined ? undefined : readUnitAuthToken(bridge.daemonAuthUnit);
        if (unit?.readable === true && unit.token !== undefined && !invalidated(unit.token)) {
          return { token: unit.token, source: "daemon configuration" };
        }
        // A unit that is no longer READABLE proves nothing, so the value the
        if (
          (unit === undefined || unit.readable === false) &&
          !invalidated(bridge.daemonAuthTokenOverride)
        ) {
          return { token: bridge.daemonAuthTokenOverride, source: "daemon configuration" };
        }
        // Readable and deliberately carrying no token: the daemon has fallen
        // back to its config or token store, so fall through to the same
        // resolution rather than replaying a credential nobody serves. The
        // BOUND config is tried first — `loadDaemonAuth` puts the gateway's
        // own token store ahead of it, which is wrong for a daemon running
        // under another account and would keep 401ing after the restart.
        if (bridge.daemonConfigPath !== undefined) {
          const configToken = readDaemonConfigAuthToken(bridge.daemonConfigPath);
          if (configToken !== undefined && !invalidated(configToken)) {
            return { token: configToken, source: "daemon configuration" };
          }
        }
      }
      if (
        bridge.daemonAuthPrefersConfig &&
        bridge.daemonConfigPath !== undefined
      ) {
        const configToken = readDaemonConfigAuthToken(bridge.daemonConfigPath);
        if (configToken !== undefined && !invalidated(configToken)) {
          return { token: configToken, source: "daemon configuration" };
        }
      }
      return loadDaemonAuth(bridge.daemonConfigPath, invalidatedCredentials);
    },
  };
}
