/**
 * Decides which username to use when a host is backed by a saved credential.
 *
 * An explicitly-set host username always wins - if the user typed a username on
 * the host it should be honoured even when a credential is attached. The
 * credential's username is only used as a fallback when the host has none. The
 * `overrideCredentialUsername` flag forces the host username regardless.
 */
export function pickResolvedUsername(
  hostUsername: unknown,
  credentialUsername: unknown,
  overrideCredentialUsername?: unknown,
): string | undefined {
  const host = isNonEmptyString(hostUsername) ? hostUsername : undefined;
  const cred = isNonEmptyString(credentialUsername)
    ? credentialUsername
    : undefined;

  if (overrideCredentialUsername) return host;
  if (host) return host;
  return cred;
}

/**
 * A host can keep a per-host password while using a shared key credential.
 * Prefer that host-specific value and fall back to the credential password.
 */
export function pickResolvedPassword(
  hostPassword: unknown,
  credentialPassword: unknown,
): string | undefined {
  if (isNonEmptyString(hostPassword)) return hostPassword;
  if (isNonEmptyString(credentialPassword)) return credentialPassword;
  return undefined;
}

/**
 * Expands the `$oidc.preferred_username` placeholder in an SSH username to the
 * connecting user's OIDC identifier. Returns the username unchanged if it does
 * not contain the placeholder or the user has no OIDC identifier.
 */
export async function expandOidcUsername(
  username: string | undefined,
  userId: string,
): Promise<string | undefined> {
  if (!username || !username.includes("$oidc.preferred_username")) {
    return username;
  }

  try {
    const { createCurrentUserRepository } =
      await import("../database/repositories/factory.js");
    const user = await createCurrentUserRepository().findById(userId);
    let oidcIdentifier = user?.oidcIdentifier;
    if (!oidcIdentifier) return username;

    const match = /^ldap:(\d+):(.+)$/.exec(oidcIdentifier);
    if (match) {
      // Make sure the SSO provider is actually LDAP, to prevent spoofing.
      const { createCurrentSsoProviderRepository } =
        await import("../database/repositories/factory.js");
      const claimedProviderId = Number(match[1]);
      const provider =
        user?.ssoProviderId != null
          ? await createCurrentSsoProviderRepository().findById(
              user.ssoProviderId,
            )
          : null;

      if (
        provider?.type === "ldap" &&
        user?.ssoProviderId === claimedProviderId
      ) {
        oidcIdentifier = match[2];
      }
    }

    return username.replace(/\$oidc\.preferred_username/g, oidcIdentifier);
  } catch {
    return username;
  }
}

function isNonEmptyString(value: unknown): value is string {
  return typeof value === "string" && value.trim() !== "";
}
